passport-google-oidc-token
Version:
Google ID token authentication strategy for Passport.
159 lines (133 loc) • 3.97 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _googleAuthLibrary = require("google-auth-library");
/**
* `GoogleOIDCTokenStrategy` constructor.
*
* The Google OIDC token strategy authenticates using the Google Auth Library
*
* Applications must supply a `verify` callback which accepts an `accessToken`,
* `refreshToken` and service-specific `profile`, and then calls the `cb`
* callback supplying a `user`, which should be set to `false` if the
* credentials are not valid. If an exception occurred, `err` should be set.
*
* @param {Object} options
* @param {Function} verify
* @example
* passport.use(new GoogleOIDCTokenStrategy(
* {
* clientID: '123456789',
* },
* (accessToken, refreshToken, profile, cb) => {
* User.findOrCreate({ googleId: profile.id }, cb);
* }
* );
*/
class GoogleOIDCTokenStrategy {
error = () => {};
fail = () => {};
success = () => {};
constructor(options, verify) {
this.client = new _googleAuthLibrary.OAuth2Client(options.clientID);
this.clientId = options.clientID;
this.name = 'google-oidc-token';
this._verify = verify;
if ('passReqToCallback' in options) {}
this._passReqToCallback = 'passReqToCallback' in options ? options.passReqToCallback : false;
}
/**
* Authenticate request using Google Auth Library
* @param {Object} req
*/
async authenticate(req) {
const idToken = this.lookup(req, 'id_token');
try {
const ticket = await this.client.verifyIdToken({
idToken,
audience: this.clientId // Specify the CLIENT_ID of the app that accesses the backend
});
const payload = ticket.getPayload();
if (!payload) {
throw new Error('No payload returned');
}
const verifiedFunction = (error, user, info) => {
if (error) {
return this.error(error);
}
if (!user) {
return this.fail(info);
}
return this.success(user, info);
};
const profile = GoogleOIDCTokenStrategy.parseProfile(payload);
if (this._passReqToCallback) {
this._verify(req, idToken, profile, verifiedFunction);
} else {
this._verify(idToken, profile, verifiedFunction);
}
} catch (err) {
this.error(err);
}
}
/**
* This method handles searhing the value of provided field in body, query, and header.
*
* @param {Object} req http request object
* @param {String} field
* @returns {String} field's value in body, query, or headers
*/
lookup(req, field) {
return req.body && req.body[field] || req.query && req.query[field] || req.headers && req.headers[field];
}
/**
* Parse profile.
*
* Parses user profiles as fetched from Google's OpenID Connect-compatible user
* info endpoint.
*
* The amount of detail in the profile varies based on the scopes granted by the
* user. The following scope values add additional data:
*
* `profile` - basic profile information
* `email` - email address
*
* References:
* - https://developers.google.com/identity/protocols/OpenIDConnect
*
* @param {object} payload
* @return {object}
*/
static parseProfile(payload) {
const profile = {
provider: 'google',
id: payload.sub,
displayName: payload.name || '',
name: undefined,
photos: [],
emails: [],
_json: payload
};
if (payload.family_name || payload.given_name) {
profile.name = {
familyName: payload.family_name,
givenName: payload.given_name
};
}
if (payload.email) {
profile.emails = [{
value: payload.email,
verified: payload.email_verified
}];
}
if (payload.picture) {
profile.photos = [{
value: payload.picture
}];
}
return profile;
}
}
exports.default = GoogleOIDCTokenStrategy;