IDX10501: Signature validation failed. kid: '[PII is hidden]', token: '[PII is hidden]' - Azure B2C - c#

I have created a sample application where the user can authenticate with Azure B2C which works fine. I get back the Token and the AuthenticationResult. Both are Ok. But I want to get back the ClaimPrincipal from the token. To do this I have added the System.IdentityModel.Tokens.Jwt (5.4.0) nuget package to the project.
With the following code I try to achieve:
string Token = "eyJ0eXAiOiJKV1QiLCJhbGciO*****"; //long token
JwtSecurityTokenHandler jwt = new JwtSecurityTokenHandler();
var validateParams = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
{
ValidIssuer = Authority, //https://login.microsoftonline.com/tfp/MYTEANANTNAME.onmicrosoft.com/MYPOLICYNAME/v2.0/"
ValidAudience = clientId, //CLIENTID: Like: b430xxxx-xxxx-xxxx-xxxx-f5c33cxxxxxx
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuer = true,
};
SecurityToken secToken;
var claimPrincipal = jwt.ValidateToken(Token, validateParams , out secToken);
But all the time when the ValidateToken is hit it throws the following exception:
IDX10501: Signature validation failed. Unable to match keys:
kid: '[PII is hidden]',
token: '[PII is hidden]'.
Do you have any advice how I should resolve this issue?
In this case the application is a .net core console app, but in the end this code will be in an WPF application.

Related

Ignore JWT Bearer token signature (i.e. don't validate token)

I have an API that sits behind an API Gateway. The API Gateway validates the bearer token before passing the request along to the API.
My API the uses the the asp.net core 2.0 native authentication and claims based authorization framework. The grunt work of getting the claims from the JWT token is done by the middleware in Microsoft.AspNetCore.Authentication.JwtBearer.
This middle ware can be configured to ignore the expiration date on the token and it is also possible to specify a local public key so it is not necessary to contact the token Authority to obtain one, but is it possible to just disable the signature validation on the token?
This would allow use of unsigned tokens for ad-hoc testing in development and prevent double validation (gateway and then API) in production.
Try this. Finally, I got it to work after so much of trying.
public TokenValidationParameters CreateTokenValidationParameters()
{
var result = new TokenValidationParameters
{
ValidateIssuer = false,
ValidIssuer = ValidIssuer,
ValidateAudience = false,
ValidAudience = ValidAudience,
ValidateIssuerSigningKey = false,
//IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey)),
//comment this and add this line to fool the validation logic
SignatureValidator = delegate(string token, TokenValidationParameters parameters)
{
var jwt = new JwtSecurityToken(token);
return jwt;
},
RequireExpirationTime = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
};
result.RequireSignedTokens = false;
return result;
}
You may setup token validation using JwtBearerOptions.TokenValidationParameters. You could check all available parameters from the class definition.
Contains a set of parameters that are used by a Microsoft.IdentityModel.Tokens.SecurityTokenHandler when validating a Microsoft.IdentityModel.Tokens.SecurityToken.
Set All ValidateXXX and RequireXXX bool properties to false if you want to disable validation at all:
.AddJwtBearer("<authenticationScheme>", configureOptions =>
{
options.TokenValidationParameters.ValidateActor = false;
options.TokenValidationParameters.ValidateAudience = false;
options.TokenValidationParameters.ValidateIssuerSigningKey = false;
...
}
As an another option you can override the default token signature validation by setting own implementation to JwtBearerOptions.SignatureValidator:
// Gets or sets a delegate that will be used to validate the signature of the token.
//
// Remarks:
// If set, this delegate will be called to signature of the token, instead of normal
// processing.
public SignatureValidator SignatureValidator { get; set; }
where SignatureValidator delegate is defined as:
public delegate SecurityToken SignatureValidator(string token, TokenValidationParameters validationParameters);

Manually validating a JWT token in C#

I am having some trouble manually validating a JWT token issued by Identity Server 4. Using the
ClientId: "CLIENT1"
ClientSecret: "123456"
The exception I keep getting is: IDX10501: Signature validation failed. Unable to match keys: '[PII is hidden by default. Set the 'ShowPII' flag in IdentityModelEventSource.cs to true to reveal it.]'
Is anyone able to advise me where I am going wrong.
private static void ValidateJwt(string jwt, DiscoveryResponse disco)
{
var parameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidIssuer = disco.Issuer,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("123456")),
ValidAudience = "CLIENT1",
//IssuerSigningKeys = keys,
// ValidateAudience = true,
// ValidateLifetime = true,
};
SecurityToken validatedToken;
var handler = new JwtSecurityTokenHandler();
handler.InboundClaimTypeMap.Clear();
try
{
var user = handler.ValidateToken(jwt, parameters, out validatedToken);
}
catch(Exception ex)
{
var error = ex.Message;
}
}
Check out ValidateJwt() in this sample:
https://github.com/IdentityServer/IdentityServer4.Samples/blob/master/Clients/src/MvcManual/Controllers/HomeController.cs
The bit you're missing is loading the public key from the discovery document.
Try changing the length of your private key. Your private key is too small to be encoded I suppose.
IdentityServer signs the JWT using RS256. This means you need to use a public key to verify the JWT (you can get this from the discovery document).
The client id & client secret are client credentials used for requesting tokens. They have no part in validating them.
You are trying to use SymmetricKey for JWT validation. Try looking your token in JWT.io and if algorithm is"RS256" then SymmetricKey won't work.
You have specified:
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret"))
but the JwtSecurityTokenHandler could not match it with the key which can be part of jwt header itself. Basically it means that your configuration has mismatch[es] with configuration of the real issuer. The error suggests that this relates to the signature keys.
Please, check the configuration of that issuer (if you can), find out missed parts, and try again.
You can use jwt.io to debug your jwt online.

