Skip to content

Accept OIDC ID tokens presented with the Bearer scheme - #8081

Open
santhosh-shanmugham wants to merge 1 commit into
flyteorg:masterfrom
santhosh-shanmugham:sshanmugham/admin-bearer-id-token
Open

santhosh-shanmugham wants to merge 1 commit into
flyteorg:masterfrom
santhosh-shanmugham:sshanmugham/admin-bearer-id-token

Conversation

@santhosh-shanmugham

Copy link
Copy Markdown

Tracking issue

Related to #8080, the client-side complement (flytectl learns to send the IDToken scheme itself). Either change alone is enough for the headless use case; together they cover both stock and updated clients.

Why are the changes needed?

flyteadmin accepts an OIDC ID token from its userAuth.openId provider over gRPC when the token is sent as IDToken <jwt>; that is how the console authenticates (GetAuthenticationInterceptor falls back to GRPCGetIdentityFromIDToken). Several clients can only send Bearer: flytectl's ExternalCommand auth type and flytekit's external_process mode both hardcode it. A user who obtains an ID token out of band, for example through the provider's device authorization grant on a host with no browser, has no way to present it: the token fails validation as an access token and the request is rejected, even though flyteadmin could have verified it.

Flyte's built-in authorization server has no device authorization endpoint, so this is the shortest route to a headless, per-user login without moving a deployment to an external authorization server.

What changes were proposed in this pull request?

  • gRPC: after the bearer token fails access-token validation and no IDToken-scheme token is present, GetAuthenticationInterceptor tries the bearer token as an ID token (GRPCGetIdentityFromBearerIDToken). Verification is the same code as the IDToken scheme: IdentityContextFromIDTokenToken, so go-oidc checks signature, issuer, the userAuth.openId.clientId audience and expiry. The UserInfo-bin metadata handling is shared through a small helper.
  • HTTP: IdentityContextFromRequest does the same for Authorization: Bearer on the REST path, returning both errors when neither validation succeeds.
  • Tokens that fail as both an access token and an ID token are rejected exactly as before; the error message gains the ID token error. Requests with no OidcProvider configured skip the new step.
  • No config changes, no proto changes, no new dependencies.

How was this patch tested?

New bearer_id_token_test.go with an httptest OIDC provider (discovery document plus JWKS for a generated RSA key, ID tokens signed with golang-jwt, both already dependencies):

  • gRPC: ID token sent as Bearer is accepted and yields the token's subject with the all scope; the same token as IDToken still works; a token for another audience is rejected with Unauthenticated; a garbage bearer token is rejected; with no OIDC provider configured the request is rejected as before.
  • HTTP: ID token as Bearer is accepted; wrong audience is rejected.

go test ./auth/ passes, go vet clean, golangci-lint run --new-from-rev=upstream/master ./auth/... reports no new issues.

End to end, before this change, against a flyteadmin on the self authorization server with Dex as userAuth.openId: a stock flytectl configured with ExternalCommand and a command that prints a Dex ID token fails with ... access token err: crypto/rsa: verification error ... Request unauthenticated with IDToken, which is the code path this PR extends. The same token sent as IDToken (via grpcurl and via a flytectl built from #8080) is accepted and get project succeeds as the user.

Labels

  • added

flyteadmin already accepts an ID token from its userAuth OIDC provider over
gRPC when the client sends it with the IDToken scheme, which is how the
console authenticates. Some clients can only send Bearer: flytectl's
ExternalCommand auth type and flytekit's external_process mode hardcode
that scheme. Today such a token fails access-token validation against the
authorization server and the request is rejected, even though flyteadmin
could have verified it as an ID token.

When a Bearer token fails validation as an access token and is not
accompanied by an IDToken-scheme token, try it as an ID token from the
userAuth provider before rejecting the request, on both the gRPC
interceptor and the HTTP path. Verification is identical to the IDToken
scheme: signature, issuer, audience (the userAuth client id) and expiry
through go-oidc. Tokens that fail as both are rejected as before, with the
ID token error added to the message.

This lets a host without a browser log in through the provider's device
flow and hand the ID token to a stock flytectl via ExternalCommand. It is
the server-side complement to flyteorg#8080, which teaches the client to send the
IDToken scheme itself.

Signed-off-by: Santhosh Shanmugham <sshanmugham@waabi.ai>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Empty OIDC client IDs can bypass audience, issuer, and expiry validation, and authentication errors are mislabeled.

Review effort: Balanced
Findings: 2 High severity · 1 Low severity

Open (3)
What changed in this PR

Enables FlyteAdmin to validate OIDC ID tokens presented using the Bearer scheme.

Changes:

  • Adds Bearer-to-ID-token fallback for gRPC and HTTP authentication.
  • Shares ID-token identity extraction logic.
  • Adds OIDC-backed acceptance and rejection tests.
File Description
flyteadmin/​auth/​token.go Adds Bearer ID-token extraction and shared validation.
flyteadmin/​auth/​handlers.go Integrates fallback into gRPC and HTTP authentication.
flyteadmin/​auth/​bearer_id_token_test.go Tests Bearer ID-token validation scenarios.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +450 to +452
if provider := authCtx.OidcProvider(); provider != nil {
identityCtx, idTokenErr := IdentityContextFromIDTokenToken(ctx, tokenStr, authCtx.Options().UserAuth.OpenID.ClientID,
provider, nil)
Comment thread flyteadmin/auth/token.go
Comment on lines +119 to +121
if provider == nil {
return nil, errors.Errorf(ErrJwtValidation, "no OIDC provider configured to validate a bearer token as an ID token")
}
if (isFromHTTP && !authCtx.Options().DisableForHTTP) ||
(!isFromHTTP && !authCtx.Options().DisableForGrpc) {
err := fmt.Errorf("id token err: %w, access token err: %w", fmt.Errorf("access token err: %w", accessTokenErr), idTokenErr)
err := fmt.Errorf("id token err: %w, access token err: %w, bearer id token err: %w", fmt.Errorf("access token err: %w", accessTokenErr), idTokenErr, bearerIDTokenErr)
@codecov

codecov Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 72.41379% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.46%. Comparing base (b2be54c) to head (489a2e0).

Files with missing lines Patch % Lines
flyteadmin/auth/token.go 58.33% 3 Missing and 2 partials ⚠️
flyteadmin/auth/handlers.go 82.35% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #8081      +/-   ##
==========================================
+ Coverage   57.32%   57.46%   +0.14%     
==========================================
  Files         931      931              
  Lines       58315    58341      +26     
==========================================
+ Hits        33427    33527     +100     
+ Misses      21835    21749      -86     
- Partials     3053     3065      +12     
Flag Coverage Δ
unittests-datacatalog 53.62% <ø> (ø)
unittests-flyteadmin 53.73% <72.41%> (+0.48%) ⬆️
unittests-flytecopilot 48.05% <ø> (ø)
unittests-flytectl 64.16% <ø> (+0.04%) ⬆️
unittests-flyteidl 76.63% <ø> (ø)
unittests-flyteplugins 60.59% <ø> (ø)
unittests-flytepropeller 53.84% <ø> (ø)
unittests-flytestdlib 64.41% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants