Files
tabungin/OTP_FIXES.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

4.1 KiB

OTP Login Issues - FIXED

🐛 Issues Identified:

Issue 1: TOTP Verification Failing (401 Unauthorized)

Problem: /api/auth/verify-otp returning 401 when verifying TOTP codes Root Cause:

  • Temp token check was wrong: payload.type !== 'temp' but we set temp: true
  • Using payload.sub but temp token has userId
  • Not actually verifying the TOTP code!

Issue 2: Google OAuth + Email OTP Redirecting to Login

Problem: After Google login with Email OTP enabled, redirects to login page instead of OTP page Root Cause:

  • Google callback passes params as URL query (?token=...&methods=...)
  • OTP page only checked location.state
  • Didn't parse URL parameters

Fixes Applied:

1. Fixed verifyOtpAndLogin in AuthService

Changes:

// OLD - Wrong check
if (payload.type !== 'temp') {
  throw new UnauthorizedException('Invalid token type');
}

// NEW - Correct check
if (!payload.temp) {
  throw new UnauthorizedException('Invalid token type');
}

// OLD - Wrong userId extraction
const token = this.generateToken(payload.sub, payload.email);

// NEW - Correct userId extraction
const userId = payload.userId || payload.sub;
const email = payload.email;

Added TOTP Verification:

if (method === 'totp') {
  if (!user.otpTotpSecret) {
    throw new UnauthorizedException('TOTP not set up');
  }
  
  const { authenticator } = await import('otplib');
  const isValid = authenticator.verify({
    token: otpCode,
    secret: user.otpTotpSecret,
  });

  if (!isValid) {
    throw new UnauthorizedException('Invalid TOTP code');
  }
}

Added Email OTP Format Check:

if (method === 'email') {
  if (!/^\d{6}$/.test(otpCode)) {
    throw new UnauthorizedException('Invalid OTP code format');
  }
}

2. Fixed OTP Verification Page

Changes:

// OLD - Only checked location.state
const { tempToken, availableMethods } = location.state || {}

// NEW - Check both location.state AND URL params
const searchParams = new URLSearchParams(location.search)
const urlToken = searchParams.get('token')
const urlMethods = searchParams.get('methods')

const tempToken = location.state?.tempToken || urlToken
const availableMethods = location.state?.availableMethods || 
  (urlMethods ? JSON.parse(decodeURIComponent(urlMethods)) : null)

Now handles:

  • Login flow: navigate('/auth/otp', { state: { tempToken, availableMethods } })
  • Google OAuth: ?token=xxx&methods={"email":true,"totp":false}

🧪 Testing:

Account 1: Email/Password + TOTP

  1. Register with email/password
  2. Setup TOTP in profile
  3. Logout
  4. Login with email/password
  5. Redirected to OTP page
  6. Enter TOTP code from authenticator app
  7. Should now verify successfully!

Account 2: Google OAuth + Email OTP

  1. Login with Google
  2. Setup Email OTP in profile
  3. Logout
  4. Click "Continue with Google"
  5. Should now redirect to OTP page (not login)
  6. Enter email OTP code
  7. Should verify successfully!

📝 Files Modified:

  1. apps/api/src/auth/auth.service.ts

    • Fixed temp token validation
    • Added actual TOTP verification using otplib
    • Added email OTP format validation
    • Fixed userId extraction from token
  2. apps/web/src/components/pages/OtpVerification.tsx

    • Added URL query parameter parsing
    • Handles both location.state and URL params
    • Decodes JSON methods from URL

What Now Works:

TOTP Login: Authenticator app codes are properly verified
Email OTP Login: Format is validated (6 digits)
Google OAuth + OTP: Redirects to OTP page correctly
Regular Login + OTP: Works as before
Token Validation: Properly checks temp tokens


🎯 Next Steps:

  1. Test both accounts - Should now login successfully
  2. Email OTP Integration - Currently only validates format, needs actual OTP verification
  3. Implement change password - Backend endpoint needed

Both login issues should now be resolved! Try logging in again. 🚀