0
votes

I have a web application running on Azure App Services. The front-end (javascript + html + css) communicates with the backend (Flask). Both are runing on the same app service instance.

My app is protected by Active Directory Authentication (configured using Azure Portal).

User authentication to the app works perfectly. When a user navigates to the app, they are redirected to the login for our azure AD tenant. When they try to sign in, their permission to the app is controlled by their membership to an azure AD group. This bit works as expected

The challenge is that the front-end needs to send authenticated requests in order for them to actually reach the backend. They must be authenticated using a service principal token, not the user's token. And to this end, we are using the new, recommended approach; Managed Service Identity (MSI), not the service principal account workflow directly.

There are 2 stages to this:

1) Adding the authorization header 2) Ensuring that the MSI principal has access (i.e. belongs to the AD group)

1) The server generates an access token using the below code:

credentials = azure_active_directory.MSIAuthentication()
session = credentials.signed_session()
return session.headers.get("Authorization")

We then add the {"Authorization": "Bearer "} header where is the result of the above code.

This appears to work as expected - we are seeing long alphanumeric access tokens

2) The tricky bit was ensuring the MSI was added to the AD group. The GUIs at myapps.microsoft.com and mygroups.microsoft.com only allow the adding of users. Instead, I used the Azure CLI and ran the following:

a) Retrieve MSI principal ID msiobjectid=$(az webapp identity show --resource-group <resource-group-name> --name <azure app services name> --query principalId)

b) Add principal to group az ad group member add --group <group name> --member-id $msiobjectid

We are still getting 401 Unauthorized and we have exhausted all documentation :(

I should note that I only completed step 2 (adding the principal to the azure AD group via Azure CLI) about an hour ago. Perhaps there is a delay?

Edit: my scenario is closest to https://github.com/uglide/azure-content/blob/master/articles/app-service-api/app-service-api-dotnet-service-principal-auth.md except a) I'm using MSI, not a direct service principal and b) I have an extra layer of authorization, which is the ad groups, restricting access to the app to a few users rather than the whole tenant.

1
Wait, are you approaching your SPA frontend as a confidential client or did i read that wrong?evilSnobu
I'm not sure what you're getting at there or why it's relevant whether the application is single or multi-page. The application should only be accessed via internal users, controlled by AD groups. The application itself sends API requests that interact with resources that users don't have access to which is why this bit uses a service account workflow, not just passing the user credential through.adamcunnington
Yeah, i read that wrong. Which resource are you trying to access with that Bearer token (as in, what's in your aud claim?)evilSnobu
@evilSnobu, I'm not trying to access an azure resource (yet). The point is that it's not even getting to my API. The front end sends a http request to my back end and that's returning 401.adamcunnington
And to be clear, it's not my API retuning 401 but the authorization provider! I.e. active directory.adamcunnington

1 Answers

0
votes

I believe you got this all backwards.

Your scenario is SPA + backend.

What you need to implement is OAuth 2.0 implicit grant flow as described here.

Implicit Flow

Source for diagram: dzimchuk.net

With the resulting access_token placed in the user-agent's session storage you can then call your backend. Use adal.js to make your life easier.

Since your Python backend IS a confidential client, you can now request an access token from the MSI endpoint for the desired audience (Azure resource), call it then filter the results so that it matches your access rights logic.

Note that at the time of writing only a subset of Azure resources are able to consume MSI-issued access tokens.