Skip to content

feat(jwt): accept LFX v2 API audience for user JWT verification - #67

Draft
mlehotskylf wants to merge 3 commits into
mainfrom
feat/accept-lfx-v2-api-audience
Draft

feat(jwt): accept LFX v2 API audience for user JWT verification#67
mlehotskylf wants to merge 3 commits into
mainfrom
feat/accept-lfx-v2-api-audience

Conversation

@mlehotskylf

Copy link
Copy Markdown

Why

Per the approved decision on linuxfoundation/lfx-self-serve#1216 (condition 1), LFX Self Serve must build the "My CLAs" identity list server-side via the lfx.auth-service.user_identity.list NATS RPC, passing the session user's own access token so the auth service verifies the JWT and extracts sub from verified claims.

That flow doesn't work today — verified empirically in dev:

  • The service verifies JWTs against the Auth0 Management API audience only; SS session tokens (and CTE impersonation tokens) carry the LFX v2 API audience and are rejected: {"success":false,"error":"invalid audience"}.
  • Independently, MetadataLookup stores the verified JWT as user.Token, which GetUser/SearchUser then reuse as the bearer for Auth0 Management API calls — where Auth0 itself would reject a non-management-audience token.

Details and evidence: linuxfoundation/lfx-self-serve#1216 (comment)

What

  1. Accept the LFX v2 API audience for JWT verification. NewJWTVerificationConfig builds an audience allow-list: the Management API audience plus, when AUTH0_LFX_V2_API_AUDIENCE is set (it already is in all deployments, for impersonation), that audience too.
  2. Never forward non-management tokens to the Management API. In MetadataLookup, user.Token is populated only when the verified token carries the Management API audience. Otherwise the verified sub is used with the service's own M2M credentials (read:users) for read lookups, and write flows fail closed:
    • LinkIdentityToUser / UnlinkIdentityFromUser reject an empty user token and never use M2M credentials (existing behavior).
    • UpdateUser re-verifies user.Token itself with the update scope (existing behavior).
  3. Validate against all aud values, not just the first — Auth0 access tokens commonly carry [api-audience, …/userinfo].

No behavior change for existing callers: all other services pass usernames/emails/subs (non-JWT path, untouched), and currently-accepted management-audience JWTs (SS Flow C profile tokens) verify and forward exactly as before.

Security note for reviewers

Accepting the LFX v2 API audience widens who can pass JWT verification on read subjects, but the response is always scoped to the token's own verified sub, reads go through the same M2M credentials already used for the non-JWT lookup paths, and write subjects still require the user's own management-scoped token. Please double-check the read/write split holds in your review.

cc @emsearcy — this implements condition 1 of your linuxfoundation/lfx-self-serve#1216 recommendation; flagging in case you intended a different token for SS to pass.

Testing

  • New unit tests: audience allow-list (ExpectedAudiences), multi-aud tokens, and MetadataLookup token retention (management kept / LFX v2 verified-but-not-forwarded / unknown audience rejected).
  • go test ./..., gofmt, go vet all clean.

🤖 Generated with Claude Code

User-facing access tokens and impersonation tokens carry the LFX v2 API
audience, not the Auth0 Management API audience, so MetadataLookup's JWT
path rejected them with 'invalid audience' (verified in dev). Accept the
audience from AUTH0_LFX_V2_API_AUDIENCE as an additional valid audience.

Tokens verified via a non-management audience are never forwarded to the
Auth0 Management API: user.Token stays empty so read lookups fall back
to the service's M2M credentials, while write flows (which require the
user's own management-scoped token) fail closed.

Also validate the audience against all 'aud' values of the token rather
than only the first one.

Needed for SS 'My CLAs' identity resolution per
linuxfoundation/lfx-self-serve#1216 (condition 1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Michal Lehotsky <mlehotsky@linuxfoundation.org>
Copilot AI review requested due to automatic review settings August 2, 2026 16:44
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: de7256a4-7999-44b1-8ce5-6d0750398795

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

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.

Pull request overview

Adds LFX v2 API audience support for read-only JWT identity lookups while retaining Management API token handling.

Changes:

  • Supports multiple allowed and token audiences.
  • Uses M2M credentials for non-management-audience reads.
  • Adds audience validation and token-retention tests.

A security issue remains: the expanded audience policy also applies to write authorization paths.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/jwt/parser.go Adds multi-audience parsing and validation.
pkg/jwt/parser_test.go Tests audience allow-lists and multi-audience tokens.
internal/infrastructure/auth0/user.go Retains only Management API tokens for lookups.
internal/infrastructure/auth0/user_test.go Tests audience-based token retention.
internal/infrastructure/auth0/jwt_parser.go Configures the LFX v2 audience allow-list.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/infrastructure/auth0/jwt_parser.go
mlehotskylf and others added 2 commits August 2, 2026 12:20
Scope-gated JWTVerify calls back the write-authorizing paths
(ChangePassword, SetPrimaryEmail, add_alias). The expanded audience
allow-list accepts the LFX v2 API audience for read-only lookups, but
required scopes are Auth0 Management API scopes and only meaningful on
Management-audience tokens. Clear ExpectedAudiences when a required
scope is present so a broader-audience token carrying an
identically named scope can never authorize a write.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Michal Lehotsky <mlehotsky@linuxfoundation.org>
Copilot AI review requested due to automatic review settings August 2, 2026 19:31

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.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants