Skip to content

feat(custom-oauth): preserve non-standard IdP claims in identity_data#2520

Open
cemalkilic wants to merge 1 commit into
masterfrom
cemal/feat-auth-1194-custom-claims
Open

feat(custom-oauth): preserve non-standard IdP claims in identity_data#2520
cemalkilic wants to merge 1 commit into
masterfrom
cemal/feat-auth-1194-custom-claims

Conversation

@cemalkilic
Copy link
Copy Markdown
Contributor

Summary

  • Custom OAuth/OIDC providers now preserve non-standard IdP claims (groups, roles, org_id, tenant_id, …) in auth.identities.identity_data and auth.users.raw_user_meta_data under the custom_claims key. Previously these were silently dropped by the typed Claims decode.
  • Scoped to CustomOAuthProvider and CustomOIDCProvider. Built-in providers (Google, Apple, GitHub, Azure, …) are unchanged.
  • No schema migration, existing JSONB columns already support this.

Why

  • Customers flagged that userinfo claims they rely on (org IDs, tenant IDs, group / role lists from their custom OIDC IdPs) were not appearing in their Postgres auth schema. They want to use these claims transactionally, reject sign-in if a required claim is missing, and keep that data inside Supabase rather than re-fetching out-of-band. The IdP already returns the data and we already verify it during callback; we just weren't persisting it.

@cemalkilic cemalkilic requested a review from a team as a code owner May 5, 2026 21:59
Copy link
Copy Markdown
Contributor

@fadymak fadymak left a comment

Choose a reason for hiding this comment

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

Thanks @cemalkilic — I left a few comments 👀 My hesitation is around persisting all fields to identity data as opposed to having some allow list that can be configured per-provider which feels like the cleaner/safer approach.

Comment on lines +268 to +270
if err := idTokenObj.Claims(&raw); err == nil {
captureCustomClaims(raw, userData.Metadata)
}
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.

I believe this would cause us to re-add any claims we explicitly excluded for certain providers (e.g.: removeAzureClaimsFromCustomClaims):

// removeAzureClaimsFromCustomClaims contains the list of claims to be removed
// from the CustomClaims map. See:
// https://learn.microsoft.com/en-us/azure/active-directory/develop/id-token-claims-reference
var removeAzureClaimsFromCustomClaims = []string{
"aud",
"iss",
"iat",
"nbf",
"exp",
"c_hash",
"at_hash",
"aio",
"nonce",
"rh",
"uti",
"jti",
"ver",
"sub",
"name",
"preferred_username",
}

Comment on lines +15 to +19
// standardClaimKeys is the set of JSON keys handled by the typed Claims
// struct (OIDC standard claims plus our typed extensions, and the
// custom_claims sink itself). Derived from the struct's json tags so it
// can't drift when Claims changes.
var standardClaimKeys = jsonKeysOf(reflect.TypeOf(Claims{}))
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.

My concern is that Claims doesn't capture actual standard claims (including SB-specific ones), e.g.: nbf, nonce, etc... which would end up in the custom claims and it doesn't feel like the right place, nor should they be persisted IMO

@IdrisCelik
Copy link
Copy Markdown

IdrisCelik commented May 21, 2026

Thanks again @cemalkilic , I wanted to add that we were running into this problem as well, so it's great to see this addressed.

Thanks @cemalkilic — I left a few comments 👀 My hesitation is around persisting all fields to identity data as opposed to having some allow list that can be configured per-provider which feels like the cleaner/safer approach.

-- @fadymak

I understand this hesitation, we would still love to see this as is or with a allow list (or even better claims mapping like with saml attribute mapping) that can be set by us by for example using the createProvider method, this because we are using a standardized IdP proxy for our market and they along with many others use non standard claims like mail, sn, nlEduPersonProfileId which we need in our before insert on auth.users trigger.

Hitting the userinfo endpoint ourselves with the token would mean we lose transactional integrity which is a big reason we wanted to go with Supabase auth.

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.

3 participants