From 602025255d002312f309952aeeae51106fde8dbd Mon Sep 17 00:00:00 2001 From: Ahmed Refaey Date: Tue, 21 Jul 2026 15:49:53 +0100 Subject: [PATCH] docs(v2): document OIDC discovery_url and claims_mapping; add Azure AD B2C guide Add documentation for the new per-provider OIDC options: - discovery_url: fetch the discovery document from a URL that differs from the token issuer (needed for Azure AD B2C, whose issuer is a tenant GUID while discovery is served from a policy-specific tenant-domain URL). - claims_mapping: JSON Pointer map for extracting user attributes from non-standard claims (e.g. B2C's emails array). Also adds a Login with Azure AD B2C guide covering setup and common pitfalls, updates the config reference table, and registers the guide in the nav. Signed-off-by: Ahmed Refaey Co-authored-by: Cursor --- .../styles/Flipt/spelling-exceptions.txt | 2 + docs/docs.json | 1 + docs/v2/configuration/authentication.mdx | 61 ++++++++ docs/v2/configuration/overview.mdx | 2 + .../login-with-azure-ad-b2c.mdx | 137 ++++++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 docs/v2/guides/operations/authentication/login-with-azure-ad-b2c.mdx diff --git a/docs/.vale/styles/Flipt/spelling-exceptions.txt b/docs/.vale/styles/Flipt/spelling-exceptions.txt index 5c1fb6c..607f32a 100644 --- a/docs/.vale/styles/Flipt/spelling-exceptions.txt +++ b/docs/.vale/styles/Flipt/spelling-exceptions.txt @@ -4,6 +4,7 @@ approvers auditable avro azblob +b2c backoff boolean caddy @@ -33,6 +34,7 @@ gitops googlecloud grafana grpc +guid hostname http httplug diff --git a/docs/docs.json b/docs/docs.json index db4af12..cebddc3 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -144,6 +144,7 @@ "group": "Authentication", "pages": [ "v2/guides/operations/authentication/login-with-github", + "v2/guides/operations/authentication/login-with-azure-ad-b2c", "v2/guides/operations/authentication/connecting-applications" ] }, diff --git a/docs/v2/configuration/authentication.mdx b/docs/v2/configuration/authentication.mdx index 6f6f8d1..5eb0c71 100644 --- a/docs/v2/configuration/authentication.mdx +++ b/docs/v2/configuration/authentication.mdx @@ -301,6 +301,7 @@ Flipt v2 has been tested with each of the following providers: - [Dex](https://dexidp.io/docs/openid-connect/) - [Okta](https://developer.okta.com/docs/concepts/oauth-openid/#oauth-2-0) - [AzureAD](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc) +- [Azure AD B2C](https://learn.microsoft.com/en-us/azure/active-directory-b2c/openid-connect) (see the [Login with Azure AD B2C](/v2/guides/operations/authentication/login-with-azure-ad-b2c) guide) - [Keycloak](https://www.keycloak.org/docs/latest/server_admin/index.html#_identity_broker_oidc) Though the intention is that it should work with all OIDC providers, these are just the handful the Flipt team has validated. @@ -433,6 +434,66 @@ authentication: If not specified, the default is an empty map. +#### Discovery URL + +By default, Flipt fetches the OIDC discovery document (`.well-known/openid-configuration`) from the `issuer_url`, and, as required by the OIDC specification, verifies that the `issuer` reported in that document matches the `issuer_url`. + +Some providers serve their discovery document from a URL that differs from the issuer they report in that document and in issued tokens. The most common example is [Azure AD B2C](/v2/guides/operations/authentication/login-with-azure-ad-b2c), whose discovery document is served from a policy-specific URL (using the tenant domain) while the `issuer` it reports is the tenant GUID. + +For these providers, set `discovery_url` to the URL Flipt should fetch the discovery document from, and set `issuer_url` to the issuer reported in that document (which matches the `iss` claim in issued tokens). When `discovery_url` is set, Flipt fetches discovery from it while still verifying tokens against `issuer_url`. + +```yaml config.yaml +authentication: + required: true + methods: + oidc: + enabled: true + providers: + some_provider: + issuer_url: "https://tenant.b2clogin.com//v2.0/" + discovery_url: "https://tenant.b2clogin.com/tenant.onmicrosoft.com//v2.0" + client_id: "some_client_identifier" + client_secret: "some_client_secret_credential" + redirect_address: "https://your.flipt.instance.url.com" +``` + + + `issuer_url` is **required** when `discovery_url` is set, because token + verification is pinned to `issuer_url`. + + +If not specified, `discovery_url` defaults to `issuer_url` and the standard OIDC issuer check applies. + +#### Claims Mapping + +By default, Flipt reads user attributes from the standard OIDC claim names in the ID token (`email`, `name`, `picture`, and `sub`). Some providers return these attributes under different claim names. For example, [Azure AD B2C](/v2/guides/operations/authentication/login-with-azure-ad-b2c) returns the email address in an `emails` array rather than a string `email` claim. + +Use the `claims_mapping` option to map Flipt's user attributes to [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) expressions that locate those values within the token claims. Mapped values take precedence over the standard claims. + +```yaml config.yaml +authentication: + required: true + methods: + oidc: + enabled: true + providers: + some_provider: + issuer_url: "https://some.oidc.issuer.com" + client_id: "some_client_identifier" + client_secret: "some_client_secret_credential" + redirect_address: "https://your.flipt.instance.url.com" + claims_mapping: + email: "/emails/0" # e.g. Azure AD B2C returns email in an array +``` + + + Only the attribute names `email`, `name`, `picture`, and `sub` are supported. + Invalid JSON Pointer expressions or paths that don't exist in the claims are + silently ignored. + + +This is particularly important when using [`email_matches`](#email-matches) with a provider that doesn't emit a string `email` claim: without mapping the email onto the `email` attribute, Flipt has no email to match against and rejects the request. + #### Self-Signed Certificates If your OIDC provider uses self-signed or internal CA certificates (common with self-hosted Keycloak, Dex, or corporate identity providers), Flipt will reject the TLS connection with an error like: diff --git a/docs/v2/configuration/overview.mdx b/docs/v2/configuration/overview.mdx index 138dc05..06192a2 100644 --- a/docs/v2/configuration/overview.mdx +++ b/docs/v2/configuration/overview.mdx @@ -353,6 +353,8 @@ Authentication configuration controls how users and systems authenticate with Fl | authentication.methods.oidc.providers.[provider].algorithms | List of accepted ID token signing algorithms | ["RS256"] | v2.6.0 | | authentication.methods.oidc.providers.[provider].fetch_extra_user_info | Fetch additional claims from the provider's UserInfo endpoint | false | v2.6.0 | | authentication.methods.oidc.providers.[provider].authorize_parameters | Extra query parameters to append to the provider authorize URL | {} | v2.11.0 | +| authentication.methods.oidc.providers.[provider].discovery_url | Override URL for the OIDC discovery document (e.g. Azure AD B2C) | | v2.12.0 | +| authentication.methods.oidc.providers.[provider].claims_mapping | JSON Pointer map for extracting user attributes from claims | {} | v2.12.0 | | authentication.methods.oidc.email_matches | List of email addresses (regex) of users allowed to authenticate | | v2.0.0 | #### Authentication Methods: GitHub diff --git a/docs/v2/guides/operations/authentication/login-with-azure-ad-b2c.mdx b/docs/v2/guides/operations/authentication/login-with-azure-ad-b2c.mdx new file mode 100644 index 0000000..357083f --- /dev/null +++ b/docs/v2/guides/operations/authentication/login-with-azure-ad-b2c.mdx @@ -0,0 +1,137 @@ +--- +title: Login with Azure AD B2C +description: Configuring Flipt v2 to enable login with Azure Active Directory B2C via OIDC +--- + +This guide walks through configuring Flipt v2 to enable login with [Azure Active Directory B2C](https://learn.microsoft.com/en-us/azure/active-directory-b2c/) (Azure AD B2C) using the [OIDC authentication method](/v2/configuration/authentication#oidc). + +Azure AD B2C is a standards-compliant OpenID Connect provider, so Flipt talks to it through the generic `oidc` method. However, B2C has two behaviors that require extra configuration compared to most providers: + +- Its OIDC discovery document is served from a **policy-specific URL** (using your tenant domain), while the `issuer` it reports is the **tenant GUID**. This requires the [`discovery_url`](/v2/configuration/authentication#discovery-url) option. +- It returns the email address in an **`emails` array** rather than a string `email` claim. This requires the [`claims_mapping`](/v2/configuration/authentication#claims-mapping) option. + +## Prerequisites + +- [Docker](https://www.docker.com/) +- An [Azure AD B2C tenant](https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant) +- A B2C user flow or custom policy (for example, a sign-up/sign-in flow such as `B2C_1_signupsignin`) + +## Register an application in Azure AD B2C + +1. In the [Azure portal](https://portal.azure.com/), switch to your Azure AD B2C tenant and open **App registrations**. + +2. Select **New registration** and give the application a meaningful name, such as "Flipt". + +3. Under **Redirect URI**, select **Web** and enter your Flipt callback URL: + + `https://your.flipt.instance.url.com/auth/v1/method/oidc/azure/callback` + + + The `azure` segment must match the provider name you use in your Flipt + configuration. This guide uses `azure`. + + +4. After creating the registration, open **Certificates & secrets**, select **New client secret**, and copy the generated value. You'll use this as the `client_secret`. + +5. Copy the **Application (client) ID** from the app's **Overview** page. You'll use this as the `client_id`. + +## Find your issuer and discovery URLs + +Flipt needs two related URLs that B2C keeps separate. + +Fetch your policy's discovery document. The metadata path uses your tenant domain and policy name, and does **not** include the `oauth2` segment: + +```bash +curl https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1_signupsignin/v2.0/.well-known/openid-configuration +``` + +From the JSON response: + +- The value of the `issuer` field is your **`issuer_url`**. It uses the tenant GUID, for example `https://yourtenant.b2clogin.com/00000000-0000-0000-0000-000000000000/v2.0/`. Copy it exactly, including the trailing slash. +- The URL you fetched, without the `.well-known/openid-configuration` suffix, is your **`discovery_url`**, for example `https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1_signupsignin/v2.0`. + + + Don't use the `oauth2/v2.0/authorize` or `oauth2/v2.0/token` endpoints as your + `issuer_url` or `discovery_url`. Those are the authorize and token endpoints; + the discovery document lives at the `/v2.0/.well-known/openid-configuration` + path **without** the `oauth2` segment. + + +## Running Flipt + +### 1. Define a Flipt `config.yml` + +Configure the `oidc` method with a provider named `azure`. Set `issuer_url` and `discovery_url` from the previous step, and map the email claim from the B2C `emails` array. + +```yaml config.yml +authentication: + required: true + session: + domain: "your.flipt.instance.url.com" + secure: true + methods: + oidc: + enabled: true + email_matches: + - ^.*@yourorg.com$ + providers: + azure: + issuer_url: "https://yourtenant.b2clogin.com/00000000-0000-0000-0000-000000000000/v2.0/" + discovery_url: "https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1_signupsignin/v2.0" + client_id: ${env:FLIPT_AZURE_CLIENT_ID} + client_secret: ${env:FLIPT_AZURE_CLIENT_SECRET} + redirect_address: "https://your.flipt.instance.url.com" + use_pkce: true + claims_mapping: + email: "/emails/0" +``` + +A few notes specific to Azure AD B2C: + +- `claims_mapping` maps Flipt's `email` attribute to the first entry of the B2C `emails` array. This is required for [`email_matches`](/v2/configuration/authentication#email-matches) to work, since B2C doesn't emit a string `email` claim. +- Don't request `email` or `profile` in `scopes`. B2C only advertises the `openid` scope (which Flipt requests automatically); requesting others can cause the authorize request to fail. Email and name claims are delivered through your user flow's application-claims configuration. +- Don't enable `fetch_extra_user_info`. B2C doesn't expose a UserInfo endpoint, so enabling it causes the login callback to fail. All claims are already present in the ID token. + +### 2. Run Flipt as a Docker container + +```bash +docker run -it --rm \ + -p 8080:8080 \ + -p 9000:9000 \ + -e FLIPT_AZURE_CLIENT_ID=your-client-id \ + -e FLIPT_AZURE_CLIENT_SECRET=your-client-secret \ + -v $HOME/flipt:/var/opt/flipt \ + -v "$(pwd)/config.yml:/etc/flipt/config/default.yml" \ + docker.flipt.io/flipt/flipt:v2 +``` + +### 3. Navigate to the Flipt UI + +Open your Flipt instance in a browser. A "Login with Azure" option is presented. Selecting it redirects you to your B2C sign-up/sign-in experience, and after authenticating you're returned to the Flipt dashboard. + +## Troubleshooting + +**`NewProvider: unable to create provider: 404 Not Found`** + +Flipt couldn't fetch the discovery document. This usually means the URL includes the `oauth2` segment, or the policy name is wrong. The discovery document is at `...//v2.0/.well-known/openid-configuration` (no `oauth2`). Verify the URL with `curl` as shown [above](#find-your-issuer-and-discovery-urls). + +**`oidc: issuer did not match the issuer returned by provider`** + +The `issuer_url` doesn't match the `issuer` reported by the discovery document. Set `discovery_url` to the policy URL you fetch discovery from, and set `issuer_url` to the exact `issuer` value from that document (the tenant-GUID form, including the trailing slash). + +**Login succeeds but every request is rejected** + +If you use `email_matches` but haven't mapped the email claim, Flipt has no email to match and rejects requests. Add `claims_mapping` with `email: "/emails/0"` as shown above. + +## Conclusion + +This guide showed how to configure Flipt v2 to authenticate with Azure AD B2C, including the `discovery_url` and `claims_mapping` options that B2C requires. + +If you have any questions or feedback, please reach out to the Flipt team on [Discord](https://discord.gg/flipt) or [GitHub Discussions](https://github.com/flipt-io/flipt/discussions). + +--- + +**References:** + +- [Flipt v2 Authentication Configuration](/v2/configuration/authentication) +- [Azure AD B2C OpenID Connect overview](https://learn.microsoft.com/en-us/azure/active-directory-b2c/openid-connect)