IDX10501: Signature validation failed. Key tried: 'System.IdentityModel.Tokens.X509AsymmetricSecurityKey'

I am trying to validate a token from Azure. I used Adal.js to get the token.
When I try to validate the token I always get the same error message every time:
IDX10501: Signature validation failed. Key tried: 'System.IdentityModel.Tokens.X509AsymmetricSecurityKey'.
token: '{"typ":"JWT",...
The token omitted from the message looks like what I can see on the client, and the information from the following 3 urls seems to be added into the data structures correctly, i.e. where I can see fields populated it is what I expect from looking at the links below and my token on the client.
https://login.windows.net/{id}.onmicrosoft.com/federationmetadata/2007-06/federationmetadata.xml
https://login.microsoftonline.com/{id}.onmicrosoft.com/.well-known/openid-configuration
https://login.microsoftonline.com/common/discovery/keys
But whenever I reach the final line ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(... I always get the same error.
Any ideas one how to make the token validate?
// Get the jwt bearer token from the authorization header
string jwtToken = null;
AuthenticationHeaderValue authHeader = request.Headers.Authorization;
if (authHeader != null)
{
jwtToken = authHeader.Parameter;
}
string issuer;
List<SecurityToken> signingTokens;
// The issuer and signingTokens are cached for 24 hours. They are updated if any of the conditions in the if condition is true.
if (DateTime.UtcNow.Subtract(_stsMetadataRetrievalTime).TotalHours > 24 || string.IsNullOrEmpty(_issuer) || _signingTokens == null)
{
// Get tenant information that's used to validate incoming jwt tokens
string stsDiscoveryEndpoint = string.Format("{0}/.well-known/openid-configuration", authority);
ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint);
OpenIdConnectConfiguration config = await configManager.GetConfigurationAsync();
_issuer = config.Issuer;
_signingTokens = config.SigningTokens.ToList();
_stsMetadataRetrievalTime = DateTime.UtcNow;
}
issuer = _issuer;
signingTokens = _signingTokens;
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters
{
ValidAudience = audience,
ValidIssuer = issuer,
IssuerSigningTokens = signingTokens,
CertificateValidator = X509CertificateValidator.None
};
try {
// Validate token.
SecurityToken validatedToken = new JwtSecurityToken();
ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwtToken, validationParameters, out validatedToken);
}
Update
Just incase there's something I'm missing when initializing the client and server.
Adal.js init options are:
var endpoints = {
"https://graph.windows.net": "https://graph.windows.net"
};
var configOptions = {
tenant: "<ad>.onmicrosoft.com", // Optional by default, it sends common
clientId: "<app ID from azure portal>",
postLogoutRedirectUri: window.location.origin,
endpoints: endpoints,
}
window.authContext = new AuthenticationContext(configOptions);
Server init options are:
static string aadInstance = "https://login.microsoftonline.com/{0}";
static string tenant = "<ad>.onmicrosoft.com";
static string audience = "<app ID from azure portal>";
string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
static string scopeClaimType = "http://schemas.microsoft.com/identity/claims/scope";
What scenario are you trying to implement? The token you have is for AAD Graph API, you don't need to validate it. When performing api calls with that token, microsoft graph server side will validate the access token.
In addition, in your server side init options, you set the audience to app ID from azure portal, which means that when validating the access token, the audience of access token should match app ID from azure portal, but audience of access token is https://graph.windows.net since you are acquiring token for Azure AD Graph api.
If the access token is for your own api, you need to validate the access token in your api, you could use OWIN middleware to process the token:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Audience = ConfigurationManager.AppSettings["ida:Audience"],
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
});
or manually validating the JWT token like this code sample .

ASP.Net 5 - OAuth bearer token (JWT) validation error

