Reputation: 740
I have a web API attempting to get set of access and refresh tokens for a B2C user. User sign-in is done through a configured "Social identity provider".
The API receives authorization code. When exchanging code for the tokens, Azure AD B2C tenant's endpoint endpoint returns invalid_grant
error.
I have looked at the other answers I've found on the site. The issue still remains. Pointers are much appreciated.
Details as follows.
Sign-up and sign-in profiles issue claims for
Error from token endpoint:
{
"error": "invalid_grant",
"error_description": "AADSTS70000: Transmission data parser failure: Authorization Code is malformed or invalid. [...]",
"error_codes": [
70000
],
[...]
}
Authorization request looks as follows:
AUTHORIZATION_ENDPOINT = 'https://login.microsoftonline.com/<tenant_id>/oauth2/v2.0/authorize'
authorization_url = f'{AUTHORIZATION_ENDPOINT}' \
f'?client_id={CLIENT_ID}' \
f'&response_type=code' \
f'&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fcode' \
f'&scope=openid offline_access' \
f'&nonce=hellobob' \
f'&p=B2C_1_<profile>'
Upon user authorization, authorization code is POST
ed by API to token endpoint. Payload is represented as a Python dictionary.
TOKEN_ENDPOINT = 'https://login.microsoftonline.com/<tenant_id>/oauth2/v2.0/token'
payload = {
'p': 'B2C_1_<profile>',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'code': code,
'grant_type': 'authorization_code',
'redirect_uri': 'http://localhost:8000/code',
'scope': 'openid offline_access'
}
response = requests.post(TOKEN_ENDPOINT, data=payload)
Upvotes: 1
Views: 3286
Reputation: 740
The URL to the token endpoint was incorrect. Authorization and token endpoint URLs needs to contain the B2C profile as part of their query parameters, e.g. https://login.microsoftonline.com/<tenant_id>/oauth2/v2.0/token?p=<B2C_profile>
.
Alternatively, you can use the following URLs to authorization and token endpoints respectively:
https://login.microsoftonline.com/te/<tenant>.onmicrosoft.com/<B2C_profile>/oauth2/v2.0/authorize
https://login.microsoftonline.com/te/<tenant>.onmicrosoft.com/<B2C_profile>/oauth2/v2.0/token
Value of B2C_profile
is in lower case.
OpenID discovery document is available at https://login.microsoftonline.com/te/<tenant>.onmicrosoft.com/<B2C_profile>/v2.0/.well-known/openid-configuration
.
Note that the OpenID provider configuration document lists the underlying Azure AD as the token issuer, making it difficult to determine whether a token originates from Azure AD or B2C. However, B2C tokens seem to include a tfp
-claim referring to the policy name being used.
In addition, B2C uses different signing keys than the claimed token issuer. Make sure you use the B2C keys when validating tokens!
Upvotes: 1
Reputation: 3237
This error generally means the auth code you've gotten is not meant for tokens on the specified endpoint. This can happen from misconfiguring the auth endpoints, registering the app in the wrong spot, or a malformed request. One thing to callout is most B2C errors are in the form of aadb2cxxxxx
rather than the traditional Azure AD error format of aadstsxxxxx
.
First thing to check with this error is your auth endpoints. From the snippets above, both look good.
Next thing is to make sure you're using the correct library to obtain the authorization code. You haven't shown the code on your client, but if it's using the ADAL library or v1.0 endpoints, your auth code will not be redeemable on the /v2.0/ endpoints.
I've also seen this happen when an app is registered in the incorrect blade within the Azure Portal. Make sure you registered an Azure AD B2C application rather than a plain Azure AD app.
If you've done this, I recommend trying 2 things:
Use a test B2C application from one of the code samples rather than your app registration and see if it works. If it does, you know you have a registration issue. This registration guide may help diagnose.
Do the request by hand using your app registration (rather than in code). This will help you understand if it's a code issue. Construct the request and use Curl or Postman, then exchange the code. The easy alternative is to plug in your configs into a sample.
Upvotes: 1