Root now contains only essential files: README.md, CLAUDE.md, CHANGELOG.md, CONTRIBUTING.md Reorganized into: docs/audits/ — all audit reports & checklists (71 files) docs/architecture/ — codebase overview, implementation plan docs/guides/ — auth guide, implementation checklist docs/load-testing/ — k6 load test guides & endpoints docs/security/ — payment & security reviews Also removed 5 untracked debug/investigation files and cleaned up playwright-report/ & test-results/ artifacts. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
4.2 KiB
4.2 KiB
GoodGo Platform - Authentication Quick Reference
🔑 Key Points at a Glance
Password Hashing
Algorithm: bcrypt
Salt Rounds: 12 (env: BCRYPT_ROUNDS)
Min Length: 8 characters
Example: bcrypt.hash('password', 12)
Phone Numbers (Vietnamese)
Valid Formats: 0900000001, 84900000001, +84900000001
Normalized: +84900000001
Regex: /^(?:\+84|84|0)(3[2-9]|5[2689]|7[06-9]|8[1-9]|9[0-9])\d{7}$/
File: apps/api/src/modules/shared/utils/vietnam-phone.validator.ts
Regex: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
Normalization: lowercase + trim
Storage: admin@goodgo.vn
PII Encryption
Algorithm: AES-256-GCM
Key: 32 bytes (64 hex chars)
Encrypted: email, phone, kycData
Searchable: email → emailHash (HMAC-SHA256)
phone → phoneHash (HMAC-SHA256)
Env Var: FIELD_ENCRYPTION_KEY
User Login
Username: phone (normalized)
Password: plain text
Lookup: by phoneHash (unique index)
Required: isActive = true, passwordHash ≠ null
Response: tokens (or MFA challenge)
User Roles
BUYER - Search, inquire, offer (default)
SELLER - Create listings
AGENT - Professional agent
ADMIN - Full access
MFA
TOTP: otplib (RFC 6238)
Period: 30 seconds
Digits: 6
Backup Codes: 10 × 8 chars (A-Z no OI, 2-9 no 01)
Hashing: HMAC-SHA256 (not bcrypt)
📋 Creating a Login-Capable Admin User
5-Step Process
1. Normalize phone
phone = '0900000001' → '+84900000001'
2. Derive HMAC key
hmacKey = crypto.hkdfSync('sha256', Buffer.from(encryptionKey, 'hex'),
Buffer.alloc(0), Buffer.from('goodgo-field-hash', 'utf8'), 32)
3. Compute hashes
phoneHash = crypto.createHmac('sha256', hmacKey).update('+84900000001').digest('hex')
emailHash = crypto.createHmac('sha256', hmacKey).update('admin@goodgo.vn').digest('hex')
4. Hash password
passwordHash = await bcrypt.hash('AdminPassword123', 12)
5. Create user
await prisma.user.create({
data: {
id: 'admin-seed-001',
phone: '+84900000001',
phoneHash,
email: 'admin@goodgo.vn',
emailHash,
passwordHash,
fullName: 'Admin',
role: 'ADMIN',
kycStatus: 'VERIFIED',
isActive: true,
totpEnabled: false,
totpBackupCodes: [],
},
});
🧪 Test Login
curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{
"phone": "0900000001",
"password": "AdminPassword123"
}'
Success Response:
{
"requiresMfa": false,
"tokens": {
"accessToken": "eyJ...",
"refreshToken": "eyJ...",
"expiresIn": 3600
}
}
⚠️ Common Issues
| Issue | Fix |
|---|---|
| User can't login | Check: passwordHash ≠ null, isActive = true |
| "Invalid phone" | Phone must match regex (mobile only) |
| Hash mismatch | Verify FIELD_ENCRYPTION_KEY is consistent |
| MFA issue | Verify MFA_BACKUP_CODE_SECRET env var |
| PII not encrypted | Verify key is exactly 32 bytes (64 hex chars) |
📁 Key Files
| File | Purpose |
|---|---|
hashed-password.vo.ts |
bcrypt hashing |
vietnam-phone.validator.ts |
Phone validation |
field-encryption.ts |
AES-256-GCM encryption |
local.strategy.ts |
Login endpoint |
mfa.service.ts |
TOTP / backup codes |
user.entity.ts |
User domain model |
prisma-user.repository.ts |
User persistence |
seed.ts |
Seed script |
🔐 Checklist for Seed User
- Password ≥ 8 chars
- Phone matches regex
- Phone normalized: +84...
- Phone hashed: HMAC-SHA256
- Email lowercased
- Email hashed: HMAC-SHA256
- Password hashed: bcrypt (12 rounds)
isActive: truepasswordHash≠ nulltotpEnabled: falsetotpBackupCodes: []
📚 Full Documentation Files
- AUTHENTICATION_GUIDE.md - Complete technical reference
- AUTH_IMPLEMENTATION_CHECKLIST.md - Implementation checklist & troubleshooting
- SEED_GENERATION_SCRIPT.ts - Ready-to-use seed script
- QUICK_REFERENCE.md - This file
Last Updated: April 12, 2026 Status: ✅ Production-Ready