We have one application that uses an IdentityServer4 cookies authorization scheme for user login like this:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = <local IDP server with IdentityServer4>;
options.ClientId = <ClientId>;
options.ClientSecret = <secret>
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("offline_access");
})
The client on the IDP looks like this:
new Client
{
ClientId = <ClientID>,
ClientName = <ClientName>,
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
RequireConsent = true,
ClientSecrets = { new Secret(<secret>.Sha256()) },
AllowOfflineAccess = true,
RedirectUris = { "http://" + ip + "/signin-oidc" },
PostLogoutRedirectUris = { "http://" + ip + "/signout-callback-oidc" },
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
};
We also have a WebAPI located at /api/...
The goal is to add JWT Bearer Token authorization to the API. For that I have added the following code:
.AddJwtBearer(jwtOptions =>
{
jwtOptions.Authority = <local IDP server with IdentityServer4>;
jwtOptions.Audience = <ClientID>
jwtOptions.SaveToken = true;
})
The API is guarded with
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
After login, I get the token with
await HttpContext.GetTokenAsync("access_token");
However, when I try to use that token to access the API, I get the following error:
AuthenticationFailed: IDX10214: Audience validation failed. Audiences: 'http://localhost:50059/resources'. Did not match: validationParameters.ValidAudience: ClientID or validationParameters.ValidAudiences: 'null'.
And indeed, when I decode the token using jwt.io, aud
is set to http://localhost:50059/resources
, while the ClientID appears as a new field 'client_id': '<ClientID>'
.
What I found out so far suggests that aud
is always set to <idp>/resources
for access tokens and that API access is handled with scope claims inside the token. However, I do not understand how to set that up correctly.
Does anybody know where the problem lies and how I can fix it?
Turns out that the solution was quite simple. As suspected, it had to do with scopes. I tried to solve that earlier but it kept saying "invalid scopes"...because I never created the API resource, duh.
new ApiResource("api-name", "API Name")
client.AllowedScopes.Add("api-name")
options.Scopes.Add("api-name")
options.Audience = "api-name"
or
options.ApiName = "api-name"
With that I was now able to use the access token to access my API.