Secure from the start.
Ready for the regulator.
Identity
Identity, delegated.
No passwords held.
Multi-factor for players and staff
TOTP and brute-force protection from the identity provider, enforced for every staff account.
A session outlives no token
An open connection closes when its token expires or the account is suspended; the client renews its token on the open connection instead.
No development shortcuts in production
Development sign-in works in Development only; anywhere else, a service without an identity provider refuses to start.
Players
- realm
- poker
- client
- poker-web · public, PKCE S256
- audience
- poker-platform
- role
- Player
- policy
- TOTP · brute-force protection
Staff
- realm
- poker-staff
- client
- poker-backoffice · public, PKCE S256
- audience
- poker-admin-api
- roles
- Ops · Finance · Risk · Compliance · Support · Marketing · Auditor · SuperAdmin
- policy
- TOTP · brute-force protection
Private PKI
Your own CA.
Strict by default.
Strictthe default
Refuses a certificate that is revoked — and one whose status cannot be learned within ten seconds.
RevokedOnlyfor a private CA
Refuses a revoked certificate; accepts an unknown status with a warning on every fetch, for a CA that publishes no CRL or OCSP responder.
Offsaid out loud
Checks nothing, and says so once at startup.
staffAuth:
# The staff identity provider for the admin API: a realm apart from the players', with MFA
# and session policy set there. Empty means the development header scheme — and outside Development the
# admin API refuses to start without it, so a real install sets this whenever adminApi is enabled.
authority: ""
audience: poker-admin-api
# As auth.ca, for the staff provider: mounted into the admin API and passed as
# StaffAuth__CaCertificatePath. The same Secret as auth.ca when one CA issued both.
ca:
secretName: ""
key: ca.crt
# As auth.certificateRevocation, for the staff provider: StaffAuth__CertificateRevocation on the admin API.
# Empty means Strict.
certificateRevocation: ""
Workloads
Locked-down workloads.
Least privilege, per pod.
- Secrets from Secrets. Database, cache, bus and archive-key credentials, and identity-provider CAs, are read only from Kubernetes Secrets — never from values files.
- Hardened web apps. A Content-Security-Policy, nosniff, frame denial, referrer and permissions policies — and cross-origin access off unless an origin is listed.
- Hole cards stay hidden. A hole card never appears in a broadcast, a log line or a staff view of a live hand.
# Every workload runs unprivileged: the images run as a non-root user (packaging/docker/Dockerfile:
# USER $APP_UID) and need no capabilities, so the rendered pods meet the restricted Pod Security
# Standard. Kept as values for a runtime that insists on its own (OpenShift assigns the user itself).
podSecurityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
111 / 111
checks on a production-shaped cluster
real sign-in, autoscaling, failover, network policies — zero pod restarts
Records and retention
Records kept for the regulator.
For as long as they ask.
Months 1–13
Live database
Every hand, entry and result, read by players, the game and the back office — never under twelve months.
Month 14
Archived, after a clean reconciliation
Exported, read back, hashed and encrypted; copied row for row to the history database; only then dropped from the live one.
Months 14–24
History database
Hands with their replays, entries and results, still searchable; the records stay for the legal period.
Retention period
Archive files
SHA‑256-checked, AES‑256‑GCM encrypted, on write-once storage — players by id only.
Nothing leaves unreconciled
Tamper-evident archives
Players by id only
Evidence a laboratory can read
The player
Protect the player.
Keep the books.
01
Responsible gambling
02
National self-exclusion registers
03
Player data on request
04
Account closure that keeps the books
Closing an account
01
Asked
The player asks to close their account.
02
Grace period
The account waits, pending deletion — the player can still change their mind.
03
Anonymised
The name, email and sign-in subject are removed; hands they played lose the name too.
04
Books intact
Ledger entries and the id stay, so every account still balances.
Markets
Every market, its own rules.
Configuration, not code.
KYC, AML and sanctions
Geolocation and geofencing
Jurisdiction rule packs
Vendor adapters
Collusion and bot detection
Change control
Built to be certified.
Every change, classified.
- Major or minor, with the reasoning in the record — a change to the ledger or to how the rules are implemented goes to the laboratory.
- Why it changes, what changes, the evidence, and how to deploy and roll it back.
- Fields for the operator's laboratory submission and release authority, so the record travels with the release.
| Change id | CR-2026-09-27-B |
| Date | 2026-09-27 |
| Classification | **Major — submit to the test laboratory before production use** (see below) |
| Depends on | CR-2026-09-27-A (deployed first) |
| Laboratory submission | _to be completed by the operator: laboratory, reference, date_ |
| Authorised by | _to be completed by the operator's release authority_ |
## Classification and justification
Bring your compliance team.
We will bring the evidence.
A live walkthrough of the engine, the back office and a production-shaped cluster — with the numbers behind every claim on this site.