import { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy, VerifyCallback } from 'passport-google-oauth20'; import { ConfigService } from '@nestjs/config'; @Injectable() export class GoogleStrategy extends PassportStrategy(Strategy, 'google') { constructor(private configService: ConfigService) { super({ clientID: configService.get('CLIENT_ID')!, clientSecret: configService.get('CLIENT_SECRET')!, callbackURL: configService.get('CALLBACK_URL')!, scope: [ 'openid', 'email', 'profile', ], accessType: 'offline', // good: gets refresh_token on first consent includeGrantedScopes: true, // optional, keeps prior grants // ⛔️ don't rely on 'prompt' here; add via authorizationParams() }); } // ✅ Guarantees account chooser every time authorizationParams(): Record { return { prompt: 'select_account', // or 'consent select_account' if you want re-consent too // login_hint: 'user@domain.com', // optional // hd: 'your-domain.com', // optional: restrict to a Google Workspace domain }; } async validate( accessToken: string, refreshToken: string, profile: any, done: VerifyCallback, ) { const email = profile.emails?.[0]?.value ?? null; const name = { givenName: profile.name?.givenName ?? '', familyName: profile.name?.familyName ?? '', displayName: profile.displayName ?? '', }; return done(null, { email, name, accessToken, refreshToken, provider: 'google', }); } }