Im using this repo as a guide

https://github.com/Azure-Samples/ms-identity-docs-code-dotnet/tree/main/web-api

My code is a .Net 6 Web API Core (.Net 6) project is

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(config =>
    config.AddPolicy("AuthZPolicy", policyBuilder =>
        policyBuilder.Requirements.Add(new ScopeAuthorizationRequirement() { RequiredScopesConfigurationKey = $"AzureAd:Scopes" }));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
    app.UseSwagger();
    app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

When i run the weatherforecast URL i get a 401 with the error listed under Debug

Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Debug: AuthenticationScheme: Bearer was not authenticated.

Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. These requirements were not met:

ScopeAuthorizationRequirement:Scope=

Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Information: AuthenticationScheme: Bearer was challenged.

My json config file

  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": "1235456",
    "TenantId": "456788",
    "Scopes": "https://ourDomain.onmicrosoft.com/123456789/"

I tried adding

builder.Services.AddAuthentication(options =>
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

Which made no difference, finally i added

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(cfg => {
        cfg.RequireHttpsMetadata = false;
        cfg.SaveToken = true;
        cfg.TokenValidationParameters = new TokenValidationParameters()
            ValidateAudience = false,
            ValidateLifetime = false,
            ValidateIssuerSigningKey = true

but then i got the error the scheme already exists.

What code am i missing or is this related to the app registration setup?

Hello,

I think the issue may be in app registration settings :

Ensure that In the "Expose an API" section, ensure that you have defined an application scope. The scope's name should match the value specified in your configuration file under "AzureAd:Scopes". For example, if your scope in the configuration is https://ourDomain.onmicrosoft.com/123456789/, you should have a scope defined as https://ourDomain.onmicrosoft.com/123456789/ in the "Expose an API" section of your app registration. Also make sure the client application that calls your Web API is granted the required permissions (delegated permissions) for the defined scope. If you still have issues, let us know more about your client app and how it requests the access token. Good luck!

And If you find this answer usefull please mark it as accepted to help others with same issue find this topic.

Hi @Mr Edge , the code sample you used contained a Web API which is protected by Azure AD. If this is what you want to add to your API, then I trust you already know that after integrating the Azure AD, you have to have a correct access token in the request header in your API request like Authorization: Bearer access_token.

Next, we have to first register an Azure AD application to expose an API and this is what @Boris Von dahle mentioned. Here's the official document about how to expose a scoped API permission. After that we can get an API scope like api://client_id/scope__name. Then we need to add this API permission to the Azure AD app which is used for the authorization (you used to set ClientId in appsetting.json), you can also use the same app which exposing the API.

After adding the API permission, we can change the code like the sample. To call this api, we have to generate an access token now. We can use auth code flow. First to get the auth code via this request, pls note to change the redirect URl you set in AAD Authentication blade.

https://login.microsoftonline.com/tenant_id/oauth2/v2.0/authorize?
client_id=aad_client_id
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=api://aad_client_id_which_exposed_api/permission_name
&state=12345

Then using the code in the url to generate access token. You can decode the access token and see it contains the scp claim which value is the API permission you exposed and consented.

Finally you can call your API

=============================================

If the answer is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

Best Regards,

TinyWang

Thanks guys. Im still getting different error with different apps i.e. if i run in a browser, Postman or via Visual Studio.

To start with i will go over the steps i took from an existing Active Directory subscription.

App Registration:

Application (client) id: ABC123
Object ID:
Directory (tenant) ID: DEF456
Supported Account Types: My organisation only
Client credentials: 0 certificate, 1 secret
Redirect URIs: 2 web (0 for rest)
Application ID URI: https://ourDomain.onmicrosoft.com/ABC123
Managed applicaton: Takes me to another page

Authentication:

I see Web with 2 URLs (might be for 2 different local PCs as both are local URLs)

Front-channel logout URL: localhost URL

Implicit grant and hybrid flows.

Access Tokens is the only one checked

Supported Accounts: Single Tenant
Enable mobile and desktop flows: No

Certificates and Secrets

One listed value is marked with ZZ******** with a secret which is 0987654321 (just for this purpose)

API Permissions

Microsoft Graph

My API listed with

Type: delegated,
Admin consent: Yes
Status: Granted for "directory name"

Expose an API

Application ID URI: https://ourDomain.onmicrosoft.com/ABC123 (seems to be the Client id from above)
Scopes
https://ourDomain.onmicrosoft.com/ABC123/NameOfScope
Who can consent: Admins only
State: Enabled

So i think thats how its set up at present.

When i converted this code replacing the values to mine

https://login.microsoftonline.com/tenant_id/oauth2/v2.0/authorize?

client_id=aad_client_id

&response_type=code

&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F

&response_mode=query

&scope=api://aad_client_id_which_exposed_api/permission_name

&state=12345

I got the error

User account 'myname@ourdomain.com' from identity provider 'https://sts.windows.net/MMMUUU/' does not exist in tenant 'Some directory name' and cannot access the application 'ABC123'(NameOfAPI) in that tenant. The account needs to be added as an external user in the tenant first. Sign out and sign in again with a different Azure Active Directory user account.

At this stage I thought I may have done something wrong as I felt using a client key and secret was what my application would use or I provide to external companies to use my app?? In my Visual Studio project i have the same code but tweaked the Json file settings to below

  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": "ABC123",
    "TenantId": "DEF456",
    "Scopes": "https://ourdoman.onmicrosoft.com/ABC123"

The above gives the exact same error as before.

I couldnt get the example working from Postman as i wasnt sure where to get all the token values (grant_type, assertion, requestedtoken_use)

Have i missed something? Or done something wrong?

Thanks

And I added API permission and consent admin consent.

The app I exposed API is the same as the one I added API permission, so I only have one Azure AD app here.

And using the request I mentioned to get auth code:

Using the copy the code value and generate access token:

POST: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token

Content-Type: application/x-www-form-urlencoded

clientid=azureadapp_id&scope=api://xxxx/tiny.read &code=OAAA... &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F &grant_type=authorization_code&client_secret=JqQX2PNo9bpM0uEihUPzyrh

And copy the access token to generate in jwt.io to decode it and see if the token contained a scp claim which value is your exposed API value.

891Reputation points May 1, 2023, 4:40 PM Can you please double check your Application ID URI it should generally be something like api://<client-id> instead of https://ourdomain.onmicrosoft.com/ABC123 and also double check that you are using the right tenant ID.

@Boris Von Dahle I was thinking the same earlier, but when i go into App Registrations and then Expose an API when i click to Edit it automatically has the domain filled in and i dont have any choice to change it as far as i can tell. Unless i have to take different steps?

@Tiny Wang-MSFT I still dont know how you generated the "code" value? All of the rest of settings seem to be ok

Im going over the advice above to see if i can resolve

@Mr Edge Hi, using auth code flow requires us to generate a code first, and we need to edit this request then copy and paste into the browser. Next it will ask you to enter user name and password, after sign in successfully, it will redirect to the URL you specified, and you can see the url now, it will contain the code. Sign in request is like this, you can also find it in my answer above.

https://login.microsoftonline.com/tenant_id/oauth2/v2.0/authorize? client_id=aad_client_id &response_type=code &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F &response_mode=query &scope=api://aad_client_id_which_exposed_api/permission_name &state=12345
											

@Tiny Wang-MSFT Hi when i run the URL above (replacing it with my values) i am prompted to login. I login with an account and received the message "The account needs to be added as an external user in the tenant first. Sign out and sign in again with a different Azure Active Directory user account.".

I wanted to use client credentials to access the API and not an account?

Also i have removed all additional code i added originally (just in case this is making any difference)