Search code examples
c#openidmulti-tenantazure-active-directory

Obtaining a token on behalf of a user in a multi-tenanted, azure AD based application - No permission to access user information is configured?


I am currently prototyping an authentication model for a series of cloud based micro services and have run into a wall when trying to obtaining a token from Azure AD on behalf of the authenticated user. I feel I am missing something obvious so I am hoping someone can point me in the right direction.

Overview

My prototype consists of two applications:

  • An Asp.MVC base UI
  • A WebAPI based data service.

Both applications are hosted in azure and use Azure's active directory for access management. In azure, I have set up two AD instances:

  • Service Directory: This is the master directory where all applications are registered.
  • Tenant Directory: The AD instance for the tenant. Going forward, there would be one of these per tenant.

Both the UI and data service are registered in the service directory and set to multi-tenant. The UI authentication is based on Vibronet's multi-tenant sample and correctly pushes the users through the consent grant flow when they first log in, and then registers the UI application with the users AD instance. During the consent grant, the UI requests the following permissions:

  • Access your organization's directory
  • Enable sign-on and read users' profiles
  • Read and write directory data
  • Read directory data

The user is then redirected back to the UI application and I can successfully view the users claim information at this point. So, up until this point I believe everything is configured and working correctly.

The Problem

Once the user is authenticated, the UI application should then obtain a token on behalf of the current user to access the back-end data service and this is where the problem lies.

The authentication for the data service is based on WebApi-On-Behalf-of sample however whenever I attempt to obtain the token, I get the following error:

No permission to access user information is configured for [AppGuid] application, or it is expired or revoked

Given the permissions granted during the consent flow, however, I believe it should have permissions to access the tenant AD instance and have tried giving the UI application all application and delegated permissions available in AD and re-running the consent flow but still get the same result.

My code for obtaining the on-behalf-of token is as follows:

ClientCredential uICredentials = new ClientCredential(StartUp.UiClientId, StartUp.UiSecret);
BootstrapContext bootStrapContext = GetBootstrapContext();
UserAssertion userAssertion = new UserAssertion(bootStrapContext.Token);
AuthenticationContext authContext = new AuthenticationContext(StartUp.adAuthority);
var authResult = authContext.AcquireToken(routerServiceResourceId, uICredentials, userAssertion);

with the exception being raised on the final line. The parameters here are:

  • StartUp.UiClientId: The application id for the UI in the service directory.
  • StartUp.UiSecret: The secret key for the UI app in the service directory.
  • StartUp.adAuthority: I have tried this with the common AD endpoint for multi-tenant applications (https://login.microsoftonline.com/common/) and with the specific endpoint for this tenant (https://login.microsoftonline.com/tenantid). Both give the same result.
  • routerServiceResourceId: The App Id URI for the data service.

In addition, I have set 'SaveSigninToken' to true in the TokenValidationParameters for the UI application so I can obtain the BootstrapContext.Token.

As far as I can see, this is everything it should need to work but, as I say, I continually get the error above =/

Can anyone suggest a way forward / obvious solution / further reading for this. I seem to be banging my head against this and not getting very far. I am also not 100% what information is pertinent here regarding the problem so if I have missed any important points, please let me know and I can update the question.


Solution

  • The OnBehalf of flow isn't really appropriate in this case. The OnBehalf of flow is appropriate when a WebAPI receives an access token and needs to get an access token for a downstream WebAPI. The flow that is most appropriate in your case is the OpenID Connect code+id_token flow. In this flow the WebApp receives an id_token that authenticates the user and an authorization code that allows the WebApp to get an access token for a back end server. The WebApp then redeems the authorization code for the access token.

    The best example of this flow is here:

    https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet

    Pay attention to Startup.Auth.cs where the AuthorizationCodeRecieved notification is set up. This shows how to retrieve the code and redeem it.