.net core 3.1 Bearer error="invalid_token", error_description="The audience 'empty' is invalid"
Asked Answered
S

3

8

I have 3 projects 1- Angular SPA 2- Web API Project core 3.1, 3- IdentityServer with Core 3.1 But I am getting following error

> www-authenticate: Bearer error="invalid_token", error_description="The audience 'empty' is invalid"

This is my API startup

 public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<SchemaRegistryConfig>(Configuration.GetSection("SchemaRegistryConfig"));


            //identity server

            services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer("Bearer", options =>
                {
                    options.Authority = "https://localhost:5002/";
                    options.RequireHttpsMetadata = false;
                    options.Audience = "Api";
                });


            IdentityModelEventSource.ShowPII = true;

           
            services.AddCors(c =>
            {
                c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
            });

            services.AddMvc(config =>
            {
                config.Filters.Add(typeof(UnhandledExceptionFilter));
                config.EnableEndpointRouting = false;
            }).SetCompatibilityVersion(CompatibilityVersion.Latest);

            services.AddServices(Configuration);
            services.AddHealthChecksUI();                
            
          
        }

        
        [Obsolete]
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                
                app.UseHsts();
            }
            
            app.UseCors("AllowOrigin");

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();        

            app.UseHttpsRedirection();
            app.UseMvc();
        }

Identity server config.cs

 public static class Config
    {
        public static IEnumerable<IdentityResource> IdentityResources =>
            new IdentityResource[]
            {               
              
                new IdentityResources.OpenId(),
                new IdentityResources.Email(),
                new IdentityResources.Profile(),
                new IdentityResources.Address(),

                new IdentityResource
                {
                    Name = "Api",
                    //UserClaims =
                    //{
                    //    "rc.garndma"
                    //}
                }
            };

       

        public static IEnumerable<Client> Clients =>
            new Client[]
            {
               
                new Client
                {
                    ClientName = "Code Flow with refresh tokens",
                    ClientId = "_client",

                    AccessTokenLifetime = 330,// 330 seconds, default 60 minutes
                    IdentityTokenLifetime = 45,

                    AllowAccessTokensViaBrowser = true,
                    RedirectUris = new List<string>
                    {
                        "http://localhost:4200/*******"
                    },
                    PostLogoutRedirectUris = new List<string>
                    {
                        "http://localhost:4200/*******"
                    },
                    AllowedCorsOrigins = new List<string>
                    {
                        "http://localhost:4200"
                    },

                    RequireClientSecret = false,

                    AllowedGrantTypes = GrantTypes.Code,
                    RequirePkce = true,
                    AllowedScopes = { "openid", "profile", "email", "Api" },

                    AllowOfflineAccess = true,
                    RefreshTokenUsage = TokenUsage.OneTimeOnly
                },
            };


        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("Api", "Invoice API")
                {
                    Scopes = { "invoice.read", "invoice.pay", "manage" }
                },
            };
        }

        public static List<ApiScope> ApiScopes()
        {
            return new List<ApiScope> {
            new ApiScope(name: "read",   displayName: "Reads your invoices."),
                new ApiScope(name: "pay",    displayName: "Pays your invoices."),
            };
        }
    }

identity server startup.cs

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();

            var builder = services.AddIdentityServer()
                .AddInMemoryIdentityResources(Config.IdentityResources)
                .AddInMemoryApiResources(Config.GetApiResources())
                .AddInMemoryApiScopes(Config.ApiScopes())
                .AddInMemoryClients(Config.Clients)
                .AddTestUsers(TestUsers.Users);


            services.AddAuthentication();
                
            services.AddCors(options => options.AddPolicy("AllowAll", p => 
                p.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()));

            // not recommended for production - you need to store your key material somewhere secure
            builder.AddDeveloperSigningCredential();
        }

        public void Configure(IApplicationBuilder app)
        {
            if (Environment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
           
            app.UseStaticFiles();
            app.UseRouting();
            app.UseCors("AllowAll");
            app.UseIdentityServer();
           
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
            });
        }
    }

