-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Preflight checklist
- I could not find a solution in the existing issues, FAQ, or Ory documentation
- I agree to follow the Ory Community Code of Conduct
- I have read and am following this repository's contribution guidelines
- This feature request has not been reported before
Problem
Azure AD B2C violates OIDC Discovery spec §4.3: the issuer in the discovery document does not match the URL used to fetch it.
Discovery URL: https://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/<policy>/v2.0/.well-known/openid-configuration
Issuer returned: https://<tenant>.b2clogin.com/<tenant-id>/v2.0/
The discovery URL must include the B2C policy name, but the returned issuer uses the tenant GUID and omits the policy. This mismatch is unavoidable — all B2C discovery URL variants (tenant-name, tenant-id, /tfp/ prefix) return the same GUID-based issuer.
Kratos (via go-oidc) strictly validates issuer == discovery URL and rejects the provider:
oidc: issuer did not match the issuer returned by provider,
expected "https://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/<policy>/v2.0"
got "https://<tenant>.b2clogin.com/<tenant-id>/v2.0/"
Why existing provider types don't work
| Provider | Behavior | Result |
|---|---|---|
microsoft |
Hardcodes login.microsoftonline.com/{tenant} |
Redirects to generic MS login, not B2C custom flow |
generic + issuer_url |
OIDC Discovery with strict issuer validation | Issuer mismatch error |
B2C-side mitigation
Azure Portal has a "Token compatibility > Issuer (iss) claim" setting, but the tfp issuer format may only be available with B2C custom policies, not standard user flows. This places the burden on the customer to migrate from user flows to custom policies — a non-trivial effort.
Proposed solution
Add a use_oidc_discovery_issuer boolean field to the generic OIDC provider configuration. When true, use go-oidc's InsecureIssuerURLContext to allow the discovery URL to differ from the issuer.
Ory's own go-oidc fork (github.com/ory/go-oidc/v3) already has InsecureIssuerURLContext — this change just wires it into the generic provider.
Key points:
- Opt-in — no behavior change for existing configs (defaults to
false) - ID token issuer validation still occurs — tokens are verified against the issuer from the discovery document. Only the spec requirement that discovery URL == issuer is relaxed.
- ~5 line code change + schema update + tests
- @aeneasr (kind of)endorsed
InsecureIssuerURLContextas the correct approach in April 2022
Configuration example
{
"id": "azure-b2c",
"provider": "generic",
"client_id": "...",
"client_secret": "...",
"issuer_url": "https://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/<policy>/v2.0",
"use_oidc_discovery_issuer": true,
"scope": ["openid"],
"claims_source": "id_token",
"mapper_url": "base64://..."
}Related issues
- Microsoft B2C OIDC provider is using invalid
issvalue #2404 — Original request for InsecureIssuerURLContext support (2022) - Workarounds for Microsoft Entra non-compliance to the OIDC spec #4005 — Microsoft Entra non-compliance (stale, still open)
- Unable to initialize OpenID Connect Provider: oidc: issuer did not match the issuer returned by provider, expected "https://facebook.com" got "https://www.facebook.com" #1686 — Facebook issuer mismatch (solved via dedicated provider)
Implementation
PR ready: #4537
Changes
selfservice/strategy/oidc/provider_config.go— addUseOIDCDiscoveryIssuerfield toConfigurationselfservice/strategy/oidc/provider_generic_oidc.go— useInsecureIssuerURLContextinprovider()when flag is setembedx/config.schema.json— adduse_oidc_discovery_issuerpropertyselfservice/strategy/oidc/provider_generic_test.go— 3 test cases covering: mismatch rejection (default), mismatch acceptance (flag=true), endpoint discovery verification
Tested end-to-end against a real Azure AD B2C tenant with standard user flows.