From 6f8c485980eaa478e5e768011f225102f6cbac53 Mon Sep 17 00:00:00 2001 From: Andrea Vos Date: Sat, 29 Apr 2023 09:42:11 +0000 Subject: [PATCH] [auth] login with apple --- nuxt.config.js | 3 +++ package.json | 2 +- server/routes/user.js | 4 +++- server/social.js | 40 ++++++++++++++++++++++++++++++++++++++++ src/socialProviders.js | 5 +++++ yarn.lock | 8 ++++---- 6 files changed, 56 insertions(+), 6 deletions(-) diff --git a/nuxt.config.js b/nuxt.config.js index 9268c40e9..2ee9dad59 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -25,6 +25,9 @@ if (process.env.ENV) { process.env.NODE_ENV = process.env.ENV; } +const applePrivateKeyFile = `${__dirname}/keys/AuthKey_${process.env.APLLE_KEY_ID}.p8`; +process.env.APPLE_PRIVATE_KEY = fs.existsSync(applePrivateKeyFile) ? fs.readFileSync(applePrivateKeyFile).toString('utf-8') : null; + const allVersionsUrls = buildList(function*() { if (process.env.NODE_ENV === 'development') { yield 'http://pronouns.test:3000'; diff --git a/package.json b/package.json index 56f7d8416..a02670b92 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "express": "^4.17.1", "express-session": "^1.17.1", "generic-diff": "^1.0.1", - "grant": "^5.4.20", + "grant": "^5.4.21", "he-date": "^1.2.2", "html-loader": "^1.3.2", "html2canvas": "^1.4.1", diff --git a/server/routes/user.js b/server/routes/user.js index 22e6b8fe6..a40a87835 100644 --- a/server/routes/user.js +++ b/server/routes/user.js @@ -537,7 +537,9 @@ router.get('/user/social-redirect/:provider/:locale', handleErrorAsync(async (re // happens on home router.get('/user/social/:provider', handleErrorAsync(async (req, res) => { - if (!req.session.grant || !req.session.grant.response || !req.session.grant.response.access_token || !socialLoginHandlers[req.params.provider]) { + if (!req.session.grant || !req.session.grant.response + || (!req.session.grant.response.access_token && !req.session.grant.response.jwt) + || !socialLoginHandlers[req.params.provider]) { console.error('Social login failed, session incomplete.', req.params.provider, req.session, req.session.grant.response); return res.status(400).json({error: 'Something went wrong… Please try again.'}) } diff --git a/server/social.js b/server/social.js index 5c12e9187..797dacea8 100644 --- a/server/social.js +++ b/server/social.js @@ -1,3 +1,22 @@ +const jwt = require('jsonwebtoken'); + +const getAppleClientSecret = () => { + const headers = { + kid: process.env.APPLE_KEY_ID, + typ: undefined + } + const claims = { + 'iss': process.env.APPLE_TEAM_ID, + 'aud': 'https://appleid.apple.com', + 'sub': process.env.APPLE_CLIENT_ID, + } + return jwt.sign(claims, process.env.APPLE_PRIVATE_KEY, { + algorithm: 'ES256', + header: headers, + expiresIn: '180d' + }); +} + module.exports.config = { defaults: { origin: process.env.BASE_URL, @@ -30,6 +49,19 @@ module.exports.config = { callback: '/api/user/social/discord', scope: ['identify', 'email'], }, + apple: { + key: process.env.APPLE_CLIENT_ID, + secret: getAppleClientSecret(), + + callback: '/api/user/social/apple', + scope: ['openid', 'name', 'email'], + response: ['raw', 'jwt'], + nonce: true, + custom_params: { + response_type: 'code id_token', + response_mode: 'form_post', + }, + }, // non-grant, but things break if it's not there mastodon: {}, indieauth: {}, @@ -97,4 +129,12 @@ module.exports.handlers = { instance: r.instance, } }, + apple(r) { + const payload = r.jwt.id_token.payload + return { + id: payload.email, + email: payload.email_verified ? payload.email : null, + name: payload.email, + }; + } }; diff --git a/src/socialProviders.js b/src/socialProviders.js index 27efc4c89..68e917f6b 100644 --- a/src/socialProviders.js +++ b/src/socialProviders.js @@ -19,6 +19,11 @@ export const socialProviders = { redirectViaHome: true, avatars: true, }, + apple: { + name: 'Apple', + redirectViaHome: true, + avatars: true, + }, google: { name: 'Google', redirectViaHome: true, diff --git a/yarn.lock b/yarn.lock index fa2d52592..65f450be8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5522,10 +5522,10 @@ graceful-fs@^4.2.6: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -grant@^5.4.20: - version "5.4.20" - resolved "https://registry.yarnpkg.com/grant/-/grant-5.4.20.tgz#01ad40559057920e2297aa1d74043edee1056548" - integrity sha512-VwoKfA8IgMIbFDBVybb6iTqkSEyy+uZYeXRnaF6L/Dc9X2eq73ciEXQ71atCoVDy6yOD2YGszs+cGAACNK6NqQ== +grant@^5.4.21: + version "5.4.21" + resolved "https://registry.yarnpkg.com/grant/-/grant-5.4.21.tgz#3306942f4a19e40d008e247d071104b19173c0c6" + integrity sha512-QaoZudI9Gmh2W415gd71Iul6gpVH9sG1SkjfnGHtqYZopQDQ5PUVxRol5zFCrwGi9S0EbExbelHlZScgdChg2w== dependencies: qs "^6.10.2" request-compose "^2.1.4"