> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kinematic.run/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> These are the customer docs for kinematic, a name written in lowercase except at the start of a sentence. Kinematic provides provably fair casino games, served to a casino's site by a game server: a Cloudflare Worker that the kinematic dashboard deploys into the casino's own Cloudflare account.
> Never put SESSION_SECRET or WALLET_SECRET in code, prompts, logs, commits or chat. Read them from environment variables and ask the person you work with to set them. The dashboard's Integration page shows each secret once.
> Values such as lucky-star, luckystar.example, og-rgs-lucky-star.luckystar.workers.dev, games.luckystar.example and player_48213 are examples. Use the casino's own casino ID, game server origin, element tag, session issuer and currencies: the Instructions for your coding agent on the dashboard's Integration page hold them, or ask the person you work with.
> To debug, start at https://docs.kinematic.run/troubleshooting and https://docs.kinematic.run/reference/errors. The wallet contract is at https://docs.kinematic.run/api/wallet.openapi.yaml.
> Sandbox bets are recorded on Solana devnet. Live game servers record nothing on Solana until the audited mainnet program is deployed.

# Session token

> A session token has an exact format, and the game server checks it in a fixed order and answers every failure the same way.

A session token is a compact JWT signed with HMAC-SHA256. [Session tokens](https://docs.kinematic.run/integrate/session-tokens.md) shows how to sign one; this page is the exact contract.

## Format

| Part | Rule |
| - | - |
| Header | Exactly `{"alg": "HS256", "typ": "JWT"}`. |
| Claims | The JSON object below. |
| Signature | HMAC-SHA256 over `<header>.<claims>`, keyed with the UTF-8 bytes of your `SESSION_SECRET`. |
| Encoding | Each part base64url without padding, joined with dots. |
| Length | At most 4,096 characters. |

A token decoded, for a player of Lucky Star betting in US dollars:

```json Header theme={null}
{ "alg": "HS256", "typ": "JWT" }
```

```json Claims theme={null}
{
  "sub": "player_48213",
  "tenant": "lucky-star",
  "iss": "https://www.luckystar.example",
  "aud": "og-rgs-v1",
  "currency": "USD",
  "exp": 1793606400,
  "cnf": {
    "jwk": {
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
    }
  }
}
```

## Claims

| Claim | Type | Rule |
| - | - | - |
| `sub` | string | 1 to 128 characters from `A-Z`, `a-z`, `0-9`, `_` and `-`. Your stable player ID. |
| `tenant` | string | Your casino ID. |
| `iss` | string | Your session issuer, exactly as in **Settings**. |
| `aud` | string | `og-rgs-v1`. |
| `currency` | string | A currency your casino serves. Optional while it serves exactly one. |
| `exp` | integer | Seconds since the epoch. Later than now, and at most 3,600 seconds from now. |
| `cnf` | object | Optional. `{"jwk": {"kty": "OKP", "crv": "Ed25519", "x": "<key>"}}`, where `x` is the canonical base64url of a 32-byte Ed25519 public key: 43 characters. |

Other claims, such as `iat` or `jti`, are ignored.

## The checks, in order

The game server refuses the token at the first check that fails:

1. The token is at most 4,096 characters and has three parts.
2. The header's `alg` is `HS256` and its `typ` is `JWT`.
3. The game server has a `SESSION_SECRET` of at least 32 characters.
4. The signature matches.
5. `sub` matches its pattern.
6. `iss` equals the issuer in your settings, and an issuer is set.
7. `aud` is `og-rgs-v1`.
8. `tenant` equals your casino ID.
9. `currency`, or your only currency when the claim is absent, is one your casino serves.
10. `exp` is an integer, in the future and at most an hour ahead.
11. If `cnf` is present, it is an Ed25519 JWK whose `x` matches the canonical 43-character form.

## When a check fails

Every failed check answers the same way, so a token reveals nothing about which rule it broke:

```json HTTP 401 theme={null}
{ "error": "unauthorized" }
```

A token whose header or claims are not valid base64url JSON fails earlier, with `409` and `{"error": "request_failed"}`.

Debug a refused token by decoding it and comparing each claim with the table above, starting with `iss`, `tenant`, `currency` and `exp`. [Troubleshooting](https://docs.kinematic.run/troubleshooting.md#the-game-server-answers-unauthorized) walks through the usual causes.

## How the element sends it

The element sends the token as `Authorization: Bearer <token>` on HTTP requests, and as the WebSocket subprotocol `auth.<token>`, next to `og.v1`, when it opens the game connection. The game server never reads a token from a URL.

When a token expires during a connection, the game server closes the connection with code `4001`, `Session expired`. The element renews tokens before they expire, so players only see this when your session endpoint stops answering.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.