Add stateless JWT credentials for Duo Workflow

Summary

Part of work item #617039 (closed) and #617040 (closed). Duo Workflow needs short-lived credentials that don't require a DB row per token.

Authn::Tokens::StatelessAccessToken mints and verifies a prefixed (glsat-) RS256 JWT via TokenIssuer, duck-typing an OAuth access token via Authn::Tokens::Concerns::DoorkeeperCompatible so it plugs into the existing Doorkeeper/AccessTokenValidationService path.

  • StatelessAccessToken::Result carries the plaintext token back to the issuing caller; StatelessAccessToken::Denylist backs revocation with a TTL-bounded Redis key, since there's no DB row to flag.
  • Composite-identity tokens (gitlab.identities claim) gate the duo_workflow_use_token_issuer flag on the embedded human user, and are rejected outright if that user can't be resolved (deleted account, or more than one kind:user entry) rather than silently falling back to gating on the service account.
  • Malformed payloads (missing jti/exp/iat) are rejected in build_from_payload rather than raising past the JWT::DecodeError rescue.

Gated behind the duo_workflow_use_token_issuer feature flag.

Depends on

  • Targets !254059 (merged) (Require TokenIssuer callers to pass explicit audiences) — needs TokenIssuer's audiences: keyword.
  • Also depends on !254062 (merged) (Extract Authn::Tokens::Concerns::DoorkeeperCompatible from IamOauthToken), merged into this branch directly so CI is green now. Once !254059 (merged) and !254062 (merged) land on master, this MR should be rebased to target master directly — at that point its diff will shrink to just the StatelessAccessToken files.

Test plan

  • ee/spec/lib/authn/tokens/stateless_access_token_spec.rb
  • ee/spec/lib/authn/tokens/stateless_access_token/denylist_spec.rb
Edited by Shilpa Kundapur

Merge request reports

Loading
Loading