Skip to main content

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.

ScopeGrants
games:readRead the catalog
battles:readRead battles
battles:writeOpen and manage battles
bots:writeSeat bots
viewer:mintMint viewer tokens
demo:mintMint 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:

  1. Issue the replacement.
  2. Deploy it to the consumer.
  3. 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 bug

A 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:write if 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