Skip to content

feat(service-accounts): Authenticate requests with service account tokens - #130914

Merged
skaasten merged 3 commits into
masterfrom
feat/service-account-token-auth
Nov 13, 2026
Merged

skaasten merged 3 commits into
masterfrom
feat/service-account-token-auth

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Allows service account access tokens to be authenticated

Stacked on #130679.

Adds ServiceAccountTokenAuthentication, which accepts sntrym_ bearer tokens. It's registered right after OrgAuthTokenAuthentication, both in the API's default authenticators and in the auth middleware (so rate limits key on the same identity the endpoint sees).

How a token becomes a request credential:

  • It looks up the active token by hash: ServiceAccountTokenReplica in the cell, ServiceAccountToken in control. Revoked (date_deactivated set) and expired tokens return 401.
  • It resolves the account with resolve_service_account. That's the same helper the viewer-context path uses, so it applies the same checks: the account is active and in the token's org, and the org has organizations:service-accounts. We reuse that flag instead of adding a separate token flag, since service accounts aren't available outside the internal org yet.
  • It returns the same service_account AuthenticatedToken as viewer-context auth, with entity_id set to the account ID. Access, project reach, service_account:<id> rate limits and creator attribution work without changes.
  • The credential's scopes are the token's scopes intersected with the account's current scopes. Narrowing the account narrows its existing tokens, but widening the account doesn't widen them.
  • On URLs with organization_id_or_slug, a token for another org fails with a 401. Access would deny it anyway, but this gives a clear error and covers endpoints that never build access.

Not in this PR: throttled date_last_used updates, which need a cell-to-control RPC, the management endpoints for creating and revoking tokens, and the token column in the service-account auth matrix.

via @skaasten.

--

View Session [Sentry]

@sentry-junior
sentry-junior Bot requested a review from a team as a code owner November 12, 2026 14:38
@sentry-junior
sentry-junior Bot requested review from a team as code owners November 12, 2026 14:38
@sentry-junior
sentry-junior Bot added this pull request to stack #130915 November 12, 2026 14:38
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 12, 2026
@sentry-junior
sentry-junior Bot force-pushed the feat/service-account-token-auth branch from 1fab28a to 734b97c Compare November 12, 2026 14:43
@sentry-junior
sentry-junior Bot requested a review from a team as a code owner November 12, 2026 14:54
@sentry-junior
sentry-junior Bot force-pushed the feat/service-account-token-auth branch from 92b6ac7 to 4158fe0 Compare November 12, 2026 15:34
Base automatically changed from ref/resolve-service-account to master November 12, 2026 17:28
@skaasten
skaasten force-pushed the feat/service-account-token-auth branch from 4158fe0 to a60f158 Compare November 12, 2026 17:28
…kens

Add ServiceAccountTokenAuthentication for sntrym_ bearer tokens and
register it next to OrgAuthTokenAuthentication in the API and the auth
middleware.

It looks up the active token by hash (the cell replica in the cell, the
token in control), rejects revoked and expired tokens, and resolves the
account with resolve_service_account, so it applies the same active, org
and feature checks as viewer-context auth. The credential is the same
service_account AuthenticatedToken, with entity_id set to the account,
so access, rate limits and attribution work unchanged. Its scopes are
the token's scopes intersected with the account's current scopes.

A token used on another organization's URL fails with a 401.
…owser login

The auth middleware leaves Django's request.user anonymous for these
tokens, so login_required views redirect to the login page.
@skaasten
skaasten force-pushed the feat/service-account-token-auth branch from a60f158 to 860210b Compare November 13, 2026 14:34
…ead of first()

first() adds an ORDER BY to a lookup that matches at most one row, which can
lead to poor query plans. Match the org auth token lookup and use get().

Co-Authored-By: Shaun Kaasten <900809+skaasten@users.noreply.github.com>
@skaasten
skaasten merged commit c0c9bc1 into master Nov 13, 2026
98 checks passed
@skaasten
skaasten deleted the feat/service-account-token-auth branch November 13, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants