I’ve recently been using JWT Tokens as my authentication method of choice for my API’s. And with it, I’ve had to do battle with various pieces of documentation on how JWT token authentication and authorization actually work in .NET Core / ASP.NET.
Primarily, there is a lot of documentation on using ASP.NET Identity to handle authentication/authorization. So using the big bloated UserManager and using the packaged attributes like [Authorize] etc. However, I always get to a point where I just need a bit more custom flexibility, that the out of the box components don’t provide. And when it comes to how to *manually* create JWT Tokens and validate them later on, the documentation is a little slim. Infact some guides show you how to manually create the token, but then tell you to use the out of the box components to validate it which creates confusion as to what you’re actually doing. So here’s hoping this article clears some things up!
Creating JWT Tokens In C# .NET
Let’s first take a look at how to create JWT tokens manually. For our example, we will simply create a service that returns a token as a string. Then however you return that token (header, response body etc) is up to you. I’ll also note in the following examples, we have things like hardcoded “secrets”. I’m doing this for demonstration purposes but quite obviously you will want these to be config driven. You should take the following as a starting point, and then modify it to be production ready.
The code to generate a JWT Token looks like so :
public string GenerateToken(int userId) { var mySecret = "asdv234234^&%&^%&^hjsdfb2%%%"; var mySecurityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(mySecret)); var myIssuer = "http://mysite.com"; var myAudience = "http://myaudience.com"; var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.NameIdentifier, userId.ToString()), }), Expires = DateTime.UtcNow.AddDays(7), Issuer = myIssuer, Audience = myAudience, SigningCredentials = new SigningCredentials(mySecurityKey, SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); }
Let’s walk through this bit by bit.
I have a security key which is essentially used to “sign” the token on it’s way out. We can verify this signature when we receive the token on the other end to make sure it was created by us. Tokens themselves are actually readable even if you sign them so you should never put sensitive information in them. Signing simply verifies that it was us who created the token and whether it’s been tampered with, but it does not “encrypt” the token.
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.
We are creating the token for 7 days, but you can set this to anything you want (Or have it not expire it at all), and the rest of the code is just .NET Core specific token writing code. Nothing too specific to what we are doing. Except for claims…
Explaining Claims
Claims are actually a simple concept, but too many articles go into the “abstract” thought process around them. In really simply terms, a claim is a “fact” stored in the token about the user/person that holds that token. For example, if I log into my own website as an administrator role, then my token might have a “claim” that my role is administrator. Or put into a sentence “Whoever holds this token can claim they are an admin”. That’s really what it boils down to. Just like you could store arbitrary information in a cookie, you can essentially do the same thing inside a JWT Token.
For example, because a claim “type” is simply a free text field, we can do things like :
Subject = new ClaimsIdentity(new Claim[] { new Claim("UserRole", "Administrator"), })
Notice how we don’t use the “ClaimTypes” static class like we did in the first example, we simply used a string to define the claim name, and then said what the claim value was. You can basically do this for any arbitrary piece of information you want, but again remember, anyone can decode the JWT Token so you should not be storing anything sensitive inside it.
I’ll also note that a great pattern to get into is to store the claim types as static consts/readonly. For example :
public static readonly string ClaimsRole = "UserRole"; [...] Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimsRole, "Administrator"), })
You are probably going to need that ClaimType string in multiple places, so it’s better to set it once and reuse that static variable everywhere.
Validating A Token
So once you’ve created the token, the next step would be to validate it when a user sends you one. Now personally I like sending it inside a header like x-api-token, but because it’s simply a string, you can send it any which way you like. Because of that, let’s make our example method simply accept a token as a string and validate it.
public bool ValidateCurrentToken(string token) { var mySecret = "asdv234234^&%&^%&^hjsdfb2%%%"; var mySecurityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(mySecret)); var myIssuer = "http://mysite.com"; var myAudience = "http://myaudience.com"; var tokenHandler = new JwtSecurityTokenHandler(); try { tokenHandler.ValidateToken(token, new TokenValidationParameters { ValidateIssuerSigningKey = true, ValidateIssuer = true, ValidateAudience = true, ValidIssuer = myIssuer, ValidAudience = myAudience, IssuerSigningKey = mySecurityKey }, out SecurityToken validatedToken); } catch { return false; } return true; }
You’ll notice that I’ve had to copy and paste the security keys, issuer and audience into this method. As always, this would be better in a configuration class rather than being copied and pasted, but it makes the example a little easier to read.
So what’s going on here? It’s pretty simply actually. We create a TokenHandler which is a .NET Core inbuilt class for handling JWT Tokens, we pass it our token as well as our “expected” issuer, audience and our security key and call validate. This validates that the issuer and audience are what we expect, and that the token is signed with the correct key. An exception is thrown if the token is not validated so we can simply catch this and return false.
Reading Claims
So the final piece of the puzzle is reading claims. This is actually fairly easy assuming we have already validated the token itself.
public string GetClaim(string token, string claimType) { var tokenHandler = new JwtSecurityTokenHandler(); var securityToken = tokenHandler.ReadToken(token) as JwtSecurityToken; var stringClaimValue = securityToken.Claims.First(claim => claim.Type == claimType).Value; return stringClaimValue; }
Read the token, go to the claims list, and find the claim with the matching type (remembering the claimType is simply a freetext string), and return the value.
What About AddAuthentication/AddJwtBearer?
So you might have read documentation that uses the following code :
services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { x.TokenValidationParameters = new TokenValidationParameters(); });
Or some variation with it that sets up the token validation parameters with signing keys, audiences and issuers. This only works if you are using the default Authorize attribute. These settings are a way for you to configure the inbuilt ASP.NET Core authorization handlers. It does not set any global settings for JWT Tokens if you are creating/validating them yourself.
Why do I point this out? I’ve seen people manually validating tokens and *not* validating the signing key. When I ask why they are not validating that the token is signed correctly, they have assumed that if they call AddJwtBearer with various settings that these also pass down anytime you call new JwtSecurityTokenHandler() . They do not!
Can I ask a question ?.
What will happen if I copy the Token and Paste it in another Browser ?.
It will work 100%. If that’s a negative for you, ask what would happen if you copied a cookie into another browser? Cookie or Tokens being stolen essentially amounts to the same thing, impersonation of another user. Theoretically you could do things like store an “IP” claim that is then validated on the server, but I’m not sure this would be a good idea.
If you specify the audience when creating the SecurityTokenDescriptor, at the point you generate a token, then hold a list of allowed audiences in your settings when you setup the TokenValidationParameters then you can limit where the token can be used. You can have a check when validating the token by getting the request scheme and host and checking it matches the token claims for the audience.
For example:
User requests a token and the audience in SecurityTokenDescriptor is set to : $”{_accessor.HttpContext.Request.Scheme}://{_accessor.HttpContext.Request.Host.Host}/”
This will be the users scheme and host name, such as https://i.p or hostname, you can even use the machine name if the i.p address can change.
When the token validation parameters are created you can sepcify the audiences allowed as a pre-defined list of allowed machine names or i.p addresses. This limits where the token can be used from.
Hope that makes sense.
May you have the code because I’ve been trying to do something to use with JWT and Roles but it doesn’t work, can you help me with that
If you are doing a completely custom implementation, you can just add a custom Claim with role and then check it on the filter.
Dude this is a great POST! amazing thank you very much, I was looking for an example simple as this. The rest of the examples on the internet are just too complicated, this is exactly what I was looking for.
This was exactly what I was looing for! Thanks so much!
When do we call the ValidateToken() method? Also I’m receiving this error
***EXCEPTION***
Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. No security keys were provided to validate the signature. at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters) in C:\agent1\_work\109\s\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 979
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken) in C:\agent1\_work\109\s\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 722
at Microsoft.Owin.Security.Jwt.JwtFormat.Unprotect(String protectedText)
at Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationHandler.d__3.MoveNext()Diagnostics Context
Any clue why this occurs and how it can be fixed?
Are you passing in the correct security key?
So in this method here :
If you think you are, debug and make sure it’s not blank etc.
The correct security key is passed, the method returns true as well, but I still receive this error and I’m not quite sure where and when it is being thrown. So I wanted to confirm when is the right time to call ValidateCurrentToken() ?
How do you mean it returns true? If it returns true, then it’s validated. Maybe throw up a quick POC on GIT and I can take a quick look for you. Or you can email the code to me at wade (at) dotnetcoretutorials.com
How can i validate the token on another api, best practice is not to store identity on the same server correct?
server 1 = identity, creates token and sends to client
server 2 = web api, with protected [authorize] endpoints
would you add the ValidateCurrentToken() to the middleware of the of server 2?
Yep.
You do not need to store the token anywhere, you can just send it with every request and validate it on the other end.
I found the answer in this question: https://stackoverflow.com/questions/67663848/idx10503-signature-validation-failed-token-does-not-have-a-kid-keys-tried-s
IN summary, to generate the issuer signin key (symmetric key) from the secret use the following function:
var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(key));
Hello.
Why not to store the security key in the appsetings.json?
is it better your way?
kindly asked
The security key should be in some sort of config (Preferably something like KeyVault etc). However for this example I don’t want to confuse where I’m pulling the configuration from so I just hardcoded it.
You should be able to validate against the application registered stuff by utilizing an IOptions class from the container for the configuration, something like this (untested):
I’m trying to validate a token created using Microsoft.Identity.Client in a mobile app. The token is passed in a header to a REST api. In the REST API, I need to validate the token. I’ve copied the example for Validating a Token (above) and substitued my own token, tenant ID, audience (app id), issuer and secret. It does not work. I get back this error:
kid: ‘System.String’.
Exceptions caught:
‘System.Text.StringBuilder’.
token: ‘System.IdentityModel.Tokens.Jwt.JwtSecurityToken’.
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
Can’t see what I’m doing wrong or differently except that perpaps the audience and/or the issuer might be wrong? For a mobile app, I thought these were supposed to be the app id and the tenant id, respectively.
I’m using this for the issuer:
$”https://login.microsoftonline.com/{myTenant}/v2.0″;
And the audience is just my app id.
My “token” validates just fine here : https://jwt.ms/
Any ideas as to what might be wrong?
Are you sure that your token “validates” just fine at jwt.ms? Or it’s just read OK because any JWT token can be opened, and it’s weather it’s signed correctly is the question.
Just reading between the lines, it seems that you are using Azure B2C or similar as a login? That’s fine, but for those tokens I don’t believe you are supposed to validate them yourself, and you are supposed to use a library that will validate the token with the Microsoft API.
If you want to. Upload your code and email me at wade[at]dotnetcoretutorials.com and I’ll see if I can take a squiz.
Hi, thanks for the post, it is very simple. Just one question could you please also show an API controller example to understand how to authorize with this code?
This is a puzzle for me, I can’t join all the explained pieces, you have an example project, please
Fantastic concise explanation! Setting this up for my first time and this was super helpful and carifying.
What libraries are needed for the code to work. I have installed System.IdentityModel.Tokens.JWT for my Azure Functions code, but not working (e.g. SymmetricSecurityKey and other classes not found). Should I be using a different library ??
This is an old question but maybe the answer could help someone else coming here…
I did a POC in .NET6 and have the following usings:
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
Thanks 🙂
I wanted to thank you for a the exact post I was looking for. Like you say, everything is SO BLOATED with examples of IdentityServer, which is now deprecated in favor of a paid solution. I simply wanted to see a secure-‘ish way to create tokens for my app that all of 5 people use! I was almost just going to go with a long random string as a token, but this is much better. Thank you again, very clear and easy to follow.
Thank you so, so, so much! I was very much in need of a simple but effective tutorial like this. You saved me hours of frantic searching today.
Using this how do you validate an Azure token with a secret key? The website gets the token from Azure authentication and I can validate using your method without any issue. But how to make use of this secret key mechanism? Should we have something in Azure as well? Can you please help explain this scenario?
It depends what you mean by Azure Token? You mean Azure AD? For that you need to use MSAL.NET (https://www.nuget.org/packages/Microsoft.Identity.Client/) for example. If you are consuming a token generated elsewhere, then I strongly suggest you use their library to validate the tokens. This guide is mostly meant if you are generating and consuming your own tokens.
Hey Wade thanks for sharing this article, however i do have a doubt in my scenario, i do have 2 webapps in azure, webapp 1 hosts the frontend app and is authenticated through Azure B2C and call the WebAPI hosted in web app2. Now i need to validate this access token in WebAPI.
So when i validate this access token in webapi do i need to check client id and secret keys exclusively or your above code should do the job ?
Thanks.
Hi there,
No if you are using Azure B2C, you should use the libraries provided by Microsoft to validate tokens.
This code is only applicable if you are generating and validating your own tokens.
Nice article but have one question if any one can answer
can we do custom authertication in .net 5 as we do in Asp.Net 4.8 or 4.7 with OAuth and JWT, creating custom providers, as per below sample
You have also created custom class to generate token and validate token, but how to use or add those in statup or how we can add custom providers in startup
Thanks
Yes you can use custom providers etc.
The reason I wrote code to create and validate custom tokens is if you need something outside of the usual OAuth flow. For example, I needed to create a JWT token to be signed when calling another API of mine. Rather than work a full OAuth flow, I can issue and validate my own tokens.
Thanks for reply.
Please tell me how we can use custom tokens (validate custom tokens you have created like JwtTokenService ) or custom providers I have created, as I don’t know how to use or register those in startup file.
Thanks
how can i store the token over app without having a conflict with another token for a different user?
Thanks for taking the time out to show us this, very useful. Just one question that was asked by others, when and how do you call ValidateCurrentToken() ? In the Controller ? In the pipeline?
Thanks
It really depends on your use case. For me, I was using JWT for a very specific piece of data that I was transferring between applications, so I called ValidateToken in my controller/service etc.
Why did you store Claims in the Subject property of the SecurityTokenDescriptor instead of storing Claims on the Claims property of the SecurityTokenDescriptor?
I’m also wondering and trying to understand that for 30mins already.
SecurityTokenDescriptor.Subject contains 1 claim. SecurityTokenDescriptor.Claims is a collection of claims. if you read the docs you will see it doesn’t matter which one you use as they will be combined when creating the token. In this case it is better to use SecurityTokenDescriptor.Subject so you don’t need to create a Dictionary with 1 item in it.
I have multiple APIs, let say:
https://api1.mywebsite.com/
https://api2.mywebsite.com/
https://api3.mywebsite.com/
If I have the code for generating the token in “api1” – what value should I set the “audience” to in order to allow it to be used for Authentication on api1/api2/api3?
Thanks!
It’s actually completely up to you *as long* as the audience matches. So if you are generating the token in API1, and want the token to *only* be used for API2, then the audience needs to be something like “api2”. But if the audience is really just “any of my API’s”, then you can just set it to any string of your choosing, as long as on the other side they are using that same audience string.
Thanks for the article, easy to get everything working here. Kudos!
Thanks a lot for this article. It helped me finally understand the token configuration.
Hi there,
Nice article thanks!
I am using .net core minimal API and the built in AddAuthorization method and then decorating any endpoints with [Authorize] if needed. However I have some endpoints that will do different things depending on whether the user has provided a valid JWT or not.
How can I check the current Authorize status..? Or d I have to manually check the JWT again..?
Thanks
Rolf