skip to Main Content

We’re implementing a custom identity provider for Azure AD B2C, using OpenID protocol option, as a generic OpenID Connect.

Everything works as expected until it’s time to post the response back to Azure AD B2C using the redirect URI provided. I’ve found documentation regarding expected structure of this response URL, and what we see in the documentation is identical to what Azure AD B2C specifies when it issues the authentication sequence.

Configured values:
Response type: code
Response mode: form_post
User ID claim: sub
Display name claim: name

When the custom identity provider GETs or POSTs authentication response (code) back to https://REDACTED.b2clogin.com/REDACTED.onmicrosoft.com/oauth2/authresp, the Azure B2C returns 404.

Note that this is not 400, not 401, not 403, not 5xx. It is precisely 404 (not found), with a basic text (non-html) content saying resource not found. This response looks to me very much like a misconfigured API management layer on Azure side, hitting a wrong internal URL.

We’re expecting that the URL https://REDACTED.b2clogin.com/REDACTED.onmicrosoft.com/oauth2/authresp actually works. It looks like what the expected Azure AD B2C response endpoint is from documentation, and it is also exactly what Azure AD B2C itself specifies when initiating the OpenID sequence with our custom identity provider web application.

So far we were unable to find the root cause, nor even any useful input beyond raw network request logs (case with Microsoft support was open since 2023-01-23). The last resort could be re-creating the B2C tenant, since this feature seems to work for other people, but that would require migration and significant down time on our end.

SOLUTION: The response to AD B2C authresp endpoint was missing ‘nonce’ claim (in the id_token payload), and ‘state’ parameter in the HTTP request. Both values are supplied by AD B2C when initiating authorization. As soon as custom identity provider started properly adding those two values, error 404 went away.

2

Answers


  1. I tried to reproduce the scenario in my environment:
    Make sure the endpoint to which I requested the authorization url

    It includes policy and with
    redirect URI= https://kavyasarabojub2c.b2clogin.com/kavyasarabojub2c.onmicrosoft.com/oauth2/authresp

    User Flow is of SignupSignin and not just Signin

    enter image description here

    Make sure to include all the required api permissions , importantly make sure to include openid , profile

    enter image description here

    I Configure idp such that , userId is mapped to oid.

    enter image description here

    The authorization url must have the policy included .

    Here I have B2C_1_SignupSignin policy set for the User flow.

    redirect URI= https://kavyasarabojub2c.b2clogin.com/kavyasarabojub2c.onmicrosoft.com/oauth2/authresp

    Auth url:

    https://kavyasarabojub2c.b2clogin.com/kavyasarabojub2c.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_newSignupSignin&client_id=xxx&nonce=defaultNonce&redirect_uri=https%3A%2F%2Fxxxb2c.b2clogin.com%2Fxxxb2c.onmicrosoft.com%2Foauth2%2Fauthresp&scope=openid&response_type=id_token&prompt=login

    When profile scope is not given I got bad request

    enter image description here

    But when openid and profile along with Directory.Read.All api permissions are included, the request run successfully.

    Note: metadata url must be : https://login.microsoftonline.com/<tenantId>/v2.0/.well-known/openid-configuration

    enter image description here

    Successfully logged in and got the token containing idp_access_token
    enter image description here

    enter image description here

    Identity provider access token , decoded and got the user claims:
    enter image description here

    Login or Signup to reply.
  2. Response should include supplied nonce as a claim inside the id_token payload, and supplied state as HTTP request parameter or query string

    https://openid.net/specs/openid-connect-basic-1_0.html

    I had the same issue (a 404 error as a result of the /authresp POST from my custom OIDC IdP back to Azure AD B2C using the redirect URI Azure AD B2C had just provided as a query parameter on the /authorize request to my IdP: redirect_uri=https://mytenant.b2login.com/mytenant.onmicrosoft.com/oauth2/authresp

    In my case (using an implicit flow), it was about properly handling the "nonce" query parameter on the inbound /authorize request (from Azure AD B2C to my IdP) by ensuring the generated id_token it returned included the nonce as a claim.

    In your case (using an authorization code flow…and assuming you also return an id_token based on the "sub" and "name" claims you’re returning), your /token endpoint needs to include the nonce inside the id_token…so propagate the nonce (and state) as query parameters along to your /token endpoint via the /authorize to /token redirect method you use.

    If a federated IdP doesn’t include the nonce as a claim inside the id_token payload that it returns, Azure AD B2C will return a 404 error from the /authresp request.

    I don’t know why Microsoft chose to return a 404 instead of a more informative "nonce invalid" error message, or at least, a 400 error…perhaps it’s for the same security reason a login form doesn’t precisely tell you when your password is invalid.

    In the OpenID Connect specification, the nonce description (under IDToken) states (bolding is my doing):

    String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. If present in the ID Token, Clients MUST verify that the nonce Claim Value is equal to the value of the nonce parameter sent in the Authentication Request. If present in the Authentication Request, Authorization Servers MUST include a nonce Claim in the ID Token with the Claim Value being the nonce value sent in the Authentication Request. Authorization Servers SHOULD perform no other processing on nonce values used. The nonce value is a case sensitive string.

    Although the spec indicates a nonce is optional, Microsoft is following best practices by supplying one…and since Azure AD B2C (as the Authorization Server) gets the id_token from the IdP, it requires a federated OIDC IdP to play by the same rule.

    In case this helps others, my custom IdP’s /.well-known/openid-configuration endpoint returns:

     {
      "authorization_endpoint": "https://myidp.azurewebsites.net/oauth2/authorize",
      "authorization_response_iss_parameter_supported": true,
      "claims_parameter_supported": false,
      "claims_supported": [
        "aud",
        "idp",
        "iss",
        "iat",
        "exp",
        "nonce",
        "s-hash",
        "sid",
        "sub",
        "auth_time",
        "email",
        "family_name",
        "given_name",
        "locale",
        "name",
        "updated_at",
        "user_id"
      ],
      "claim_types_supported": ["normal"],
      "grant_types_supported": ["implicit"],
      "id_token_signing_alg_values_supported": ["RS256"],
      "issuer": "https://myidp.azurewebsites.net",
      "jwks_uri": "https://myidp.azurewebsites.net/oauth2/jwks",
      "response_modes_supported": ["form_post"],
      "response_types_supported": ["id_token"],
      "scopes_supported": ["openid"]
    }
    

    (Yes, my IdP runs on an Azure App server…but, "myidp" isn’t my real tenant name.)

    p.s. Currently, my IdP is used exclusively in a federation with AzureAD B2C (which acts as the Authorization Server for my client application via the MSAL library), so my IdP simply supports just an implicit flow and three endpoints (/.well-known/openid-configuration, /jwks and /authorize). If it were a general purpose IdP, or allowed direct client requests, it would support other flows (e.g. an authorization code flow), additional scopes (beyond "openid"…e.g. "profile") and additional endpoints (e.g. /token and /userinfo). However, regardless of flow, as long as an id_token is returned, it needs to include the nonce in its payload.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search