uk_ct_… contact session. Your backend needs to know who is
calling it, and asking us on every request would put our latency and our uptime in
front of your API.
So the contact session buys a short-lived JWT, signed per environment, that
your backend verifies offline against a public key set.
Minting
Each mint records the contact against the month’s active-contact meter,
idempotently. That is the number your bill reads — see
the meter.
What the token carries
string
The environment id. Pin it. A test-environment token must not satisfy a live
check.
uuid
The contact id.
uuid
The session id — what you pass to
DELETE /v1/contact/sessions/{id}.string
Your own id for this person, present when the contact has one. In federated mode
this is what your backend keys on.
string
boolean
Whether the identity behind the session was proven. Gate on this before
anything another person’s data could leak through — a
verified: false token is
a perfectly valid signature over an unproven claim.integer
Unix seconds. The lifetime is 5 minutes.
Verifying
Fetch the key set once, cache it, and verify locally.Cache the key set
The response carries:POST /v1/contact/token is where you get the 501 jwt_unavailable.
Revocation, and the five minutes
A JWT is verified offline, so nothing can recall one. Deleting a session stops the next refresh, not the token already in a page. That makes five minutes the longest a revoked session keeps working — and it is the whole reason the long-lived credential is the opaque, revocable one and the short-lived credential is the signed one. If you need immediate revocation for a particular action, check the session server-side for that action rather than lengthening the JWT.Sessions the contact can see
The contact session token lives on your domain withouthttpOnly. That makes “see
my devices and end one” part of the token’s safety case, not a nice-to-have.
404.
Rotating the signing key
api_keys:write — the same gate as the identity secret, because this key
mints the tokens your backend trusts.
The old key stops signing immediately and keeps verifying for 24 hours: the
overlap that lets JWKS caches refresh and in-flight tokens expire. Your backend
needs no deploy — it refetches the key set and finds both kids.
For a suspected compromise the arithmetic runs the other way: every token signed
with the old key is dead within its 5-minute lifetime of the rotation. That is the
bound to quote.
The active-contact meter
customers:read. A contact counts as active for a month when a JWT is
minted for them — so a session opened in January and refreshed in February is
active in both.
Live environment only, because only live contacts count at all. The month is
UTC, decided once in the schema: display may translate it, a bill may not be
ambiguous. This reads the same query the bill reads.