gt-downunder
gt-downunder

Reputation: 71

Graph authentication using validated JWT

We have an app registration within our Azure subscription that requires access to Graph, set up under the "Required permissions" section.

Delegated Permissions image

Our Angular application is kicking off authentication against AAD, receiving the JWT, appending it to all requests in the Header and sending it to our WebApi where it's being validated successfully....great!

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjlGWERw...

Now, from the WebApi, I also want to make a request to Graph and considering I have the validated token, I'm passing it to a Graph REST API via an Authorization header.

request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);

However, I'm getting a 401 (Unauthorized) result. Why? Obviously I'm missing a piece of the puzzle, but I don't know what.

I assumed that by setting up Graph permissions in the Azure app registration that when it sent the token to our Angular app it was valid for both AAD and Graph...but it seems this is not the case.

My JWT looks like the following. Note the "aud" only shows my app registration id and not Graph (if that's the problem, how do I fix it?)

{
  "aud": "<application id here>",
  "iss": "https://sts.windows.net/<tenant id here>/",
  "iat": 1499121655,
  "nbf": 1499121655,
  "exp": 1499125555,
  "aio": "ASQA2/8DAAAACuKzzzni2uaVoaIb9yJa4j3XuG0O+9cQQQlnqXl8Sr0=",
  "amr": [
    "pwd",
    "mfa"
  ],
  "family_name": "Smith",
  "given_name": "John",
  "name": "John Smith",
  "nonce": "<nonce here>",
  "platf": "3",
  "pwd_exp": "941678",
  "sub": "<sub here>",
  "tid": "<tenant id here>",
  "unique_name": "[email protected]",
  "upn": "[email protected]",
  "ver": "1.0"
}

EDIT

I've now implemented the on-behalf-of code as Nan Yu described, but I am still getting a 401. The front-end token is being validated in the WebAPI, which is then creating a request to Graph.

string authString = ConfigurationManager.AppSettings["ida:Authority"];
string clientId = ConfigurationManager.AppSettings["ida:Audience"];
string clientSecret = ConfigurationManager.AppSettings["ida:AppSecret"];
string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
string graphResourceId = ConfigurationManager.AppSettings["ida:GraphResourceId"];

AuthenticationContext authenticationContext = new AuthenticationContext(authString);
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);

var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);

string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
string userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;

AuthenticationResult result = await authenticationContext.AcquireTokenAsync(graphResourceId, clientCred, userAssertion);

This works fine because of the token being returned now has the Graph "aud" and "scp" for the user that logged in:

"aud": "https://graph.windows.net",
"scp": "User.Read User.ReadBasic.All",
"unique_name": "[email protected]",
"upn": "[email protected]",

Why am I still unauthorized when trying call the /me Graph API?

Upvotes: 1

Views: 2175

Answers (1)

Nan Yu
Nan Yu

Reputation: 27528

If you want to call microsoft graph api , you need to acquire access token for microsoft graph api , that means the aud(audience) in access token claims should be https://graph.microsoft.com .

In your scenario , if user login in client app , then client app calls your web api , in web api , you want to call microsoft graph api , there are two ways to achieve that :

1.Using OAuth 2.0 On-Behalf-Of flow to delegate the user’s identity and authenticate to the second-tier web API. See code sample here .

2.Using OAuth 2.0 Client Credentials Grant , Azure AD authenticates the web api application and returns a JWT access token that is used to call the Microsoft graph . In this scenario , you should grant permissions for microsft graph in web api application .See code samples here .

Please click here for more details about above scenarios.

Upvotes: 2

Related Questions