I have been working on a system to authenticate and authorize users on my website using JSON Web Tokens. My system is just about completed, but I am running into an error when I attempt to use the [Authorize("Bearer")] attribute in my code. The error is as follows:
System.IdentityModel.Tokens.SecurityTokenInvalidSignatureException occurred
Message: Exception thrown: 'System.IdentityModel.Tokens.SecurityTokenInvalidSignatureException' in Microsoft.IdentityModel.Logging.dll
Additional information: IDX10503: Signature validation failed. Keys tried: ''.
Exceptions caught:
''.
token: '{"typ":"JWT","alg":"RS256","kid":null}.{"nameid":"6581f5a0-1775-4ce4-8650-a3d7e613b216","unique_name":"alex","AspNet.Identity.SecurityStamp":"8da933c3-0f88-42ea-876d-c07e99d1eecc","iss":"Uniti","aud":"Uniti","exp":1436849284,"nbf":1436845684}'
I don't understand why it isn't testing any keys with the JWT. I have an RSA key defined in my startup file. Without further dragging this on, I have provided the code that may be necessary to solve this error below.
My startup code (generating key and OAuthBearer options):
#region RSA Key Generation
var rsa = new RSACryptoServiceProvider(2048);
var rsaKey = rsa.ExportParameters(true);
var key = new RsaSecurityKey(rsaKey);
services.AddInstance(new SigningCredentials(key, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest));
#endregion
services.AddInstance(new OAuthBearerAuthenticationOptions
{
SecurityTokenValidators = new List<ISecurityTokenValidator>
{
new JwtSecurityTokenHandler()
},
TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = key,
ValidIssuer = "Uniti",
ValidAudience = "Uniti"
},
});
services.AddAuthorization();
services.ConfigureAuthorization(auth =>
{
auth.AddPolicy("Bearer", builder =>
{
builder.AddAuthenticationSchemes(OAuthBearerAuthenticationDefaults.AuthenticationScheme);
builder.RequireAuthenticatedUser();
});
});
My token generation code:
var claimsIdentity = (ClaimsIdentity) User.Identity;
var handler = BearerOptions.SecurityTokenValidators.OfType<JwtSecurityTokenHandler>().First();
var securityToken = handler.CreateToken(
issuer: "Uniti",
audience: "Uniti",
signingCredentials: BearerCredentials,
subject: claimsIdentity
);
var token = handler.WriteToken(securityToken);
Am I forgetting to add something somewhere, or am I generating the keys incorrectly? Thanks ahead of time if you can help me!
I bet it's due to the incorrect way of registering the OAuth2 bearer options, as already explained in my previous answer: https://stackoverflow.com/a/31322654/542757
services.AddInstance(new OAuthBearerAuthenticationOptions());
When you use services.AddInstance, the OAuth2 bearer middleware is unable to retrieve the options (and thus, the key), as it internally uses IOptions<OAuthBearerAuthenticationOptions> and not OAuthBearerAuthenticationOptions.
This is the correct way to register the OAuth2 bearer options:
services.ConfigureOAuthBearerAuthentication(options => {
// Configure the options used by the OAuth2 bearer middleware.
});

Validate Live.com (Microsoft account) JWT token

Fellow programmers,
I'm currently struggling with Microsoft account JWT token validation in Web Api 2.
I've found OWIN middleware for that (NuGet package Microsoft.Owin.Security.Jwt) and here is the code from my Startup.cs configuring that:
public void ConfigureAuth(IAppBuilder app)
{
var sha256 = new SHA256Managed();
var secretBytes = System.Text.Encoding.UTF8.GetBytes(#"(My app client secret)" + "JWTSig");
byte[] signingKey = sha256.ComputeHash(secretBytes);
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AllowedAudiences = new[] { "(My API's domain )" },
IssuerSecurityTokenProviders =
new[]
{
new SymmetricKeyIssuerSecurityTokenProvider(
"urn:windows:liveid", signingKey)
}
});
}
I've found that snippet here:
http://code.lawrab.com/2014/01/securing-webapi-with-live-id.html
The JWT token is sent from my Windows Store app client using Live SDK. I'm sending the authentication token, not access token, so I'm sure it's JWT. Using online debuggers like this one: http://jwt.io/ I'm able to successfully decode the header & payload part, but I cannot find a way to validate the signature. The debug output from my Web API when a request with that JWT is sent is:
Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Error: 0 : Authentication failed
System.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = System.IdentityModel.Tokens.NamedKeySecurityKeyIdentifierClause
)
',
token: '{"alg":"HS256","kid":"0","typ":"JWT"}.{"ver":1,"iss":"urn:windows:liveid","exp":1408666611,"uid":"my Microsoft account uid","aud":"(My API's domain)","urn:microsoft:appuri":"ms-app://(client app store id)","urn:microsoft:appid":"(ID of the app from account.live.com/developers)"}
RawData: (the JWT token)'.
w System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
w System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateToken(String securityToken, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
w Microsoft.Owin.Security.Jwt.JwtFormat.Unprotect(String protectedText)
w Microsoft.Owin.Security.Infrastructure.AuthenticationTokenReceiveContext.DeserializeTicket(String protectedData)
w Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationHandler.d__0.MoveNext()
Sorry for my english, any corrections are more than welcome.
One of the Easiest way I can use , is to validate it from the Source itself.
in your case right now you are using live.com , then send one request to live.com and use your token in the header and if it's a valid header it will return the known value (ex. user account information)
choose a url like this :
https://outlook.live.com/ows/v1.0/OutlookOptions
and send the token in the header as Authorization: Bearer TOKEN_VALUE
if it returned the expected value , then it's a valid token and the session also is working

Resources