- Add Google OAuth 2.0 login flow with passport-google-oauth20 - Create User and RefreshToken entities for session management - Implement JWT access tokens (15min) + HttpOnly refresh cookies (7 days) - Add auth endpoints: /google, /google/callback, /refresh, /me, /logout - Create LoginPage with Google sign-in button (shadcn/ui) - Add AuthGuard for protected routes with redirect preservation - Implement silent token refresh on app mount - Add UserMenu component with avatar and sign-out Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
41 lines
1.3 KiB
TypeScript
41 lines
1.3 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { PassportStrategy } from '@nestjs/passport';
|
|
import { Strategy, VerifyCallback, Profile, StrategyOptions } from 'passport-google-oauth20';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { AuthService } from './auth.service';
|
|
|
|
@Injectable()
|
|
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
|
|
constructor(
|
|
private readonly configService: ConfigService,
|
|
private readonly authService: AuthService,
|
|
) {
|
|
const options: StrategyOptions = {
|
|
clientID: configService.get<string>('GOOGLE_CLIENT_ID') || '',
|
|
clientSecret: configService.get<string>('GOOGLE_CLIENT_SECRET') || '',
|
|
callbackURL: configService.get<string>('GOOGLE_CALLBACK_URL') || '',
|
|
scope: ['email', 'profile'],
|
|
};
|
|
super(options);
|
|
}
|
|
|
|
async validate(
|
|
_accessToken: string,
|
|
_refreshToken: string,
|
|
profile: Profile,
|
|
done: VerifyCallback,
|
|
): Promise<void> {
|
|
try {
|
|
const user = await this.authService.validateOAuthUser({
|
|
id: profile.id,
|
|
emails: profile.emails as Array<{ value: string; verified: boolean }>,
|
|
displayName: profile.displayName,
|
|
photos: profile.photos as Array<{ value: string }>,
|
|
});
|
|
done(null, user);
|
|
} catch (error) {
|
|
done(error as Error, undefined);
|
|
}
|
|
}
|
|
}
|