Skip to content

Đặ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_ACTIVEBannedException("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-incheck-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_AUTHBICONOMY
  • DM2DM2
  • WEB3_AUTH_SOLANASOLANA
  • IMMUTABLEIMMUTABLE
  • WEB3_AUTHDM2 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