- 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>
128 lines
3.4 KiB
Markdown
128 lines
3.4 KiB
Markdown
# 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
|