Workhorse: Proxy OAuth calls to the IAM Auth Service during gradual rollout

Overview

As part of the gradual rollout plan for OAuth in Protocells (AUTH-011), Workhorse and Rails act as a temporary reverse proxy for OAuth traffic during the migration period. No changes to the HTTP Router are required during the rollout phase — OAuth requests continue to arrive at Rails exactly as today.

Workhorse is responsible for inspecting each incoming OAuth request and deciding whether to handle it locally (Doorkeeper/Rails) or proxy it to the IAM Auth service, based on feature flag state, query parameter presence, and token prefixes.

Routing Logic

Workhorse applies the following routing logic for OAuth endpoints:

Endpoint Condition Action
/.well-known/openid-configuration Always Proxy to IAM Auth service
/oauth/discovery/keys Always Proxy to IAM Auth service
/oauth/userinfo Always Handle locally (Rails)
/oauth/device Always Handle locally (Rails)
/oauth/authorize, /oauth/authorize_device Feature flag enabled for client/percentage or IAM Auth-specific query parameter is present Proxy to IAM Auth service
/oauth/authorize, /oauth/authorize_device Feature flag not enabled Handle locally (Doorkeeper)
/oauth/token, /oauth/revoke, /oauth/introspect Token has giat_ prefix Proxy to IAM Auth service
/oauth/token, /oauth/revoke, /oauth/introspect No prefix (Doorkeeper token) Handle locally (Doorkeeper)

Requirements

  • Proxy /.well-known/openid-configuration unconditionally to the IAM Auth service
  • Proxy /oauth/discovery/keys unconditionally to the IAM Auth service
  • Always handle /oauth/userinfo and /oauth/device locally in Rails
  • For /oauth/authorize and /oauth/authorize_device: proxy to IAM Auth service when the feature flag is enabled for the client/percentage or an IAM Auth-specific query parameter is present; otherwise handle locally via Doorkeeper
  • For /oauth/token, /oauth/revoke, and /oauth/introspect: inspect the token/code/refresh_token parameter — proxy to IAM Auth service if it carries the giat_ prefix, otherwise handle locally via Doorkeeper
  • Use the existing PreAuthorize or send-url mechanism to call Rails for feature flag checks
  • Support a new Authn::OAuthApplication actor type in Rails feature flags for per-client rollout control
  • Emit structured log entries for each OAuth request indicating whether it was handled locally or forwarded to the IAM Auth service
  • This proxy logic must be cleanly removable after the Phase 5 Cloudflare Origin Rule cutover

Background

The routing decision is non-trivial because OAuth flows are stateful — multiple sequential requests must reach the same service that started the flow. The giat_ prefix on IAM Auth-issued tokens/codes ensures that once a flow starts on IAM Auth, all subsequent requests (token exchanges, revocations) are automatically proxied to IAM Auth without additional feature flag checks.

IAM Auth service issues structured opaque codes with a giat_ prefix:

code=giat_ac_Hn_JMPQas_4diX0q1BruK68BFx0PtxF2x7u6Bb2cUH0.kBMbu366Lq_P8dQVo8uHVMQfWHwwFF45F6_oXmZgdfQ

Doorkeeper issues opaque codes with no prefix or structure:

code=SplxlOBeZQQYbYS6WxSbIA39dkJm8z

Checklist for the MRs to achieve this issue

  • MR 1: Workhorse skeleton + structured logging
  • MR 2: Token-prefix routing
  • MR 3: Rails FF infrastructure
  • MR 4: Workhorse FF-gated routing

References

Edited by 🤖 GitLab Bot 🤖