I am new JWT in DOTNet core web Api. In our application, we are getting access_token from the Microsoft site. https://login.microsoftonline.com/
We would like to validate the token (RS256 algo) in the .net core (Api) but we don't have the PUBLIC KEY.
Note: I already have a token. How can we validate JWT with our public key and any other thing? I only have an access token.
With JWT you basically have two scenarios:
you created your JWT yourself and you know the keys used for it. Than you can write the validation, or pass the parameters to .net core pipeline.
you got the JWT from external authority. In this case the authority (in your particular case - Microsoft) knows how to validate the JWT.
Authority will implement the JWT protocol and expose it via a URL. Normally you need to know two things: authority and audience (recipient of the token).
Now good news is that .net core handles the protocol details for you, all you need to do is to set up the authentication pipeline. This is what it boils down to:
services.AddAuthentication()
.AddJwtBearer("schemeName", options =>
{
options.Audience = "your audience";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "your domain",
ValidateAudience = true,
ValidAudience = "your audience",
ValidateIssuerSigningKey = true,
IssuerSigningKeys = jwks, // use "Keys" as JsonWebKeySet or "Key" (below), just one of them
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)), // your encoding etc may differ
RequireSignedTokens = true,
RequireExpirationTime = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
ValidAlgorithms = new[] { SecurityAlgorithms.EcdsaSha256, }, // your algorithm may differ
};
})
For details, do some reading on JWT authentication in .net core, e.g. JWT Validation and Authorization in ASP.NET Core. There are a lot of articles on the topic.
Related
We are using ASP.NET Zero based on ASP.NET Boilerplate (.NET Core). We have a Mobile App that authenticates with AWS Cognito and needs to consume some API's and Application Services on our application. (We already make sure that each user in Cognito also has a corresponding user in AbpUsers with permissions.)
The Mobile App will authenticate with a JWT Bearer Token from Cognito. We have added JWT Validation to our Startup.cs as follows:
services.AddAuthentication(options => {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options => {
options.ClaimsIssuer = CognitoIssuer;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
var json = new WebClient().DownloadString(CognitoIssuer + "/.well-known/jwks.json");
var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(json)!.Keys;
return keys;
},
RoleClaimType = "cognito:groups",
NameClaimType = "username",
ValidIssuer = CognitoIssuer,
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidateAudience = false
};
});
This validation works in so far as when I decorate an API with the [Authorize] attribute, the API only executes if a valid JWT token is provided. (With an invalid token, a 401 error is returned as expected.)
The problem we have is that the user identity is not being set. I can see that the Claims Principal contains the claims from Cognito. But inside the API the current user and tenant appears as NULL. I assume that after JWT validation I'm missing steps to "map" the claims/user from Cognito to an actual user that exists in the ABP database so that the AbpSession can reflect this user. But how do I do that? How do I set the Identity/User/Tenant/AbpSession so that it can correctly and seamlessly be picked up in my Application Services and Controllers after I've validated the JWT token? (So that Application Services and Controllers can work just as seamlessly as if the user had actually logged on in the ABP app?)
I have an Owin client connected to IdentityServer 4, and am wondering how to get owin to request a new access_token using the refresh token. I can successfully get owin to swap the code given for an access_token, id_token and refresh_token with the following configuration:
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookie"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "http://localhost:5000",
ClientId = "mywebsite",
ClientSecret = "secret",
RedirectUri = "https://localhost:5001/",
ResponseType = "code",
RequireHttpsMetadata = false,
SaveTokens = true,
UseTokenLifetime = true,
SignInAsAuthenticationType = "Cookie",
Scope = "openid profile email offline_access",
RedeemCode = true,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = n =>
{
Console.WriteLine(n);
return System.Threading.Tasks.Task.FromResult(0);
},
TokenResponseReceived = n =>
{
Console.WriteLine(n);
return System.Threading.Tasks.Task.FromResult(0);
}
},
});
}
Firstly, where do I save these tokens to? I can access them all the SecurityTokenValidated callback - should they go into the claims? Database? Memory?
Secondly, I have on my IdentityServer client configuration the access_token lifespan set to 60s, identity_token set to 3600s, and refresh to 30 days (please note the access_token is only this short for testing purposes). So how can I configure Owin to recognize that the access_token has expired and that it needs to go back to identityserver with the refresh_token and get a new one. Answers with example code snippets would be appreciated as my knowledge on all this is very small.
Relevant Info:
IS4 v3
.Net Framework v4.6
Client is set in IS to allow offline access
Take a look at this article:
Automatic Token Management for ASP.NET Core and Worker Services 1.0
Otherwise than that there is no logic in the AddOpenIdConnect(..) handler to deal with renewal of refresh tokens. I think its up to your application to refresh them. Refreshing them in code is not that hard if you have saved the refresh token somewhere safe.
See this question How to use 'refresh_token' in IdentityServer 4?
I would like to use a .Net Core 3.1 web app to allow an app (e.g. iPhone or Web Javascript) to authenticate with a username and password and receive a Jason Web Token (JWT) that contains claims about the user... if it succeeds, then the JWT can be sent as a bearer token to an API that would decode and validate the JWT (the token would be asymmetric and use a public/private key pair) and retrieve any claims that are embedded... perhaps a bonus if the app could decode the JWT as well in order to retrieve any claims.
Any thoughts on if this approach is possible? And, if there are any discussions or examples of how this might be done, that would be terrific.
Take a look at the examples that IdentityServer4 is providing. This sample/quickstart includes the case you are describing. https://github.com/IdentityServer/IdentityServer4/tree/main/samples/Quickstarts/6_AspNetIdentity/src
The API needs to be a scope in the IdentityServer4 configuration. It has a connection with the authority (IdentityServer4):
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:5001";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
The Client, in this example an MVC Client, needs to be a client in IdentityServer4. There are many types of GrantTypes. https://identityserver4.readthedocs.io/en/latest/topics/grant_types.html
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code";
options.Scope.Add("api1");
options.SaveTokens = true;
});
Hope this helps you out
I have an ASP .Net Core API Project. In this project I am using JWTBearer Authentication. I am also using the AddDistributedRedisCache feature of the .Net Core Dependency Injection. (Both shown below)
We have a need to blacklist the tokens on occasion (Admin user removing rights, logout, etc) so that these can take immediate effect. Essentially forcing a user to log back in before the next call can be made.
We are adding the JWT Tokens to the redis cache as well as removing them from the client side cache on logout. But a user could (in theory) store the JWT token, and still gain access until the token expires, unless we intercept the call and check it against the blacklist.
How can I access the distributed cache object in the "OnTokenValidated" event in the code below? Do I have to manually create a new connection each time? We are only checking valid tokens, as that will stop invalid requests from even being checked against the blacklist.
Bearer Token Config:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "localhost:5000",
ValidAudience = "localhost:5000",
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(Configuration.GetValue<string>("SigningKey"))),
};
options.Events = new JwtBearerEvents
{
OnTokenValidated = context => {
//context.Fail("User has been logged out");
return Task.CompletedTask;
}
};
});
Redis Cache Config:
services.AddDistributedRedisCache(option =>
{
option.Configuration = Configuration.GetValue<string>("RedisCacheAddress");
option.InstanceName = Configuration.GetValue<string>("RedisCacheInstance");
});
You can access services in DI utilizing the HttpContext available there:
OnTokenValidated = ctx =>
{
var cache = ctx.HttpContext.RequestServices.GetRequiredService<IDistributedCache>();
return Task.CompletedTask;
}
GetRequiredService will throw an exception if the service is not found. You can use GetService<T>() if you want the service to be optional.
I'm converting a ASP.NetCore project to a stateless Web Api one. I was using the following to authenticate my JWT:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = key,
ValidIssuer = "http://localhost:5000",
ValidAudience = "http://localhost:5000/resources",
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(0)
}
});
And then Authorizing a controller using [Authorize("Bearer")]
However, I've noticed the OWIN project uses a different Authorize and Filters? I've not been able to successfully authorize my JWT using this and HostAuthentication.
Is this possible?