Summary
Let users issue long-lived API tokens so external clients — Claude Code, Codex and other LLM
agents talking to the Bublik MCP server, plus CI jobs and scripts — can call the Bublik API
on behalf of the user. A request made with a token should be able to do exactly what that
user can do through the web UI: leave a comment on a run, classify results under an issue, and
every other action.
Today the only way in is the short-lived JWT cookie pair set at login, which a headless client
can't realistically use. The MCP server has no authentication and no notion of a calling user,
so it can only ever expose read-only tools.
What we want
- Users issue named tokens from their profile.
- Expiry is picked from fixed options: 7 / 30 / 90 days, or never.
- The token value is shown exactly once, at creation. It can never be retrieved again.
- One token works for both the REST API and the MCP server.
- Everything a token does is attributed to its owner.
- Users see their own tokens — name, prefix, created, expires, last used, status — and can
revoke them.
- Admins see all users' tokens and can revoke any of them.
Not in this ticket
- Per-token scopes or permissions. A token simply inherits its owner's permissions.
- Service accounts not tied to a human user.
- Rotating a token in place (rotating means revoke + issue a new one).
Behaviour
Tokens carry a bpat_ prefix so they're recognisable in logs and by secret scanners. The
first few characters stay visible in the UI as a handle, so a user can tell which token a client
is configured with without ever seeing the secret again.
Storage keeps no recoverable copy of the token — there must be no code path, for a user or an
admin, that can display a token after creation.
Revocation takes effect on the very next request. Revoked tokens stay in the list as a record
of who revoked what, rather than disappearing.
Expiry is enforced per request. "Never" really means never.
Last used is recorded on use and shown in the UI at minute granularity.
Deactivating a user stops that user's tokens from working.
Existing browser login is unaffected — cookie sessions keep working exactly as they do now.
User flows
Issuing a token for Claude Code
- User opens Profile → Access tokens and clicks "New token".
- Names it (
code-laptop) and picks an expiry: 7 / 30 / 90 days / Never.
- The token appears once, with a copy button and a clear warning that it won't be shown again.
The dialog also shows how to plug it into an MCP client.
- User pastes it into their code config. From then on, agent actions — including
comments left on runs — show up in Bublik as that user's actions.
- Back in the list, the token shows only its prefix, its expiry, and "Never used" until first use.
Revoking a leaked token
- User notices a token they no longer recognise, or one they pasted somewhere public.
- They see when it was last used, which tells them whether it's actually been abused.
- They revoke it; the next request made with it fails.
- They issue a replacement and update their client.
Admin cleaning up
- An admin opens the admin token list and sees every token across all users, with owner,
expiry and last-used.
- They spot tokens belonging to someone who has left, or ones unused for months.
- They revoke them. The record shows which admin did it.
- Admins never see token values — that's structurally impossible, and it's the point.
Security requirements
- Token values never appear in logs, error reports or the eventlog.
- Expired, revoked and invalid tokens each fail with a distinguishable message, so agents can be
debugged without guesswork.
- Cap the number of tokens per user (suggest 20) and rate-limit creation.
- MCP responses are cached today. Once requests carry an identity, that cache must never serve
one user's response to another. Treat this as blocking — it's the one place where adding
authentication could actively leak data.
Acceptance criteria
Open questions
- Is MCP authentication mandatory, or opt-in via a setting? Mandatory breaks existing
unauthenticated local setups. Probably required in production, optional locally — needs a call.
- Should a password reset also revoke tokens? Leaning no: it would silently break users' CI,
and tokens are independently revocable.
- Should users get a warning email before a token expires, to avoid silent CI breakage?
Summary
Let users issue long-lived API tokens so external clients — Claude Code, Codex and other LLM
agents talking to the Bublik MCP server, plus CI jobs and scripts — can call the Bublik API
on behalf of the user. A request made with a token should be able to do exactly what that
user can do through the web UI: leave a comment on a run, classify results under an issue, and
every other action.
Today the only way in is the short-lived JWT cookie pair set at login, which a headless client
can't realistically use. The MCP server has no authentication and no notion of a calling user,
so it can only ever expose read-only tools.
What we want
revoke them.
Not in this ticket
Behaviour
Tokens carry a
bpat_prefix so they're recognisable in logs and by secret scanners. Thefirst few characters stay visible in the UI as a handle, so a user can tell which token a client
is configured with without ever seeing the secret again.
Storage keeps no recoverable copy of the token — there must be no code path, for a user or an
admin, that can display a token after creation.
Revocation takes effect on the very next request. Revoked tokens stay in the list as a record
of who revoked what, rather than disappearing.
Expiry is enforced per request. "Never" really means never.
Last used is recorded on use and shown in the UI at minute granularity.
Deactivating a user stops that user's tokens from working.
Existing browser login is unaffected — cookie sessions keep working exactly as they do now.
User flows
Issuing a token for Claude Code
code-laptop) and picks an expiry: 7 / 30 / 90 days / Never.The dialog also shows how to plug it into an MCP client.
comments left on runs — show up in Bublik as that user's actions.
Revoking a leaked token
Admin cleaning up
expiry and last-used.
Security requirements
debugged without guesswork.
one user's response to another. Treat this as blocking — it's the one place where adding
authentication could actively leak data.
Acceptance criteria
Open questions
unauthenticated local setups. Probably required in production, optional locally — needs a call.
and tokens are independently revocable.