2
votes

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:

enter image description here

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]
1

1 Answers

3
votes

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://docs.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.