feat(oauth): add token prefixes for routable tokens

Summary

  • Adds prefixes to three token types (gliamac- authorization code, gliamat- access token, gliamrt- refresh token), for the OAuth gradual rollout and Cells routing. Part 1 of gitlab-org/gitlab#604548 (closed).
  • Enables Workhorse to distinguish IAM-issued tokens from Doorkeeper tokens during the gradual rollout. Enables the Cells HTTP Router to recognize tokens for cell-based routing (a follow-up adds the actual routing claim; this MR adds the prefix it will key off).
  • Wraps fosite's core strategy to inject and strip prefixes without reimplementing any cryptographic logic.

What changed

  • auth/oauth/core/token_prefix.go (new): prefixedCoreStrategy wraps fosite's oauth2.CoreStrategy interface. It overrides the token generation and validation methods to prepend/strip the appropriate prefix around calls to the wrapped strategy. All HMAC and JWT operations remain delegated to the wrapped strategy, unchanged. Prefix stripping uses strings.TrimPrefix, a no-op when the prefix is absent — but that's not a backward-compatibility guarantee: IAM has never been deployed, so there's no pre-existing population of unprefixed tokens to support.

  • auth/oauth/core/provider.go: switched from fosite's compose.NewOAuth2HMACStrategy (which silently applies fosite's own default ory_ac_/ory_rt_ prefixes — unnoticed until now, since nothing in this codebase asserted on token format) to oauth2.NewHMACSHAStrategyUnPrefixed, so prefixedCoreStrategy is the only source of a prefix rather than doubling up. The existing strategy chain (newJTIJWTStrategy(...)) is now wrapped with newPrefixedCoreStrategy(...).

  • auth/oauth/server/handler_integration_test.go: two tests that parsed the access token as a bare JWT now strip core.AccessTokenPrefix first. Rollout coordination point for reviewers: any current or future consumer that treats IAM's access token as a bare JWT (an RFC 9068 resource server, introspection, etc.) will break the moment this ships unless it strips gliamat- first.

  • auth/oauth/server/revokedtokens/revokedtokens.go: removed a stale doc comment referencing the placeholder prefix name giat_ (an earlier draft value from the ticket, never implemented).

  • No migration: signature columns on both backends are TEXT and store only the token's HMAC/JWT signature, never the full token, so the prefix never touches them.

Testing

  • Unit tests (go test ./...): pass
  • Integration tests against both backends (ENV=development-l2 and ENV=development-l1, go test -tags=integration ./auth/oauth/...): pass
  • golangci-lint: 0 issues
  • ./scripts/verify-agent-docs.sh: all documented claims hold

Out of scope (tracked separately)

  • Cell/user-ID routing claims on the access token (ticket section 8.2): !590 (merged), stacked on this MR. Sourced from gitlab-rails via LoginService.Accept, not from a Topology Service call in IAM — investigating that turned out to be unnecessary and blocked on infra access IAM doesn't have.
  • Claiming the prefixes in gitlab-org/gitlab's docs/security/tokens/_index.md: separate repo, separate MR.
  • The Cells HTTP Router ruleset change (gitlab-org/cells/http-router, TypeScript) that will parse gliamat-: separate repo; IAM team committed to authoring it per the issue thread.
Edited by Shilpa Kundapur

Merge request reports

Loading
Loading