0
votes

I have an Azure Function setup with a Web Trigger endpoint that I want to use as my backend for a React app. Without authentication setup, it works fine. When I setup App Service Authentication using AD, it works fine when I access directly via the browser (after authentication), but when I try to access from JS providing the Bearer token I get a 401.

const response = await axios.get(`${window.apiUrl}api/jobs`, {
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Bearer ' + token.accessToken,
    },
  });

The client app is running on Azure and is registered as an Azure AD app. I am able to authenticate, query AD, and use MS Graph API successfully.

I am using the built-in Azure App Services AD authentication. I have the Client ID set as the same client ID as the previously mentioned Azure AD app, as well as the same Issuer Url.

Attempt to get session token:

const accessToken = await authProvider.getAccessToken();
const idToken = await authProvider.getIdToken();
const login = await axios.post(
  'https://<appname>.azurewebsites.net/.auth/login/aad',
    { access_token: accessToken.accessToken },
    {
      headers: {
        'Content-Type': 'application/json',
      },
    },
  );

More Info

My aud claim is 00000003-0000-0000-c000-000000000000. In Azure Portal, my Azure Function is configured to use the same Azure AD App as my SPA. I am using MSAL.js for authentication in my SPA. I am requesting the User.Read and Directory.Read.All scopes.

2
Need a bit more information. Here are some things to gather. 1) you can paste your access token inside jwt.ms and look at the "aud" claim. Can you paste that information here? 2) your configuration on the Authentication/Authorization blade - you have it configured for a specific App ID 3) what are you using in your SPA - is it ADAL.js or MSAL.js 4) in your SPA what is your list of scopes you are requesting.Saeed Akhter
@SaeedAkhter The requested info was added to the OP.Mike Cole

2 Answers

1
votes

Microsoft has published a how-to article entitled Advanced usage of authentication and authorization in Azure App Service. In the section on validating tokens from providers, it says:

In a client-directed sign-in, the application signs in the user to the provider manually and then submits the authentication token to App Service for validation (see Authentication flow). This validation itself doesn't actually grant you access to the desired app resources, but a successful validation will give you a session token that you can use to access app resources.

So you need to get the session token to access app resources.

Request:

POST https://<appname>.azurewebsites.net/.auth/login/aad HTTP/1.1
Content-Type: application/json

{"id_token":"<token>","access_token":"<token>"}

Response:

{
    "authenticationToken": "...",
    "user": {
        "userId": "sid:..."
    }
}

enter image description here

Once you have this session token(authenticationToken), you can access protected app resources by adding the X-ZUMO-AUTH header to your HTTP requests

GET https://<appname>.azurewebsites.net/api/products/1
X-ZUMO-AUTH: <authenticationToken_value>
0
votes

You cannot request a token for Microsoft Graph and use it to call your own API. The Audience "00000003-0000-0000-c000-000000000000" means "intended for Microsoft Graph".

In MSAL, when you request the token, you need to adjust the scopes. Delete User.Read, delete Directory.Read.All and add the "Application ID URI" with a /.default at the end of it. You can find the Application ID URI in the "Expose an API" blade of your application registration on portal.azure.com. Example: https://SaeedApp/.default

If you need to do both, you can only request an access token for one resource at a time. However, you can request as many scopes as you need for one resource (User.Read and Directory.Read.All are both scopes for the same resource).

So you'll need to make two sets of requests: 1) to get an access token with all the scopes you need for Microsoft Graph 2) to get an access token with all of the scopes you need for your API

The reason behind why: If I could take an access token that's intended for your API and call Microsoft Graph with it, then that would open up "replay" attacks where one Resource API is hacked and the hacker that controls one resource can now reply access tokens it receives from clients against all the other Resource APIs.