- 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
6.1 KiB
6.1 KiB
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:
# 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:
# 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
- Go to Google Cloud Console
- Create a new project or select existing one
- Enable Google+ API
- Go to Credentials → Create Credentials → OAuth 2.0 Client ID
- Configure OAuth consent screen
- Add authorized redirect URIs:
http://localhost:3001/api/auth/google/callback(development)https://your-domain.com/api/auth/google/callback(production)
- Copy Client ID and Client Secret to your
.envfiles
Email Webhook Setup (n8n)
n8n Workflow for Sending OTP Emails
- Create a new workflow in n8n
- Add a Webhook node:
- Method: POST
- Path:
/send-otp
- Add an Email node (or your preferred email service):
- To:
{{ $json.to }} - Subject:
{{ $json.subject }} - Body:
{{ $json.message }}
- To:
- Activate the workflow
- Copy the webhook URL to
EMAIL_WEBHOOK_URLin your.env
Expected Webhook Payload
{
"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:
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/passwordPOST /api/auth/login- Login with email/passwordGET /api/auth/google- Initiate Google OAuthGET /api/auth/google/callback- Google OAuth callbackPOST /api/auth/verify-otp- Verify OTP for MFAGET /api/auth/me- Get current user (requires JWT)
OTP/MFA Management
GET /api/otp/status- Get OTP statusPOST /api/otp/email/send- Send email OTPPOST /api/otp/email/verify- Verify and enable email OTPPOST /api/otp/email/disable- Disable email OTPPOST /api/otp/totp/setup- Setup TOTPPOST /api/otp/totp/verify- Verify and enable TOTPPOST /api/otp/totp/disable- Disable TOTP
Security Notes
- JWT_SECRET: Use a strong, random secret (at least 32 characters)
- HTTPS: Always use HTTPS in production
- Password: Passwords are hashed with bcrypt (10 rounds)
- Token Expiry: JWT tokens expire in 7 days
- Temp Tokens: OTP temp tokens expire in 5 minutes
- Email OTP: Codes expire in 10 minutes
Development vs Production
Development
- Use
http://localhost:3001for API - Use
http://localhost:5174for frontend - Email OTP codes are logged to console if webhook fails
Production
- Update all URLs to your production domain
- Use environment-specific
.envfiles - 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