Bearer error="invalid_token", error_description="The signature is invalid" - .net-core

I have a angular application that request a token from azure. The login went well and I get a token. This token is now send from the angular app to a net core webapi application. Net core should verify this token but failed. I think the webapi should also contact azure to validate the token because it has no knowledge of the private and public key that is needed to verify the token.
At the moment it is not clear why it is failing. Both angular app and the webapi are running local on my computer.
The error is: Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: 'IDX10500: Signature validation failed. No security keys were provided to validate the signature.'
my net core 2 config is:
var tokenValidationParameters = new TokenValidationParameters
{
RequireExpirationTime = true,
RequireSignedTokens = false,
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidIssuer = "8d708afe-2966-40b7-918c-a39551625958",
ValidateAudience = true,
ValidAudience = "https://sts.windows.net/a1d50521-9687-4e4d-a76d-ddd53ab0c668/",
ValidateLifetime = false,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Audience = "8d708afe-2966-40b7-918c-a39551625958";
options.ClaimsIssuer = "https://sts.windows.net/a1d50521-9687-4e4d-a76d-ddd53ab0c668/";
options.RequireHttpsMetadata=false;
options.TokenValidationParameters = tokenValidationParameters;
options.SaveToken = true;
});

That is quite a lot of configuration you have :)
The two mandatory settings are the Audience and Authority:
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(o =>
{
o.Audience = "8d708afe-2966-40b7-918c-a39551625958";
o.Authority = "https://login.microsoftonline.com/a1d50521-9687-4e4d-a76d-ddd53ab0c668/";
});
You are missing the Authority so it does not know where to load the signing public keys from.

You are missing IssuerSigningKey property in your TokenValidationParameters. Thats why its complaining.
The simplest example would be
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("yOURsECRETkEY12345"))
I'm not sure how azure comes into play, you probably need it to retrieve security key information, if thats your signing authority
Edit:
Azure specific settings
.AddJwtBearer(options => {
options.Authority = string.Format("https://login.microsoftonline.com/tfp/{0}/{1}/v2.0/", Configuration["Authentication:AzureAd:Tenant"], Configuration["Authentication:AzureAd:Policy"]);
options.Audience = Configuration["Authentication:AzureAd:ClientId"];
});

Related

.NET Core 6 Minimal API - check JWT authorize status

