- 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>
115 lines
3.9 KiB
Markdown
115 lines
3.9 KiB
Markdown
# Research: Google OAuth Authentication
|
|
|
|
**Feature**: 001-google-oauth-auth
|
|
**Date**: 2026-01-29
|
|
|
|
## 1. NestJS Passport Google OAuth Setup
|
|
|
|
**Decision**: Use `@nestjs/passport` with `passport-google-oauth20` strategy
|
|
|
|
**Rationale**:
|
|
- Official NestJS integration provides decorator-based guards and strategies
|
|
- `passport-google-oauth20` is the actively maintained Google OAuth package
|
|
- Seamless integration with NestJS dependency injection and module system
|
|
- Built-in validate method simplifies user profile handling
|
|
|
|
**Alternatives Considered**:
|
|
- `passport-google-oauth2`: Older package, less TypeScript support
|
|
- Custom OAuth implementation: Too much boilerplate, harder to maintain
|
|
|
|
## 2. Authentication Strategy for SPAs
|
|
|
|
**Decision**: Hybrid approach - JWT access tokens (short-lived, in-memory) + HttpOnly cookie refresh tokens (7-day)
|
|
|
|
**Rationale**:
|
|
- Access tokens in memory provide stateless, scalable API authentication
|
|
- HttpOnly refresh tokens prevent XSS attacks while enabling token rotation
|
|
- Best balance between security, UX, and distributed system requirements
|
|
- Industry standard for modern SPAs
|
|
|
|
**Alternatives Considered**:
|
|
- Pure JWT (stateless): Can't invalidate tokens on logout/compromise
|
|
- Pure sessions: Doesn't scale well, requires sticky sessions
|
|
- localStorage for tokens: Vulnerable to XSS attacks
|
|
|
|
## 3. Token Storage in React
|
|
|
|
**Decision**: Access tokens in Zustand store (memory), refresh tokens in HttpOnly cookies
|
|
|
|
**Rationale**:
|
|
- HttpOnly cookies are inaccessible to JavaScript, preventing XSS token theft
|
|
- In-memory storage for short-lived access tokens (15-30 min)
|
|
- CSRF protection via `sameSite: 'strict'` and CORS configuration
|
|
- Silent refresh mechanism restores access token on page reload
|
|
|
|
**Alternatives Considered**:
|
|
- localStorage: Vulnerable to XSS attacks
|
|
- sessionStorage: Data lost on tab close, still XSS vulnerable
|
|
|
|
## 4. React Router Protected Routes
|
|
|
|
**Decision**: Layout-based protection using AuthGuard wrapper component with Navigate
|
|
|
|
**Rationale**:
|
|
- React Router v7 provides clean, declarative route protection
|
|
- Easy to preserve intended destination via `location.state.from`
|
|
- Simple loading state handling during auth check
|
|
|
|
**Alternatives Considered**:
|
|
- Higher-Order Component (HOC): More verbose in modern React
|
|
- Route-level guards: Duplicates auth logic across routes
|
|
|
|
## 5. OAuth Redirect Flow Implementation
|
|
|
|
**Decision**: Backend-initiated flow with frontend callback handler
|
|
|
|
**Flow**:
|
|
1. Frontend links to `/api/auth/google` (backend initiates OAuth)
|
|
2. NestJS redirects to Google consent screen
|
|
3. Google redirects to `/api/auth/google/callback`
|
|
4. Backend validates tokens, creates/updates user, issues JWT
|
|
5. Backend redirects to frontend `/auth/callback?token=...`
|
|
6. Frontend stores token, clears URL, redirects to intended destination
|
|
|
|
**Rationale**:
|
|
- NestJS handles OAuth state management and token exchange securely
|
|
- Supports TypeORM user creation/lookup with transaction safety
|
|
- Token cleared from URL immediately for security
|
|
|
|
**Alternatives Considered**:
|
|
- Frontend-initiated PKCE flow: More complex state management
|
|
- Popup-based flow: Poor UX on mobile, blocked by some browsers
|
|
|
|
## 6. Session Validity & Token Expiration
|
|
|
|
**Decision**:
|
|
- Access tokens: 15 minutes (short-lived for security)
|
|
- Refresh tokens: 7 days (per spec assumptions)
|
|
- Automatic token refresh via 401 interceptor in Axios
|
|
|
|
**Rationale**:
|
|
- Short access tokens limit exposure window if compromised
|
|
- 7-day refresh aligns with spec requirements
|
|
- Auto-refresh provides seamless UX
|
|
|
|
## Implementation Notes
|
|
|
|
**CORS Configuration Required**:
|
|
```
|
|
origin: FRONTEND_URL
|
|
credentials: true (allow cookies)
|
|
```
|
|
|
|
**Environment Variables Needed**:
|
|
- GOOGLE_CLIENT_ID
|
|
- GOOGLE_CLIENT_SECRET
|
|
- GOOGLE_CALLBACK_URL
|
|
- JWT_SECRET
|
|
- JWT_ACCESS_EXPIRATION (15m)
|
|
- JWT_REFRESH_EXPIRATION (7d)
|
|
- FRONTEND_URL
|
|
|
|
**TypeORM Indexes**:
|
|
- Index `googleId` for OAuth lookups
|
|
- Index `email` for user queries
|