The audience is invalid error

Viewed 72893

I have 3 projects 1- Javascript SPA 2- Web API Project, 3- IdentityServer with EF Core

I started debugging API and Identity Server and successfully get the jwt token but, when I try to get value from API method which has Authorize Attribute I get an error:

WWW-Authenticate →Bearer error="invalid_token", error_description="The audience is invalid"

I could not found any property about audience in auth options. This is my configuration in API project

app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
        {
            ApiSecret="secret",
            Authority = "http://localhost:5000",
            ApiName="fso.Api",
            RequireHttpsMetadata = false,
        });

And my Config.cs file in Identity

 public class Config
{        
    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource>
        {                
            new ApiResource()
            {
                Name = "fso.Api",                    
                DisplayName = "feasion API",
                Scopes =
                {
                    new Scope("api1"),
                    new Scope(StandardScopes.OfflineAccess)
                },
                UserClaims =
                {
                    JwtClaimTypes.Subject,
                    JwtClaimTypes.EmailVerified,
                    JwtClaimTypes.Email,
                    JwtClaimTypes.Name, 
                    JwtClaimTypes.FamilyName,
                    JwtClaimTypes.PhoneNumber,
                    JwtClaimTypes.PhoneNumberVerified,
                    JwtClaimTypes.PreferredUserName,
                    JwtClaimTypes.Profile, 
                    JwtClaimTypes.Picture, 
                    JwtClaimTypes.Locale, 
                    JwtClaimTypes.IdentityProvider,
                    JwtClaimTypes.BirthDate, 
                    JwtClaimTypes.AuthenticationTime
                }
            }
        };
    }
    public static List<IdentityResource> GetIdentityResources()
    {
        return new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Email(),
            new IdentityResources.Profile(),
        };
    }

    // client want to access resources (aka scopes)
    public static IEnumerable<Client> GetClients()
    {
        return new List<Client>
        {
            new Client
            {
                ClientId = "fso.api",
                AllowOfflineAccess=true,
                ClientSecrets =
                {
                    new Secret("secret".Sha256())
                },
                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,                    
                AllowedScopes =
                {                       
                   StandardScopes.OfflineAccess,                    
                   "api1"
                }
            }
        };
    }
}
4 Answers

To avoid the error, audience should be consistently added in 4 places

  1. In My (e.g. MVC) client as custom Scope.
  2. In API application as ApiName
  3. In IdentityServer Clients configuration as AllowedScope
  4. In API Resources configuration as ApiResource

See details ( previously available in IdentityServer4 wiki):

When configuring a new API connection in identityServer4, you can get an error:

WWW-Authenticate: Bearer error="invalid_token", 
error_description="The audience is invalid"

To avoid the error, Audience should be consistently added in 4 places

  1. In My (e.g. MVC) client as custom Scope :
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
  Authority = Configuration["IdpAuthorityAddress"],
  ClientId = "my_web_ui_id",
  Scope = { "openid", "profile", "offline_access", "MyApi" },               

//other properties removed for brevity...
});
  1. In API application as ApiName
//Microsoft.AspNetCore.Builder.IdentityServerAuthenticationOptions
var identityServerAuthenticationOptions = new IdentityServerAuthenticationOptions()
{
  Authority = Configuration["Authentication:IdentityServer:Authority"],
  RequireHttpsMetadata = false,
  EnableCaching = false,
  ApiName = "MyApi",
  ApiSecret = "MyApiSecret"
};
  1. In IdentityServer \IdentityServerHost\Configuration\Clients.cs (or corresponding Clients entry in the database)
var client = new Client
{
  ClientId = clientId,  
  //other properties removed for brevity...   
  AllowedScopes =
  {
    IdentityServerConstants.StandardScopes.OpenId,
    IdentityServerConstants.StandardScopes.Profile,
    //IdentityServerConstants.StandardScopes.Email,
    IdentityServerConstants.StandardScopes.OfflineAccess, "MyApi",
  },
};
  1. In IdentityServer \IdentityServerHost\Configuration\Resources.cs (or corresponding ApiResource entry in the database) as apiResource.Scopes
var apiResource = new ApiResource
{
  Name = "MyApi",
  ApiSecrets =
  { 
    new Secret("MyApiSecret".Sha256())
  },
  UserClaims =
  {
    JwtClaimTypes.Name,
    JwtClaimTypes.Profile,
  },
};

In your app configuration file in AD configuration section add "Audience" line:

"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "ClientId": "<-- Enter the Client Id -->",
  "Audience": "<-- Enter the Client Id -->",
  "TenantId": "<-- Enter the tenantId here -->"
}

In my case "ClientId" & "Audience" was the same.

P.S.: And if after that you'll see

IDW10201: Neither scope or roles claim was found in the bearer token

Add another line to AD configuration:

"AllowWebApiToBeAuthorizedByACL": true

More here

In IdentityServer had to add claim "aud" to the jwt Token. In Order to do that under .AddJwtBearer("Bearer", options => options.Audience="invoice" and set ApiResource

Reference Link https://identityserver4.readthedocs.io/en/latest/topics/resources.html#refresources

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