Search code examples
asp.net-coreazure-active-directoryasp.net-core-webapiazure-ad-msalmicrosoft-identity-platform

How do you get an Access Token from Azure Active Directory that the scaffolded Weather Forecast Api will accept?


I'm trying to build a new WebApi secured using access tokens from azure active directory.

I'm using .net core v3.1 and visual studio 2019.

I created a new project using the "Asp.net core web application" template and picked an "API" project and changed the authentication type to "Work or School Accounts" and set the App ID Url to Api://Automation/TestApi

Visual Studio then scaffolded me a web API with a mock weather forecast service which, if I comment out the [Authorize] attribute spins up nicely in a browser as expected. It also created me an Application Registration in AzureActive Directory.

With the [Authorize] attribute back in place I had trouble calling the API from a client app so I decided to call the API using postman to see what's going on.

I added a client secret to the app registration visual studio created and put a postman request together as below using the Application (client) Id and api://Automation/TestApi/.default as the scope.

Postman Call to token endpoint

This works fine and returns an access token however when I try to use that access token to call the default weatherforcast endpoint I get an HTTP 401 unauthorized error with the following in the WWW-Authenticate response header

"Bearer error="invalid_token", error_description="The audience 'api://Automation/TestApi' is invalid"

Is there something I'm missing? I cannot find any clue as to what the audience is expected to be and no obvious way of controlling that.

As Requested here is the content of the expose an API screen

Expose an API

and the decoded jwt token I am using

enter image description here

Update

I tried out @CarlZhao s answer below and it didn't really work. However I remembered a question I asked a while ago about the wrong issuer in the token the outcome from this is to manually edit the manifest json in the registration for the API and set "accessTokenAcceptedVersion": 2

Now I get a v2 function with the clientId guid as the audience

V2 JWT

However, using this token still doesn't work!! I now get an error about the issuer:

Bearer error="invalid_token", error_description="The issuer 'https://login.microsoftonline.com/{{guid}}/v2.0' is invalid


Solution

  • I've found a better way of doing it so thought I would post the answer as an alternative to my first answer.

    I found this very good sample application and tutorial and worked through the 1st part "Desktop App Calls Web Api" and produces an api that is using the correct endpoints and handles validates the token in a more predictable manor. If you are stating out on a new Web API I would suggest using this as a starting point instead of the api that visual studio scaffolds.

    To get the scaffolded weather forcast api to accept token an access token

    • You need seperate application registrations for the client and the api as well as a scope as sugested by @Carl Zhao and the tutorial linked above.
    • Replace the Microsoft.AspNetCore.Authentication.AzureAD.UI nuget package with Microsoft.Identity.Web
    • In your startup.cs in Configure services replace the call to services.AddAuthentication(...).AddAzureAdBearer(....) with a call to AddMicrosoftIdentityWebApiAuthentication
    • remove using directives for Microsoft.AspNetCore.Authentication.* and add in using Microsoft.Identity.Web;

    heres what my Configure Services Looks Like now

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
    
            services.AddControllers();
        }
    

    The custom issuer validator presented in my other answer is not requried and can be removed.