import { FastifyInstance , RouteOptions } from 'fastify' ; import { AnyStrategy } from 'fastify-passport/dist/strategies' ; import { BaseProvider } from './base' ; import type { EzBackendInstance } from '@ezbackend/common' ; import { EzError } from '@ezbackend/utils' ; import { Strategy as GoogleStrategy } from 'passport-google-oauth20' ; import { ProviderOptions } from '.' ; import fastifyPassport from 'fastify-passport' ; interface GoogleProviderOptions extends ProviderOptions { googleClientId ? : string ; googleClientSecret ? : string ; scope : Array < string > ; } declare module '../auth' { interface EzBackendAuthOpts { google ? : GoogleProviderOptions ; } } export class GoogleProvider extends BaseProvider { constructor ( modelName ) { super ( 'google' , modelName ) ; } addStrategy ( instance , server , opts ) { const that = this ; if ( opts . googleClientId === undefined || opts . googleClientSecret === undefined ) { throw new EzError ( 'Google Client ID and Client Secret not found' , 'The Google Client ID and Client Secret are used to authenticate EzBackend to provide the google login' , 'Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in your .env file in the root (Same folder as package.json), or specify the option in app.start({...})' , 'https://www.ezbackend.io/docs/auth/user-auth#creating-the-user' ) ; } const googleStrategy = new GoogleStrategy ( { clientID : opts . googleClientId , clientSecret : opts . googleClientSecret , callbackURL : this . getCallbackURL ( server ) , } , function ( accessToken , refreshToken , profile , cb ) { that . defaultCallbackHandler ( instance , profile . id , profile , cb ) ; } ) ; return [ this . providerName , googleStrategy ] ; } getLoginRoute ( server , opts ) { return { method : 'GET' , url : `/${ this . getRoutePrefixNoPrePostSlash ( server ) }/login` , handler : fastifyPassport . authenticate ( 'google' , { scope : opts . scope } ) , schema : { tags : [ 'Google Auth' ] , summary : `Login for model '${ this . modelName }' with provider ${ this . providerName }` , description : `# 🔑 [CLICK HERE](/${ this . getFullRoutePrefixNoPrePostSlash ( server ) }/login) or visit the URL with this extension to login
                1. Creates/Updates '${ this . modelName }' on login
                2. Provider ${ this . providerName }
                3. Scopes: ${ opts . scope . toString ( ) }` , } , } ; } getLogoutRoute ( server , opts ) { return { method : 'GET' , url : `/${ this . getRoutePrefixNoPrePostSlash ( server ) }/logout` , handler : ( req , res ) => this . defaultLogoutHandler ( req , res , opts ) , schema : { tags : [ 'Google Auth' ] , summary : `Logout for model '${ this . modelName }' with provider ${ this . providerName }` , description : `# 🔑 [CLICK HERE](/${ this . getFullRoutePrefixNoPrePostSlash ( server ) }/logout) or visit the URL with this extension to logout` , } , } ; } getCallbackRoute ( server , opts ) { const callbackRoute = `/${ this . getRoutePrefixNoPrePostSlash ( server ) }/callback` ; return { method : 'GET' , url : callbackRoute , preValidation : fastifyPassport . authenticate ( 'google' , { scope : opts . scope , successRedirect : opts . successRedirectURL , failureRedirect : opts . failureRedirectURL , } ) , handler : function ( req , res ) { res . redirect ( opts . successRedirectURL ) ; } , schema : { tags : [ 'Google Auth' ] , summary : `Callback Route for model '${ this . modelName }' with provider ${ this . providerName }` , description : `Google redirects to this URL with the user's details. This route must be specified in the google callback URLs` , } , } ; } }