Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I'm developing an ASP.NET Core 2 app using Identity and Sustainsys.Saml2 (for SAML auth). I've made the necessary configurations in the Startup.cs file. Now when I run the project and try to login using the SAML2 (as an external login), I get the following error after enter my credentials:
SecurityTokenInvalidAudienceException: IDX10214: Audience validation
failed. Audiences: '[PII is hidden]'. Did not match:
validationParameters.ValidAudience: '[PII is hidden]' or
validationParameters.ValidAudiences: '[PII is hidden]'.
Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable
audiences, SecurityToken securityToken, TokenValidationParameters
validationParameters)
Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateConditions(Saml2SecurityToken
samlToken, TokenValidationParameters validationParameters)
Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateToken(string
token, TokenValidationParameters validationParameters, out
SecurityToken validatedToken)
Sustainsys.Saml2.Saml2P.Saml2Response+d__60.MoveNext()
System.Collections.Generic.List..ctor(IEnumerable collection)
System.Linq.Enumerable.ToList(IEnumerable source)
Sustainsys.Saml2.Saml2P.Saml2Response.GetClaims(IOptions options,
IDictionary relayData)
Sustainsys.Saml2.WebSso.AcsCommand.ProcessResponse(IOptions options,
Saml2Response samlResponse, StoredRequestState storedRequestState)
Sustainsys.Saml2.WebSso.AcsCommand.Run(HttpRequestData request,
IOptions options)
Sustainsys.Saml2.AspNetCore2.Saml2Handler+d__12.MoveNext()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__6.MoveNext()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware+d__4.MoveNext()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d__6.MoveNext()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+d__7.MoveNext()
I'm not understanding what does this mean. Am I missing something?
Here's what I have in the Startup file
services.AddAuthentication()
.AddSaml2(options =>
var spOptions = new SPOptions
EntityId = new EntityId("https://localhost:44373/Saml2"),
ReturnUrl = new Uri("https://localhost:44373"),
MinIncomingSigningAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
options.SPOptions = spOptions;
options.IdentityProviders.Add(new IdentityProvider(new EntityId("https://www.example.com/SSO/SAML/App"), options.SPOptions)
AllowUnsolicitedAuthnResponse = false,
MetadataLocation = "https://www.example.com/SSO/SAMLMetadata/App",
LoadMetadata = true,
Thanks in advance...
–
As far as I know, this error clearly states that audience that came in your SAML-token is different from the value in your Startup configuration. It might be helpful to compare these values. Sometimes the validation fails due to case-sensitive comparison, so you should pay attention in which case your audiencies are in token and configuration.
According to the source code (Saml2Response) and as Anders Abel pointed out, ValidAudience
property is initialized from SPOptions.EntityId
that you configure here:
var spOptions = new SPOptions
EntityId = new EntityId("https://localhost:44373/Saml2"),
ReturnUrl = new Uri("https://localhost:44373"),
MinIncomingSigningAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
So you should compare the EntityId
value, that you have configured with the value in your saml-token, which might look like this:
<saml:Audience>The value here should be the same as in your startup configuration</saml:Audience>
–
–
–
IDX10214
: Check this section if you are using Microsoft.Identity.Web
version 1.4.1 or similar and you get this exception (literally copied, and you have to change the log levels in appsettings.json
to get to see this):
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[1]
Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed. Audiences: 'System.String'. Did not match: validationParameters.ValidAudience: 'System.String' or validationParameters.ValidAudiences: 'System.String'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
at Microsoft.Identity.Web.Resource.RegisterValidAudience.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateAudience(IEnumerable`1 audiences, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Would be so much more helpful to actually see the value of those System.String
's. And if it didn't matter whether you use a GUID or something memorizable and readable.
Essentially you have to add the Audience
property to appsettings.json
and that must be equal to the Application ID URI
in the Azure portal. I had no luck whatsoever hacking the ClientId
and have that match the Application ID URI
. That isn't the final solution to this - AFAIK that must still be equal to the Application (client) ID
in the Azure portal, i.e. a GUID without any prefixes or suffixes.
–
–
in my case the issuer and audience for the JwtSecurityToken were omitted. In my derived class UserService: IUserService I defined the issuer and audience variables in the function generateJwtToken. They variables must match services.AddJwtBearer variables in the startup.csv for ValidIssuer and ValidAudience. see(https://dotnetcoretutorials.com/2020/01/15/creating-and-validating-jwt-tokens-in-asp-net-core/).
quote:
The Issuer and Audience are funny things because realistically, you probably won’t have a lot of use for them. Issuer is “who” created this token, for example your website, and Audience is “who” the token is supposed to be read by. So a good example might be that when a user logs in, your authentication api (auth.mywebsite.com) would be the issuer, but your general purposes API is the expected audience (api.mywebsite.com). These are actually free text fields so they don’t have to be anything in particular, but later on when we validate the issuer/audience, we will need to know what they are.
public class UserService : IUserService
private string generateJwtToken(long userId)
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.Secret));
var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
var tokenOptions = new JwtSecurityToken(
issuer: "http://localhost:5000",
audience: "http://localhost:5000",
claims: new List<Claim> {
new Claim(ClaimTypes.Name, userId.ToString()),
new Claim(ClaimTypes.Role, "Operator")
expires: DateTime.UtcNow.AddDays(7),
signingCredentials: signinCredentials
var tokenString = new JwtSecurityTokenHandler().WriteToken(tokenOptions);
return tokenString;
startup.cs
public void ConfigureServices(IServiceCollection services)
services.AddAuthentication(opt =>
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
.AddJwtBearer(opt =>
opt.RequireHttpsMetadata = false;
opt.SaveToken = true;
opt.TokenValidationParameters = new TokenValidationParameters
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidIssuer = "http://localhost:5000",
ValidAudience = "http://localhost:5000"
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.