API keys
Where the S2S credential a casino's backend authenticates with is issued and revoked.
Casino → API keys. Reading the list costs apikeys.read; issuing and revoking cost
apikeys.write.
Issuing
Choose a label and the scopes. The label is for humans, so make it name the consumer ("orders service") rather than the casino, which is already implied. You will need it to tell two keys apart later.
| Scope | Grants |
|---|---|
games:read | Read the catalog |
battles:read | Read battles |
battles:write | Open and manage battles |
bots:write | Seat bots |
viewer:mint | Mint viewer tokens |
demo:mint | Mint a demo game session. Evaluation only, never the production flow |
bots:write is separate from battles:write and is the one most often forgotten. Seating
bots spends the casino's own provider sessions, which is a different act from opening a lobby.
A key without it fails only when someone tries to fill a table, which is late.
The plaintext is shown once
sbk_0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9
Only the SHA-256 hash is stored, plus the first 12 characters for display. There is no way to show it again: losing it means issuing a replacement and revoking the old one.
Deliver it over something that is not a chat scrollback.
Rotating
There is no in-place rotation. The order matters:
- Issue the replacement.
- Deploy it to the consumer.
- Then revoke the old one.
Revoking first means downtime for as long as the deploy takes.
One key per consumer
Revoking a key shared between services takes all of them down at once. Issue separately and scope narrowly, so a compromised key costs you one service instead of the casino.
Revocation is immediate
There is no cache in front of key lookups, so there is nothing to wait out, not even the 30-second window the game allowlist can fall back to.
Everything is attributed
Issuing and revoking record who did it, as the actor's address at the time, snapshotted rather than stored as a foreign key to the users table.
A foreign key would cascade or null out when that user is deleted, erasing the record.
The actor always comes from the session, never the request body. Naming one in the payload is
a 400.
CLI / unknown is not a bugA key your host issued outside the console has no signed-in operator, so the console renders
CLI / unknown rather than a blank cell, which would read as a rendering failure. Keys you
issue from the console carry your own name.
Checklist for handing a key over
- Scopes match what they will actually do, including
bots:writeif they use bots - Label names the consumer, not the casino
- Delivered securely, once
- They know it cannot be recovered
- They know it must never reach a browser