Every issued personal access token, as metadata.
const url = 'https://example.com/api/v1/api-tokens';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://example.com/api/v1/api-tokens \ --header 'Authorization: Bearer <token>'Neither the raw token nor its hash is returned — a token’s value exists only in the response
that created it. These credentials authenticate whichever surfaces each token names — /mcp,
this REST API, or both.
Authorizations
Section titled “Authorizations”Responses
Section titled “Responses”Token metadata only — never the raw token or its hash
One API token’s metadata for the admin listing — never the raw token or its hash (security.md: a credential is never returned in an API response after issuance).
object
When the token stops authenticating, or None for no expiry.
The account the token acts as. None means the owner was deleted before this column
existed, or could not be matched during the 0057 backfill — such a token no longer
authenticates and is shown so an admin can revoke it deliberately.
Whether the owner account is currently able to authenticate (enabled). Surfaced so the listing can explain a token that is live by its own dates yet refused.
The owner’s last interactive sign-in, when the owner authenticates through an external IdP.
This is the only signal Yagra has that an SSO account is still live (see [ApiTokenStore]),
so the listing shows it; None for local and service accounts, where it means nothing.
Predefined roles, ordered least → most privileged.
Which auth surfaces this token may be presented at. Never empty in practice — a token that named no surface could authenticate nowhere — but stored as a list so it can grow.
Example
[ { "role": "viewer", "scope": "All", "surfaces": [ "mcp" ] }]No valid bearer token
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}Role below Admin
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}Skeleton mode has no token store
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}