Đặc tả: Authentication Feature
Module: authentication (port 8085)
Status: Production
1. Tổng quan
Feature này cung cấp cơ chế xác thực user qua nhiều provider (Web3Auth/Immutable) và quản lý session/JWT cho toàn hệ thống BountyHunter. Mọi API của các module khác đều dựa vào JWT token phát ra từ module này.
2. Mục tiêu
- Multi-provider auth: Hỗ trợ
WEB3_AUTH, DM2, IMMUTABLE, WEB3_AUTH_SOLANA login types.
- JWT session: Cấp access token + refresh token an toàn, single-device policy via Redis.
- Wallet management: Tự động tạo/cập nhật ví blockchain (Biconomy, DM2, Solana, Immutable) khi login.
- User lifecycle: Tạo user mới, init coin/ticket/equipment, assign NFT ownership khi first login.
3. Phạm vi
In-scope
| Endpoint |
Method |
Mô tả |
/api/auth/generate-code |
POST |
Tạo auth code và trả JWT (new/existing user) |
/api/auth/sign-in |
POST |
Xác thực nội bộ bằng auth code + trả UserAuthResponse |
/api/auth/logout/{firebaseToken} |
DELETE |
Logout device cụ thể, xóa session |
/api/auth/check-email |
POST |
Kiểm tra email tồn tại, trả userId + wallet info |
Out-of-scope
| Mục |
Lý do |
| OAuth2 authorization code flow |
Không dùng flow này |
| Email/password login |
Hệ thống dùng Web3/blockchain auth |
| Admin console auth |
Thuộc module admin riêng |
4. User stories
| ID |
Role |
Story |
Acceptance |
| AUTH-US-01 |
Mobile user |
Đăng nhập bằng Web3Auth lần đầu → hệ thống tự tạo account + ví + cấp JWT |
User nhận access_token + refresh_token |
| AUTH-US-02 |
Existing user |
Re-login cùng provider → hệ thống update ví, cấp token mới, không tạo duplicate account |
Token mới, account cũ |
| AUTH-US-03 |
User đa thiết bị |
Login trên thiết bị mới → push notification tới thiết bị cũ "NEW_DEVICE_CONNECTED" |
Thiết bị cũ nhận notification |
| AUTH-US-04 |
User bị ban |
Cố login → nhận lỗi YOUR_ACCOUNT_HAS_BEEN_BANNED |
4xx error, không cấp token |
| AUTH-US-05 |
User logout |
Gọi logout/{firebaseToken} → device token bị xóa, session Redis bị invalidate |
Token không còn dùng được |
5. Functional requirements
| ID |
Requirement |
Chi tiết |
| AUTH-F-01 |
Login type routing |
Factory chọn đúng handler theo login_type: WEB3_AUTH/IMMUTABLE/DM2/WEB3_AUTH_SOLANA |
| AUTH-F-02 |
New user creation |
Nếu email/verifierId chưa tồn tại: tạo UserModel, set status=ACTIVE, random avatar, referral code |
| AUTH-F-03 |
Wallet creation |
Tạo UserWalletModel theo walletType (BICONOMY/DM2/SOLANA/IMMUTABLE), kèm secondary wallet async |
| AUTH-F-04 |
User initialization |
Async init: UserSystemCoin, UserSystemTicket, UserEquipment, gửi welcome email |
| AUTH-F-05 |
Auth code |
Generate 6-char code random từ ABCDEFGHJKLMNPQRSTUVWXYZ1234567890, TTL 5 phút |
| AUTH-F-06 |
JWT generation |
SecurityJwtService.createUserAuthResponse trả accessToken + refreshToken |
| AUTH-F-07 |
Session management |
UserSessionRepository lưu session vào Redis theo userId; single-device per site (x-site: APP) |
| AUTH-F-08 |
Device token |
Lưu firebase token theo device type, xóa token cũ khi đăng nhập thiết bị mới |
| AUTH-F-09 |
Banned check |
User status=NO_ACTIVE → BannedException("YOUR_ACCOUNT_HAS_BEEN_BANNED") |
| AUTH-F-10 |
Lock concurrency |
Lock theo USER_EMAIL_LOCKER:{verifierId} để tránh tạo duplicate account concurrent |
| AUTH-F-11 |
API key guard |
sign-in và check-email yêu cầu header x-api-key match application.authentication.secret-key |
| AUTH-F-12 |
NFT ownership assign |
Async gọi NftOwnerService.assignNftOwner(userId, verifierId, publicAddress) sau khi tạo user |
6. Business rules
- Login code TTL:
CODE_TIME_OUT = 5 phút.
- Code length:
CODE_LENGTH = 6 ký tự.
- Wallet type mapping:
WEB3_AUTH → BICONOMY
DM2 → DM2
WEB3_AUTH_SOLANA → SOLANA
IMMUTABLE → IMMUTABLE
WEB3_AUTH và DM2 user đều có secondary wallet loại còn lại (async).
loginSession counter: 0=new, 1=first login (lưu firstLoginAt), ≥2=subsequent.
x-site: APP header kích hoạt single-device session enforcement.
7. Data contracts
Request - generate-code
{
"login_type": "WEB3_AUTH | DM2 | IMMUTABLE | WEB3_AUTH_SOLANA",
"id_token": "<provider_token>",
"device_type": "IOS | ANDROID | WEB",
"firebase_token": "<fcm_token>",
"language_code": "EN | JA | ...",
"app_pub_key": "<optional>",
"private_key": "<optional>"
}
Response - CodeLoginResponse
{
"id": "<userId>",
"code": "ABC123",
"verifier_id": "<verifierId>",
"login_type": "WEB3_AUTH",
"create_time": "2024-01-01T00:00:00Z",
"expired_at": "2024-01-01T00:05:00Z",
"is_first_login": false,
"access_token": "<jwt>",
"refresh_token": "<jwt>",
"message": null
}
Request - sign-in (x-api-key required)
{
"id": "<userId>",
"code": "<authCode>",
"login_type": "WEB3_AUTH",
"verifier_id": "<verifierId>"
}
Response - check-email
{
"user_id": "<id>",
"user_name": "<username>",
"wallet_biconomy": "0x...",
"wallet_dm_two": "0x..."
}
8. Acceptance criteria
- [ ] Gọi
generate-code với login_type=WEB3_AUTH → trả CodeLoginResponse với valid JWT
- [ ] Gọi cùng email 2 lần concurrent → không tạo 2 user (lock mechanism)
- [ ] User
NO_ACTIVE gọi sign-in → nhận YOUR_ACCOUNT_HAS_BEEN_BANNED
- [ ] Sai
login_type → nhận INVALID_LOGIN_TYPE
- [ ]
sign-in không có x-api-key → nhận SECRET_KEY_IS_INVALID
- [ ]
logout/{firebaseToken} xóa đúng device token và invalidate session
- [ ] First login (
loginSession == 1) → is_first_login: true trong response
- [ ] Device login mới → thiết bị cũ nhận push notification
NEW_DEVICE_CONNECTED
- [ ] Auth code expire sau 5 phút
9. Constraints
- Rate limit trên
generate-code được comment out, có thể re-enable: @RateLimit(windowSeconds=5, maxRequests=1).
create-account-fake endpoint chỉ dùng cho internal testing.
- Session data lưu trong Redis với key theo userId (TTL managed by
UserSessionRepository).
10. Code references
authentication/
controllers/auth/
AuthController.java # REST endpoints
AuthService.java # Business logic (signIn, generateCode)
AuthAsyncService.java # Async: wallet, device, email, NFT
SecurityJwtService.java # JWT generation/validation
handler/
LoginHandler.java # Interface
LoginHandlerFactory.java # Strategy factory theo login_type
Web3AuthLoginHandler.java # WEB3_AUTH + DM2 + SOLANA handler
ImmutableLoginHandler.java # IMMUTABLE handler
infrastructures/spring-security-jwt/
JwtTokenFilter.java # JWT filter trên mọi request
SecurityConfig.java # Whitelist + stateless config