0
votes

I have an ASP.NET Core API, where I want to use Azure AD authentication. I have created an App Registration and provided the config below for my API:

 "AzureAd": {
    "TenantId": "<tenantid>",
    "ClientId": "api://<clientid>", // tried it with only the guid clientid as well
  },

Authentication config (App registration exposed API scope provided):

services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                options.RequireHttpsMetadata = false;
                options.Audience = Configuration["AzureAd:ClientId"];
                options.Authority = "https://login.microsoftonline.com/" + Configuration["AzureAd:TenantId"];
            })

My problem is, that when I log in to azure AD, the audience in my token will be 00000002-0000-0000-c000-000000000000 (Id of AAD Graph API), instead of the client id of the App registration.

I am using swagger to test the authentication:

        app.UseSwaggerUi3(config =>
        {
            config.OAuth2Client = new NSwag.AspNetCore.OAuth2ClientSettings
            {
                ClientId = Configuration["AzureAd:ClientId"],
                ClientSecret = string.Empty,
                UsePkceWithAuthorizationCodeGrant = true,
                ScopeSeparator = " "
            };
        });

swagger document config:

services
    .AddOpenApiDocument(c =>
    {
        c.AddSecurity("OAuth2", new OpenApiSecurityScheme
        {
            OpenIdConnectUrl = $"https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration",
            Scheme = "Bearer",
            Type = OpenApiSecuritySchemeType.OAuth2,
            Flows = new OpenApiOAuthFlows
            {
                AuthorizationCode = new OpenApiOAuthFlow
                {
                    AuthorizationUrl = $"https://login.microsoftonline.com/{Configuration["AzureAd:TenantId"]}/oauth2/authorize",
                    TokenUrl = $"https://login.microsoftonline.com/{Configuration["AzureAd:TenantId"]}/oauth2/token",
                    Scopes = new Dictionary<string, string>
                    {
                        { "api://<client id>/Api.Read", "api://<client id>/Api.Read" }
                    }
                }
            }
        });
    })
2
You need to ask for a token for your API in your front-end application. Can you show how you are getting the token.juunas
You can go to the API app registration, Expose an API, add a scope, and then use that scope when asking for a token.juunas
Thank you for your answer, I have tried it, but it did not work. I have updated the question to show the swagger doc config with the requested scopefbede
Try using the v2.0 authorization and token URLs, e.g. https://login.microsoftonline.com/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/tokenjuunas
It works! Thanks for your help, that was an easy to miss detail.fbede

2 Answers

1
votes

After discussion in comments, found working solution:

  1. Define a scope for the API app registration in Expose an API page
  2. Use the scope in Swagger UI, e.g.: api://client-id/Api.Read
  3. Use the v2.0 token and authorization endpoints:
AuthorizationUrl = $"https://login.microsoftonline.com/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/authorize",
TokenUrl = $"https://login.microsoftonline.com/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/token",
Scopes = new Dictionary<string, string>
{
    { "api://<client id>/Api.Read", "api://<client id>/Api.Read" }
}
0
votes

As per the documentation the client Id of the requester is contained in the appid (v1 tokens) or azp (v2 tokens) claim. The behaviour you've observed is correct as the audience is the Id of the party expected to verify the token and provide access to the required resource.