feat: remove OTP gate from transactions, fix categories auth, add implementation plan
- Remove OtpGateGuard from transactions controller (OTP verified at login) - Fix categories controller to use authenticated user instead of TEMP_USER_ID - Add comprehensive implementation plan document - Update .env.example with WEB_APP_URL - Prepare for admin dashboard development
This commit is contained in:
245
AUTH_SETUP.md
Normal file
245
AUTH_SETUP.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# Custom Authentication Setup Guide
|
||||
|
||||
## Overview
|
||||
|
||||
Tabungin now uses a custom authentication system with:
|
||||
- **Primary Methods**: Email/Password + Google OAuth
|
||||
- **Multi-Factor Authentication (MFA)**: Google Authenticator (TOTP) + Email OTP
|
||||
|
||||
## Environment Variables Setup
|
||||
|
||||
### Backend (`/apps/api/.env`)
|
||||
|
||||
Create `/apps/api/.env` file with the following variables:
|
||||
|
||||
```env
|
||||
# Database Configuration (use your existing PostgreSQL database)
|
||||
DATABASE_URL="postgresql://user:password@host:port/tabungin?schema=public"
|
||||
SHADOW_DATABASE_URL="postgresql://user:password@host:port/tabungin_shadow?schema=public"
|
||||
|
||||
# JWT Authentication
|
||||
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
|
||||
|
||||
# Google OAuth (for "Continue with Google")
|
||||
GOOGLE_CLIENT_ID=your-google-client-id-from-google-cloud-console
|
||||
GOOGLE_CLIENT_SECRET=your-google-client-secret-from-google-cloud-console
|
||||
GOOGLE_CALLBACK_URL=http://localhost:3001/api/auth/google/callback
|
||||
|
||||
# Email Webhook for OTP (n8n webhook URL)
|
||||
EMAIL_WEBHOOK_URL=https://your-n8n-instance.com/webhook/send-otp
|
||||
|
||||
# App Configuration
|
||||
PORT=3001
|
||||
WEB_APP_URL=http://localhost:5174
|
||||
```
|
||||
|
||||
### Frontend (`/apps/web/.env.local`)
|
||||
|
||||
Create `/apps/web/.env.local` file:
|
||||
|
||||
```env
|
||||
# API Base URL
|
||||
VITE_API_URL=http://localhost:3001
|
||||
|
||||
# Google OAuth Client ID (same as backend)
|
||||
VITE_GOOGLE_CLIENT_ID=your-google-client-id-from-google-cloud-console
|
||||
```
|
||||
|
||||
## Google OAuth Setup
|
||||
|
||||
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Create a new project or select existing one
|
||||
3. Enable **Google+ API**
|
||||
4. Go to **Credentials** → **Create Credentials** → **OAuth 2.0 Client ID**
|
||||
5. Configure OAuth consent screen
|
||||
6. Add authorized redirect URIs:
|
||||
- `http://localhost:3001/api/auth/google/callback` (development)
|
||||
- `https://your-domain.com/api/auth/google/callback` (production)
|
||||
7. Copy **Client ID** and **Client Secret** to your `.env` files
|
||||
|
||||
## Email Webhook Setup (n8n)
|
||||
|
||||
### n8n Workflow for Sending OTP Emails
|
||||
|
||||
1. Create a new workflow in n8n
|
||||
2. Add a **Webhook** node:
|
||||
- Method: POST
|
||||
- Path: `/send-otp`
|
||||
3. Add an **Email** node (or your preferred email service):
|
||||
- To: `{{ $json.to }}`
|
||||
- Subject: `{{ $json.subject }}`
|
||||
- Body: `{{ $json.message }}`
|
||||
4. Activate the workflow
|
||||
5. Copy the webhook URL to `EMAIL_WEBHOOK_URL` in your `.env`
|
||||
|
||||
### Expected Webhook Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"to": "user@example.com",
|
||||
"subject": "Tabungin - Your OTP Code",
|
||||
"message": "Your OTP code is: 123456. This code will expire in 10 minutes.",
|
||||
"code": "123456"
|
||||
}
|
||||
```
|
||||
|
||||
## Database Migration
|
||||
|
||||
Run the Prisma migration to add auth fields:
|
||||
|
||||
```bash
|
||||
cd apps/api
|
||||
npx prisma migrate deploy
|
||||
npx prisma generate
|
||||
```
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
### 1. Email/Password Registration
|
||||
|
||||
```
|
||||
POST /api/auth/register
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "securepassword",
|
||||
"name": "John Doe" (optional)
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"user": { "id", "email", "name", "avatarUrl", "emailVerified" },
|
||||
"token": "jwt-token"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Email/Password Login
|
||||
|
||||
```
|
||||
POST /api/auth/login
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "securepassword"
|
||||
}
|
||||
|
||||
Response (no MFA):
|
||||
{
|
||||
"user": { ... },
|
||||
"token": "jwt-token"
|
||||
}
|
||||
|
||||
Response (MFA enabled):
|
||||
{
|
||||
"requiresOtp": true,
|
||||
"availableMethods": { "email": true, "totp": false },
|
||||
"tempToken": "temporary-token-for-otp-verification"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Google OAuth Login
|
||||
|
||||
```
|
||||
Frontend redirects to: GET /api/auth/google
|
||||
Google redirects back to: GET /api/auth/google/callback
|
||||
Backend redirects to frontend with token
|
||||
```
|
||||
|
||||
### 4. OTP Verification (if MFA enabled)
|
||||
|
||||
```
|
||||
POST /api/auth/verify-otp
|
||||
{
|
||||
"tempToken": "temp-token-from-login",
|
||||
"otpCode": "123456",
|
||||
"method": "email" or "totp"
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"user": { ... },
|
||||
"token": "full-jwt-token"
|
||||
}
|
||||
```
|
||||
|
||||
## MFA Setup
|
||||
|
||||
### Enable Email OTP
|
||||
|
||||
```
|
||||
1. POST /api/otp/email/send (sends OTP to user's email)
|
||||
2. POST /api/otp/email/verify { "code": "123456" }
|
||||
```
|
||||
|
||||
### Enable TOTP (Google Authenticator)
|
||||
|
||||
```
|
||||
1. POST /api/otp/totp/setup
|
||||
Response: { "secret": "...", "qrCode": "otpauth://..." }
|
||||
2. Scan QR code with Google Authenticator app
|
||||
3. POST /api/otp/totp/verify { "code": "123456" }
|
||||
```
|
||||
|
||||
### Disable MFA
|
||||
|
||||
```
|
||||
POST /api/otp/email/disable
|
||||
POST /api/otp/totp/disable
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Authentication
|
||||
- `POST /api/auth/register` - Register with email/password
|
||||
- `POST /api/auth/login` - Login with email/password
|
||||
- `GET /api/auth/google` - Initiate Google OAuth
|
||||
- `GET /api/auth/google/callback` - Google OAuth callback
|
||||
- `POST /api/auth/verify-otp` - Verify OTP for MFA
|
||||
- `GET /api/auth/me` - Get current user (requires JWT)
|
||||
|
||||
### OTP/MFA Management
|
||||
- `GET /api/otp/status` - Get OTP status
|
||||
- `POST /api/otp/email/send` - Send email OTP
|
||||
- `POST /api/otp/email/verify` - Verify and enable email OTP
|
||||
- `POST /api/otp/email/disable` - Disable email OTP
|
||||
- `POST /api/otp/totp/setup` - Setup TOTP
|
||||
- `POST /api/otp/totp/verify` - Verify and enable TOTP
|
||||
- `POST /api/otp/totp/disable` - Disable TOTP
|
||||
|
||||
## Security Notes
|
||||
|
||||
1. **JWT_SECRET**: Use a strong, random secret (at least 32 characters)
|
||||
2. **HTTPS**: Always use HTTPS in production
|
||||
3. **Password**: Passwords are hashed with bcrypt (10 rounds)
|
||||
4. **Token Expiry**: JWT tokens expire in 7 days
|
||||
5. **Temp Tokens**: OTP temp tokens expire in 5 minutes
|
||||
6. **Email OTP**: Codes expire in 10 minutes
|
||||
|
||||
## Development vs Production
|
||||
|
||||
### Development
|
||||
- Use `http://localhost:3001` for API
|
||||
- Use `http://localhost:5174` for frontend
|
||||
- Email OTP codes are logged to console if webhook fails
|
||||
|
||||
### Production
|
||||
- Update all URLs to your production domain
|
||||
- Use environment-specific `.env` files
|
||||
- Set up proper email service (not just n8n webhook)
|
||||
- Use HTTPS everywhere
|
||||
- Rotate JWT_SECRET regularly
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "No token provided" error
|
||||
- Make sure you're sending the JWT token in the `Authorization: Bearer <token>` header
|
||||
|
||||
### Google OAuth not working
|
||||
- Check that redirect URIs match exactly in Google Cloud Console
|
||||
- Verify GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET are correct
|
||||
|
||||
### Email OTP not received
|
||||
- Check n8n webhook URL is correct and workflow is active
|
||||
- Check backend console logs for OTP code (development mode)
|
||||
|
||||
### TOTP not working
|
||||
- Make sure time is synced on both server and client
|
||||
- Verify the secret was saved correctly in database
|
||||
Reference in New Issue
Block a user