[PR #6956] [management] Honor AuthUserIDClaim in reverse-proxy SSO callback #30047

Open
opened 2026-08-05 08:09:52 -04:00 by saavagebueno · 0 comments
Owner

Original Pull Request: https://github.com/netbirdio/netbird/pull/6956

State: open
Merged: No


Describe your changes

The reverse-proxy OAuth callback (management/server/http/handlers/proxy/auth.go) extracts the user ID from the OIDC ID token by hardcoding the sub claim, ignoring the configured HttpConfig.AuthUserIDClaim that the rest of management honors.

On Azure AD / Microsoft Entra ID, sub is a pairwise pseudonymous identifier (unique per user+app pair), while NetBird user IDs are keyed by the stable oid claim (AuthUserIDClaim=oid, per the self-hosted Entra guide). The user lookup therefore never matches, and every SSO attempt on a proxied service fails with denied_reason: user_not_found — reverse-proxy SSO is effectively broken for all self-hosted Entra deployments. It goes unnoticed on Keycloak/Auth0/Zitadel/embedded Dex because there sub is the stable user ID.

This PR plumbs AuthUserIDClaim through ProxyOIDCConfig and uses it in extractUserIDFromToken, falling back to sub when unset — zero behavior change for existing deployments that don't set the claim.

  • management/internals/shared/grpc/proxy.go: add UserIDClaim field to ProxyOIDCConfig
  • management/internals/server/boot.go: populate it from HttpConfig.AuthUserIDClaim
  • management/server/http/handlers/proxy/auth.go: extract the configured claim, fallback sub, warn if missing

Fixes #6155 (closed via triage → discussion #6203, unanswered).

Testing

Validated end-to-end on a production self-hosted deployment (v0.74.7 + this patch, Entra ID IdP, AuthUserIDClaim=oid, BYOP reverse-proxy account cluster):

  • Before: full OAuth chain succeeds (authorize → callback → token exchange), then proxy denies with Session validation denied denied_reason: user_not_found (session minted with the pairwise sub).
  • After: callback extracts oid, session matches the account user, SSO-protected service loads normally. IdPs without AuthUserIDClaim configured keep the previous sub behavior via the fallback.

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Summary by CodeRabbit

  • New Features

    • Added support for configuring which OIDC claim identifies a user.
    • The default sub claim remains available when no custom claim is configured.
  • Bug Fixes

    • Improved authentication handling for identity providers that use alternative user identifier claims.
    • Added warnings when the configured user identifier claim is missing or empty.
**Original Pull Request:** https://github.com/netbirdio/netbird/pull/6956 **State:** open **Merged:** No --- ## Describe your changes The reverse-proxy OAuth callback (`management/server/http/handlers/proxy/auth.go`) extracts the user ID from the OIDC ID token by hardcoding the `sub` claim, ignoring the configured `HttpConfig.AuthUserIDClaim` that the rest of management honors. On **Azure AD / Microsoft Entra ID**, `sub` is a pairwise pseudonymous identifier (unique per user+app pair), while NetBird user IDs are keyed by the stable `oid` claim (`AuthUserIDClaim=oid`, per the self-hosted Entra guide). The user lookup therefore never matches, and every SSO attempt on a proxied service fails with `denied_reason: user_not_found` — reverse-proxy SSO is effectively broken for all self-hosted Entra deployments. It goes unnoticed on Keycloak/Auth0/Zitadel/embedded Dex because there `sub` *is* the stable user ID. This PR plumbs `AuthUserIDClaim` through `ProxyOIDCConfig` and uses it in `extractUserIDFromToken`, **falling back to `sub` when unset** — zero behavior change for existing deployments that don't set the claim. - `management/internals/shared/grpc/proxy.go`: add `UserIDClaim` field to `ProxyOIDCConfig` - `management/internals/server/boot.go`: populate it from `HttpConfig.AuthUserIDClaim` - `management/server/http/handlers/proxy/auth.go`: extract the configured claim, fallback `sub`, warn if missing Fixes #6155 (closed via triage → discussion #6203, unanswered). ## Testing Validated end-to-end on a production self-hosted deployment (v0.74.7 + this patch, Entra ID IdP, `AuthUserIDClaim=oid`, BYOP reverse-proxy account cluster): - Before: full OAuth chain succeeds (authorize → callback → token exchange), then proxy denies with `Session validation denied denied_reason: user_not_found` (session minted with the pairwise `sub`). - After: callback extracts `oid`, session matches the account user, SSO-protected service loads normally. IdPs without `AuthUserIDClaim` configured keep the previous `sub` behavior via the fallback. ## Checklist - [x] Is it a bug fix - [ ] Is a typo/documentation fix - [ ] Is a feature enhancement - [ ] It is a refactor - [ ] Created tests that fail without the change (if possible) 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/netbirdio/codesmith/netbird/pr/6956"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1787907451&installation_model_id=427504&pr_number=6956&repository=netbirdio%2Fnetbird&return_to=https%3A%2F%2Fgithub.com%2Fnetbirdio%2Fnetbird%2Fpull%2F6956&signature=7602e02a8c5e268b6056cb5e34a2b4bf389ad0e18167d4967ba7aa4d5bc251ff"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for configuring which OIDC claim identifies a user. * The default `sub` claim remains available when no custom claim is configured. * **Bug Fixes** * Improved authentication handling for identity providers that use alternative user identifier claims. * Added warnings when the configured user identifier claim is missing or empty. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
saavagebueno added the pull-request label 2026-08-05 08:09:52 -04:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#30047