Files
tabungin/AUTH_SETUP.md
dwindown 249f3a9d7d 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
2025-10-11 14:00:11 +07:00

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

  1. Go to Google Cloud Console
  2. Create a new project or select existing one
  3. Enable Google+ API
  4. Go to CredentialsCreate CredentialsOAuth 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

{
  "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/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