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:
127
specs/001-google-oauth-auth/quickstart.md
Normal file
127
specs/001-google-oauth-auth/quickstart.md
Normal 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
|
||||
Reference in New Issue
Block a user