Angular SPA oidc config

export function configureAuth(oidcConfigService: OidcConfigService) {
  return () =>
    oidcConfigService.withConfig({
      stsServer: 'https://localhost:5002',
      redirectUrl: "http://localhost:4200/home",
      postLogoutRedirectUri: window.location.origin,
      clientId: '_client',
      scope: 'openid profile email offline_access Api',
      responseType: 'code',
      silentRenew: true,
      useRefreshToken: true    
     
    });

My token payload is enter image description here

enter image description here

I have 3 controllers and I added [Authorize] on each controller. Can anyone help me with this? I get the token generated successfully and when I am using the token to call the webapi it throwing 401 with message. But no audience is present in it.

Serration answered 23/10, 2020 at 11:9 Comment(2)
You have to set an audience. Does this help?Unrequited
@Unrequited This doesn't help added scopes alreadySerration
S
15

I was facing the same issue, and ?I was missing Aud and Iss in my token. I needed that since in my Startup.cs file, I set them to be required for validation.

In your token string I don't see Aud claim.

Please see both codes below:

ConfigureServices method in Startup.cs

 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuer = true,
                    --> ValidateAudience = true, <--
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = Configuration["Jwt:Issuer"],
                    ValidAudience = Configuration["Jwt:Audience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"])),
                    ClockSkew = TimeSpan.Zero
                };
            });

Below is my generate token method:

    private string GenerateToken(UserViewModel loginViewModel)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"]));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, loginViewModel.UserName),
            new Claim("fullName", loginViewModel.FirstName + " " + loginViewModel.LastName),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim(JwtRegisteredClaimNames.Aud, _configuration["Jwt:Audience"]),
            new Claim(JwtRegisteredClaimNames.Iss, _configuration["Jwt:Issuer"])
        };

        var token = new JwtSecurityToken(
            issuer: _configuration["Issuer"],
            audience: _configuration["Audience"],
            claims: claims,
            expires: DateTime.Now.AddMonths(2),
            signingCredentials: credentials
            );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
Stirpiculture answered 23/11, 2020 at 18:56 Comment(3)
Happy of help with itStirpiculture
What is the value of _configuration["Jwt:Issuer"]?Tineid
You can find more details here: quora.com/… and understand why I didn't share it. For local machine, you can set it to whatever you want.Stirpiculture
W
-1

turn off validating audience by adding line ValidateAudience = false in:

.AddJwtBearer("Bearer", options =>
    {
     options.Authority = "https://localhost:5002/";
     options.RequireHttpsMetadata = false;
     options.Audience = "Api";
     options.ValidateAudience = false;
    });
Waggoner answered 25/11, 2023 at 8:56 Comment(0)
A
-2

For me, I had to remove the following

//services.AddAuthentication("Bearer")
//    .AddIdentityServerAuthentication("Bearer", options =>
//    {
//        options.Authority = identityServerUrl;
//        options.RequireHttpsMetadata = false;
//        options.ApiName = "bankOfDotNetApi";
//        //options.TokenValidationParameters = new TokenValidationParameters();
//    });

//services.AddAuthorization(options =>
//{
//    options.AddPolicy("bankOfDotNetApi", policy =>
//    {
//        policy.RequireAuthenticatedUser();
//        policy.RequireClaim("scope", "bankOfDotNetApi");
//    });
//});

and add the following code. Note ValidateAudience = false. That made the difference.

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
    options.Authority = identityServerUrl;
    options.RequireHttpsMetadata = false;
    options.Audience = "bankOfDotNetApi";
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ////////////////////////////////////////////////////////
        // The following made the difference.  
        ////////////////////////////////////////////////////////
        ValidateAudience = false,
    };
});
Alexandrina answered 31/10, 2021 at 16:9 Comment(1)
downvoted coz disabling the check is not a solutionGlycogen

© 2022 - 2024 — McMap. All rights reserved.