# 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 ` 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