Files
frontend/backend/src/modules/auth/google.strategy.ts
Andre 130f35c4f8 feat: implement Google OAuth authentication
- 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>
2026-01-29 13:05:18 -03:00

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);
}
}
}