# API xác thực backend trò chơi độc lập

NBTiktok xác thực tài khoản và ký JWT ngắn hạn; máy khách trò chơi tự chọn tuyến mạng. Backend cục bộ, kiểm thử và chính thức dùng cùng hợp đồng `credentials.gameBackend`, audience và bộ xác minh JWKS.

## Luồng máy khách

| Mục | Hợp đồng |
| --- | --- |
| Backend JWT | `credentials.gameBackend` |
| Khóa công khai | `/.well-known/game-backend-jwks.json` |
| Danh tính dữ liệu | `(gameId, space, sub)` |

Gọi `POST /api/game-client/v2/login` chỉ với email, mật khẩu, `gameId`, `mode` và `clientBuild`. Khi xác thực backend độc lập được bật, phản hồi có `backendAuth` không chứa URL và `credentials.gameBackend` là JWT Ed25519 có hiệu lực tối đa 30 phút.

Đọc riêng URL HTTP và WebSocket từ cấu hình build đáng tin cậy. Cục bộ có thể dùng `NBT_GAME_BACKEND_HTTP_URL=http://127.0.0.1:19101` và `NBT_GAME_BACKEND_WS_URL=ws://127.0.0.1:19101/ws`. Chỉ localhost, `127.0.0.0/8` hoặc `[::1]` được dùng HTTP/WS rõ; môi trường từ xa phải dùng HTTPS/WSS. Không tải URL lên NBTiktok và không mang Bearer qua redirect khác Origin.

Backend phải kiểm tra chữ ký, `kid`, issuer, audience chính xác, `gameId`, `scope=game.session`, `space`, `sub`, `account`, `iat/nbf/exp` và thời hạn tối đa bằng [`/.well-known/game-backend-jwks.json`](/.well-known/game-backend-jwks.json). Khóa dữ liệu là `(gameId, space, sub)` và Sandbox phải tách khỏi Production.

SDK Node `@nbtiktok/game-backend-auth` 0.4.x cung cấp `createVerifier`; cùng cấu hình hoạt động ở mọi môi trường và từ chối Token dài hơn 1,800 giây.

## WebSocket của backend độc lập

WebSocket này tách biệt với endpoint sự kiện nền tảng `/ws/game-client/v2`: backend độc lập dùng `credentials.gameBackend.token`, còn endpoint nền tảng tiếp tục dùng `credentials.websocket.ticket` một lần. Không được dùng lẫn nhau.

Kết nối URL backend đáng tin cậy bằng subprotocol cố định `nbt.game-backend.v1`. Không đặt Token trong URL, Cookie hoặc subprotocol. Trong năm giây sau khi mở, gửi text frame không quá 20 KiB:

```json
{"type":"nbt.auth","token":"<credentials.gameBackend.token>"}
```

Backend chuyển nguyên văn tới SDK `verifyWebSocketAuthFrame(text, verifier, currentClaims?)`. Thành công trả Claims đã xác minh và ACK an toàn:

```json
{"type":"nbt.auth.ok","expiresAt":"2026-09-02T12:30:00.000Z"}
```

Sau khi refresh Session nền tảng trả Backend JWT mới, gửi lại cùng frame `nbt.auth` trên kết nối hiện tại. Gia hạn yêu cầu giữ nguyên `gameId`, `space`, `sub`, `sid`, rồi cập nhật nguyên tử snapshot tài khoản, phiên bản cấu hình và hạn dùng. Không xử lý frame nghiệp vụ trước xác thực đầu tiên hoặc sau frame gia hạn đang chờ theo thứ tự; đóng kết nối khi JWT đã cài hết hạn.

Dùng mã đóng `4401` cho xác thực thiếu, sai hoặc hết hạn; `4403` khi đổi danh tính; `4408` khi quá thời gian; `1009` khi frame quá lớn; `1013` khi JWKS tạm không dùng được. Che Authorization và `token` trong log. Bản trình duyệt phải kiểm tra Origin chính xác; máy khách native không có Origin vẫn phải xác thực JWT.

Dịch vụ chạy được tại `examples/independent-game-backend` minh họa HTTP Bearer, xác thực frame đầu, gia hạn tại chỗ, máy khách trình duyệt và Node trên loopback.

## Portal trình duyệt

Trang bên thứ ba tạo `state` và PKCE S256 rồi mở `/game-portal/authorize`. Người dùng nhập lại email và mật khẩu chỉ trên trang NBTiktok chính thức. Callback nhận Code dùng một lần trong 60 giây; backend đổi Code tại `POST /api/game-portal/v2/token` và xác minh `portalToken` bằng Portal JWKS.

Production dùng callback HTTPS đã đăng ký chính xác. Cục bộ chỉ dùng `http://127.0.0.1:<port>/__nbt/callback` hoặc loopback IPv6. SDK cung cấp `createPortalAuthorizationRequest`, `exchangePortalCode` và `createPortalVerifier`.

Sau khi xác minh, backend tự tạo Cookie HttpOnly, Secure, SameSite=Lax, tối đa tám giờ và không vượt `authorizationExpiresAt`. NBTiktok không proxy request nghiệp vụ và không sở hữu Cookie bên thứ ba.
