# Independent Game Backend Authentication API

NBTiktok authenticates the account and signs short-lived JWTs. The game client owns routing. Local, test, and production backends use the same `credentials.gameBackend` contract, audience, and JWKS verifier.

## Game client flow

| Item | Contract |
| --- | --- |
| Backend JWT | `credentials.gameBackend` |
| Public keys | `/.well-known/game-backend-jwks.json` |
| Data identity | `(gameId, space, sub)` |

Call `POST /api/game-client/v2/login` with only email, password, `gameId`, `mode`, and `clientBuild`. When independent backend authentication is enabled, the response includes:

- `backendAuth`: audience, operator, privacy policy, and configuration version; never a URL.
- `credentials.gameBackend`: an Ed25519 JWT valid for at most 30 minutes.

Read separate HTTP and WebSocket URLs from trusted build configuration. A local build may use `NBT_GAME_BACKEND_HTTP_URL=http://127.0.0.1:19101` and `NBT_GAME_BACKEND_WS_URL=ws://127.0.0.1:19101/ws`. Plaintext is permitted only on localhost, `127.0.0.0/8`, or `[::1]`; remote test and production URLs require HTTPS/WSS. Never upload either URL to NBTiktok, and never follow a cross-origin redirect while carrying the Bearer token.

Verify `iss`, the exact `urn:nbtiktok:game-backend:<gameId>` audience, `gameId`, `scope=game.session`, `space`, `sub`, `iat/nbf/exp`, maximum lifetime, signature, and `kid` through [`/.well-known/game-backend-jwks.json`](/.well-known/game-backend-jwks.json). Use `(gameId, space, sub)` as the data identity and isolate Sandbox from Production.

The Node SDK is `@nbtiktok/game-backend-auth` 0.4.x. Use `createVerifier`; the same configuration works in every backend environment and accepts no Token lifetime longer than 1,800 seconds.

## Independent backend WebSocket

This WebSocket is separate from the platform event endpoint `/ws/game-client/v2`: the independent backend uses `credentials.gameBackend.token`, while the platform endpoint continues to use its one-use `credentials.websocket.ticket`. Never interchange them.

Open the trusted backend URL with the fixed `nbt.game-backend.v1` subprotocol. Do not put the Token in the URL, a Cookie, or the subprotocol. Within five seconds of opening, send this text frame, no larger than 20 KiB:

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

Pass the exact text to SDK `verifyWebSocketAuthFrame(text, verifier, currentClaims?)`. Success returns the verified Claims and a safe acknowledgement:

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

After platform Session refresh returns a new Backend JWT, send the same `nbt.auth` frame on the existing connection. Reauthentication requires the same `gameId`, `space`, `sub`, and `sid`, then atomically updates the account snapshot, configuration version, and expiry. Do not accept business frames before initial authentication or while an ordered reauthentication frame is pending. Close when the installed JWT expires.

Use close code `4401` for missing, invalid, or expired authentication, `4403` for an identity change, `4408` for authentication timeout, `1009` for an oversized frame, and `1013` when JWKS is temporarily unavailable. Redact Authorization headers and `token` fields. Browser deployments must also enforce an exact Origin allowlist; native clients without Origin still require JWT authentication.

The repository's runnable `examples/independent-game-backend` service demonstrates HTTP Bearer, first-frame WebSocket authentication, in-place renewal, a browser client, and a Node client on loopback.

## Browser Portal

The third-party site creates `state` and an S256 PKCE transaction, then opens `/game-portal/authorize` with `response_type=code`, `client_id`, exact `redirect_uri`, `state`, `code_challenge`, `code_challenge_method=S256`, and `prompt=login`.

The user re-enters the NBTiktok email and password only on the official NBTiktok page. The callback receives a 60-second, single-use Code and the original `state`; the backend exchanges it at `POST /api/game-portal/v2/token` and verifies `portalToken` with the Portal JWKS.

Production uses the registered HTTPS callback. Local Portal uses only `http://127.0.0.1:<port>/__nbt/callback` or the IPv6 loopback equivalent. Use `createPortalAuthorizationRequest`, `exchangePortalCode`, and `createPortalVerifier` from the SDK.

After verification, create your own HttpOnly, Secure, SameSite=Lax Cookie. Limit it to eight hours and `authorizationExpiresAt`. NBTiktok does not proxy application requests or own the third-party Cookie.
