I am trying to do an Azure AD Graph API REST API call to get the currently logged in user information. However, the HTTP GET call to https://graph.windows.net/me?api-version=1.6 fails always with the response 401 Unauthorized. I have registered an App in Azure AD and have the below API Permissions configured:
The call to authorize endpoint is shown below:
HTTP GET https://{my tenant}.b2clogin.com/{my tenant}.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_signinsignup&client_id={my app id}&nonce=defaultNonce&redirect_uri=https://localhost:44351/Login/LoginResponse&scope=https://graph.windows.net/Directory.AccessAsUser.All https://graph.windows.net/User.Read&response_type=code&prompt=login
The call to token endpoint is as shown below:
HTTP POST to URL: https://{my tenant}.b2clogin.com/{my tenant}.onmicrosoft.com/B2C_1_signinsignup/oauth2/v2.0/token Content type: application/x-www-form-urlencoded
Body:
grant_type=authorization_code&client_id={my app id}&scope=https://graph.windows.net/Directory.AccessAsUser.All https://graph.windows.net/User.Read&code={the code received from authorize endpoint}&redirect_uri=https://localhost:44351/Login/LoginResponse&client_secret={secret from the portal}
The HTTP POST to token endpoint is successful. I get the JWT token, and I am able to successfully retrieve the access token from the JWT. However, when I try to use this access token to retrieve the user details, the below code fails every time with 401 response. The error message is
"odata.error":{"code":"Authentication_ExpiredToken","message":{"lang":"en","value":"Your access token has expired. Please renew it before submitting the request."}}}"
string strURL = @"https://graph.windows.net/me?api-version=1.6";
HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(strURL);
httpWebRequest.Headers.Add("Authorization", $"Bearer {jWTToken.access_token}");
using (HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse())
{
using (StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream()))
{
string str = streamReader.ReadToEnd();
}
}
The JWT token used in the above code is the one I receive from the Token endpoint. Why is it failing? The access token I received is decoded by jwt.ms as follows:
{
"typ": "JWT",
"alg": "RS256",
"kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk"
}.{
"iss": "https://{my tenant}.b2clogin.com/fc292353-4def-47bd-af44-b92e40798a60/v2.0/",
"exp": 1576642155,
"nbf": 1576638555,
"aud": "00000002-0000-0000-c000-000000000000",
"oid": "05c93456-2f02-4601-afb0-d4599b7e6826",
"sub": "05c93456-2f02-4601-afb0-d4599b7e6826",
"tfp": "B2C_1_signinsignup",
"nonce": "defaultNonce",
"scp": "Directory.AccessAsUser.All User.Read",
"azp": "{my app ID}",
"ver": "1.0",
"iat": 1576638555
}.[Signature]
B2C does not support delegated access to Graph API. You have to add Application permissions to the app registration, and use client credential authentication to get tokens.
See docs: https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-graph-dotnet?tabs=applications#assign-api-access-permissions
Under APPLICATION PERMISSIONS, select Read and write directory data.
Acquire the tokens from the underlying Azure AD's token endpoint, not your B2C policy endpoint.
You won't be able to use /me
of course since the token won't contain user info.
But you can use /users/id
instead.
The reason for the 401 is probably the issuer in your token. Graph API expects the normal AAD issuer, and that is not it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With