feat(oauth): add IsRevoked RPC for access-token revocation checks

This MR delivers the gRPC half of gitlab-org/gitlab#603631. It adds InternalOAuthTokensService.IsRevoked(jti) → {revoked} to check token revocation state. Rails validates gliamat- tokens against IAM's JWKS and needs only revocation state. The HTTP /oauth/introspect endpoint (RFC 7662) is a separate follow-up. The handler queries Storage.IsAccessTokenRevoked, wrapping revokedtokens.IsRevoked added in !388 (merged).

The RPC takes jti instead of the token because every revocation path (RFC 7009 /oauth/revoke, refresh rotation, and app de-authorization) already records jti in revoked_tokens. Taking jti keeps the token off the Rails object and out of its logs, which matches the contract the Rails draft MR gitlab-org/gitlab!256142 (merged) already relies on. Expiry remains the caller's responsibility, while a malformed jti returns INVALID_ARGUMENT and lookup failures return INTERNAL without leaking the cause. Tests cover both answers, proto validation, and storage integration on Postgres and YugabyteDB. After merge, Rails regenerates its stubs with scripts/update-iam-grpc-client.sh (docs/rails-grpc-client-updates.md).

  • fosite: The framework ships CoreValidator (signature lookup) and StatelessJWTValidator (JWT verification) but neither answers "is this jti revoked"; Hydra has the same gap.
  • This RPC: One indexed denylist lookup. Revocation handling already funnels all paths through revoked_tokens; the check is custom because fosite cannot hook JWT revocation and the caller already validated the signature.
  • Doorkeeper parity: Doorkeeper 5.9.3 reports introspection as active when tokens are neither expired nor revoked; this RPC covers the revoked half for the Rails hot path. Doorkeeper tokens are opaque with no jti, so no direct equivalent exists.

Merge request reports

Loading
Loading