- 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
246 lines
6.1 KiB
Markdown
246 lines
6.1 KiB
Markdown
# 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
|