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>
This commit is contained in:
2026-01-29 13:05:18 -03:00
parent fe2c861007
commit 130f35c4f8
32 changed files with 2477 additions and 98 deletions

View File

@@ -0,0 +1,127 @@
# Quickstart: Google OAuth Authentication
**Feature**: 001-google-oauth-auth
**Date**: 2026-01-29
## Prerequisites
1. **Google Cloud Console Setup**
- Create a project at https://console.cloud.google.com
- Enable "Google+ API" or "Google Identity" API
- Configure OAuth consent screen (External, if not Google Workspace)
- Create OAuth 2.0 credentials (Web application type)
- Add authorized redirect URI: `http://localhost:3000/api/auth/google/callback`
2. **Environment Variables**
Add to `backend/.env`:
```env
# Google OAuth
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-client-secret
GOOGLE_CALLBACK_URL=http://localhost:3000/api/auth/google/callback
# JWT Configuration
JWT_SECRET=your-secure-random-secret-min-32-chars
JWT_ACCESS_EXPIRATION=15m
JWT_REFRESH_EXPIRATION=7d
# Frontend URL (for redirects)
FRONTEND_URL=http://localhost:5173
```
## Installation
### Backend Dependencies
```bash
cd backend
npm install @nestjs/passport @nestjs/jwt passport passport-google-oauth20 bcrypt
npm install -D @types/passport-google-oauth20 @types/bcrypt
```
### Frontend Dependencies
No additional dependencies required. Uses existing:
- react-router-dom (routing)
- zustand (auth state)
- axios (API calls)
- shadcn/ui (UI components)
## Database Migration
Create and run migration for new tables:
```bash
cd backend
npm run typeorm:generate -- -n CreateAuthTables
npm run typeorm:run
```
Tables created:
- `users` (id, googleId, email, displayName, avatarUrl, createdAt, lastLoginAt)
- `refresh_tokens` (id, userId, token, expiresAt, createdAt, revokedAt)
## Quick Test Flow
1. **Start the backend**:
```bash
cd backend && npm run start:dev
```
2. **Start the frontend**:
```bash
cd frontend && npm run dev
```
3. **Test OAuth flow**:
- Navigate to `http://localhost:5173/tool`
- Should redirect to login page
- Click "Sign in with Google"
- Complete Google consent
- Should redirect back to `/tool` with active session
4. **Verify session persistence**:
- Refresh the page
- Should remain on `/tool` without re-authenticating
5. **Test sign out**:
- Click user menu → Sign out
- Should redirect to login page
- Navigating to `/tool` should redirect to login
## API Endpoints
| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/auth/google` | Initiate OAuth (browser redirect) |
| GET | `/api/auth/google/callback` | OAuth callback handler |
| POST | `/api/auth/refresh` | Refresh access token |
| GET | `/api/auth/me` | Get current user (requires auth) |
| POST | `/api/auth/logout` | Sign out (requires auth) |
## Frontend Routes
| Path | Component | Protected |
|------|-----------|-----------|
| `/` | LandingPage | No |
| `/login` | LoginPage | No |
| `/auth/callback` | AuthCallbackPage | No |
| `/tool` | ToolPage | Yes |
## Troubleshooting
**"redirect_uri_mismatch" error**:
- Ensure callback URL in Google Console matches `GOOGLE_CALLBACK_URL` exactly
- Include protocol (http/https) and port
**"Invalid token" after refresh**:
- Check `JWT_SECRET` is set and consistent
- Verify refresh token cookie is being sent (check browser DevTools)
**CORS errors**:
- Ensure `FRONTEND_URL` matches exactly (including port)
- Check `credentials: true` in CORS config
**Session not persisting**:
- Verify `httpOnly` cookie is set (check Application → Cookies in DevTools)
- Check `sameSite` and `secure` settings match environment