I am experimenting with .Net Core 6 Minimal APIs and using JWT authorization.
I've set up the 'standard' JWT builder service to add authentication and authorization
builder.Services.AddAuthentication(o =>
{
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ClockSkew = TimeSpan.Zero,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
builder.Services.AddAuthorization();
app.UseAuthentication();
app.UseAuthorization();
That works great and I can issue valid JWTs and then decorate endpoints with [Authorize] and get a 401 if the JWT is not valid.
What I want to do next is to use an endpoint without Authorize but then check the JWT and have some logic depending on its validity. Can I use the DI services (I'm not sure if these are triggered if the endpoint is not decorated [Authorize]) or do I need to manually check the JWT outside of the middleware?
Thanks

Having trouble with JWT token in ASP.NET Core app with multiple authentication schemes

I have an ASP.NET Core 2.0 app with both web pages and API. I'm using cookie authentication for web pages and now I want to use JWT Tokens for API methods.
I followed this article to set this up which does a pretty good job in walking us through the process: https://wildermuth.com/2017/08/19/Two-AuthorizationSchemes-in-ASP-NET-Core-2
I am, however, getting a strange response in my API method that I set up to use JWT token. When I hit the API method, I do get a Status 200 response in Postman but I never hit the break point I set up in the API method. More interestingly, Visual Studio debugger is showing a successful request and when I click it, I see a response code 302 even though Postman shows me a 200 -- see below:
Stranger still, the response I see in Postman is the HTML code of my login page which I redirect users to if they're not authenticated.
Here's my configuration for authentication. As you'll see below, I use social logins as well so my configuration is a bit long so I put all the configuration in a separate file in order not to clutter my Startup.cs. I simply call this from the ConfigureServices() method.
public static void MyAppAuthenticationConfig(IServiceCollection services, IConfiguration configuration)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "my_cookie";
options.DefaultChallengeScheme = "my_cookie";
})
.AddCookie("my_cookie", options =>
{
options.AccessDeniedPath = "/Home/Denied";
options.LoginPath = "/Login";
})
.AddCookie("social_auth_cookie")
.AddOAuth("LinkedIn", options =>
{
options.SignInScheme = "social_auth_cookie";
options.ClientId = "my_client_id";
options.ClientSecret = "my_secret";
options.CallbackPath = "/linkedin-callback";
options.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
options.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
options.UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,picture-url,picture-urls::(original))";
options.Scope.Add("r_basicprofile");
options.Scope.Add("r_emailaddress");
options.Events = new OAuthEvents
{
OnCreatingTicket = OnCreatingTicketLinkedInCallBack,
OnTicketReceived = OnTicketReceivedCallback
};
})
.AddFacebook(options =>
{
options.SignInScheme = "social_auth_cookie";
options.AppId = "my_app_id";
options.AppSecret = "my_secret";
options.Events = new OAuthEvents
{
OnCreatingTicket = OnCreatingTicketFacebookCallback,
OnTicketReceived = OnTicketReceivedCallback
};
})
.AddGoogle(options =>
{
options.SignInScheme = "social_auth_cookie";
options.ClientId = "my_id.apps.googleusercontent.com";
options.ClientSecret = "my_secret";
options.CallbackPath = "/google-callback";
options.Events = new OAuthEvents
{
OnCreatingTicket = OnCreatingTicketGoogleCallback,
OnTicketReceived = OnTicketReceivedCallback
};
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, jwtBearerOptions =>
{
jwtBearerOptions.RequireHttpsMetadata = false;
jwtBearerOptions.SaveToken = true;
jwtBearerOptions.Challenge = JwtBearerDefaults.AuthenticationScheme;
jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("my_secret_key")),
ValidateIssuer = true,
ValidIssuer = "myapp-api",
ValidateAudience = true,
ValidAudience = "myapp-client",
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
});
}
And this is the API method where I want to use JWT Token.
[HttpGet("testit")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult Test()
{
return Ok("Hello World!");
}
I have a break point where I return Ok("Hello World!"); but like I said I never hit it.
What am I doing wrong here?
UPDATE:
When I inspect the ChallangeResult("Bearer"), this is what I see:
And here's how I'm sending my request in Postman:

Catch ClaimsIssuer on asp.net core 2 ConfigureServices

I am looking a way to grab the value of Claim Issuer. I want to make 2 way validation of token.
First step user will get the token from System API and pass it to Customer API. In customer API token need to be validate with system API token parameter.
if it is validated customer api generate a new token to the user and user will use the new token in next steps.
I am doing this because in the second step I will add some claim for only that user have to see and use. like connection string, user role for its own database.
Or is there any other way to do like this verification ?
thanks.
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
if (????)
{
// system token validator
}
else
{
//customer token validator
}
});
Found a way to handle the problem
Just add two claim issuer and two key to validation parameter so I don't need to check anymore the claim issuer
var issuers = new List<string>()
{
Configuration["SystemToken:Issuer"],
Configuration["CustomerToken:Issuer"]
};
SecurityKey SystemKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SystemToken:Key"]));
SecurityKey CustomerKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["CustomerToken:Key"]));
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuers = issuers,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = new List<SecurityKey>() { SystemKey, CustomerKey },
ValidateLifetime = true
};
thanks you for helping
#Tratcher
https://github.com/aspnet/Security/issues/1604

Use only one authentication scheme (jwt bearer)

I am building an ASP.Net Core API and am using JWT for authentication.
I have the following configuration:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidateAudience = true,
ValidateIssuer = true,
ValidateActor = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
ValidIssuers = Global.Issuers,
ValidAudiences = Global.Audiences,
IssuerSigningKey = Global.symmetricSecurityKey
};
});
}
As you can see, I want to use JWT and only JWT.
For a few hours I was pulling my hair out trying to figure out why I was constantly getting a 401 on any actions with the [Authorize] attribute.
I finally ended up trying [Authorize(AuthenticationSchemes = "Bearer")] and it worked!
So what gives?!
How can i figure out what other authentication schemes are challenging?
Do I have to explicitly disable the default scheme (cookie)?
I would like to avoid having to specify the AuthenticationSchemes on all my Authorize tags.
Thanks!

Token validation stops working when using identity

I've added token (jwt) validation to my Web-API by following the steps in this tutorial. However, when I now try to add Asp.Net Identity to my application it somehow skips the token validation.
The token generation still works fine.
The API-controller-action that I am trying to access looks like this:
// GET api/users/5
[HttpGet("{id}")]
[Authorize]
public User Get(int id)
{
return _userService.FindById(id);
}
The "Authorize" attribute doesn't seem to make any difference after adding identity to my OWIN startup file, which looks like this:
var secretKey = "secret";
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
var audience = "aud";
var issuer = "iss";
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
ValidIssuer = issuer,
ValidateAudience = true,
ValidAudience = audience,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters
});
app.UseStaticFiles();
app.UseIdentity(); // When adding this the token-validation above seems to stop working...
var options = new TokenProviderOptions
{
Audience = audience,
Issuer = issuer,
SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
};
app.UseMiddleware<TokenProviderMiddleware>(Options.Create(options));
app.UseMvc();
I've tried moving the Identity middleware above JwtBearerAuth, with no luck.
It always seems to skip validating my token, and even if I leave out the token I am able to reach the action, but when I remove the Identity middleware the token-validation starts working again.

Resources