UNPKG

passport-appleid

Version:

Apple authentication strategy for Passport.

119 lines (105 loc) 4 kB
/** * Module dependencies. */ const util = require('util'); const OAuth2Strategy = require('passport-oauth2'); const appleSignin = require("apple-signin"); const Profile = require('./profile'); const InternalOAuthError = OAuth2Strategy.InternalOAuthError; const AuthorizationError = OAuth2Strategy.AuthorizationError; /** * `Strategy` constructor. * * The Apple authentication strategy authenticates requests by delegating to * Apple using the OAuth 2.0 protocol. * * Applications must supply a `verify` callback which accepts an `accessToken`, * `refreshToken` and service-specific `profile`, and then calls the `done` * callback supplying a `user`, which should be set to `false` if the * credentials are not valid. If an exception occured, `err` should be set. * * Options: * - `clientID` identifier of Apple Service ID * - `callbackURL` URL to which Apple will redirect the user after granting authorization * - `teamId` apple Developer Team ID. * - `keyIdentifier` identifier of private Apple key associated with clientID * - `privateKeyPath` path to private Apple key associated with clientID * - `scope` (optional) array of permission scopes to request. valid scopes include: * * Examples: * * passport.use(new AppleStrategy({ * clientID: '123-456-789', * callbackURL: 'https://www.example.net/auth/apple/callback', * teamId: "123456AB", * keyIdentifier: 'RB1233456', * privateKeyPath: path.join(__dirname, "./AuthKey_RB1233456.p8") * }, * function(accessToken, refreshToken, profile, done) { * User.findOrCreate(..., function (err, user) { * done(err, user); * }); * } * )); * * @param {Object} options * @param {Function} verify * @api public */ function Strategy(options, verify) { this._options = options || {}; this._verify = verify; this.name = 'apple'; } /** * Inherit from `OAuth2Strategy`. */ util.inherits(Strategy, OAuth2Strategy); /** * Authenticate request by delegating to a service provider using OAuth 2.0. * * @param {Object} req * @api protected */ OAuth2Strategy.prototype.authenticate = function(req, options) { var self = this; if (req.query && req.query.error) { if (req.query.error == 'access_denied') return this.fail({ message: req.query.error_description }); return this.error(new AuthorizationError(req.query.error_description, req.query.error, req.query.error_uri)); } const redirectUri = options.callbackURL || self._options.callbackURL; if (req.query && req.query.code){ const state = req.query.state; function verified(error, user, info) { if (error) return self.error(error); if (!user) return self.fail(info); info = info || {}; if (state) { info.state = state; } self.success(user, info); } const params = {clientID: self._options.clientID, redirectUri: redirectUri, clientSecret: appleSignin.getClientSecret(self._options)}; appleSignin.getAuthorizationToken(req.query.code, params).then(token => { var idToken = token['id_token']; if (!idToken) { return self.error(new Error('ID Token not present in token response')); } appleSignin.verifyIdToken(idToken, self._options.clientID).then(jwtClaims => { const profile = {}; profile.id = jwtClaims.sub; self._verify(token.access_token, token.refresh_token, profile, verified); }).catch(error => { return self.error(new InternalOAuthError('token is not verified', error)); }); }).catch(error => { return self.error(new InternalOAuthError('failed to obtain access token', error)); }); } else { let params = self._options; params.redirectUri = redirectUri; params.scope = options.scope || params.scope; params.state = options.state; self.redirect(appleSignin.getAuthorizationUrl(self._options)); } }; /** * Expose `Strategy`. */ module.exports = Strategy;