213

I don't understand how this library works. Could you help me please ?

Here is my simple code :

public void TestJwtSecurityTokenHandler()
    {
        var stream =
            "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJJU1MiLCJzY29wZSI6Imh0dHBzOi8vbGFyaW0uZG5zY2UuZG91YW5lL2NpZWxzZXJ2aWNlL3dzIiwiYXVkIjoiaHR0cHM6Ly9kb3VhbmUuZmluYW5jZXMuZ291di5mci9vYXV0aDIvdjEiLCJpYXQiOiJcL0RhdGUoMTQ2ODM2MjU5Mzc4NClcLyJ9";
        var handler = new JwtSecurityTokenHandler();

        var jsonToken = handler.ReadToken(stream);
    }

This is the error :

The string needs to be in compact JSON format, which is of the form: Base64UrlEncodedHeader.Base64UrlEndcodedPayload.OPTIONAL,Base64UrlEncodedSignature'.

If you copy the stream in jwt.io website, it works fine :)

Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
Cooxkie
  • 6,740
  • 6
  • 22
  • 26
  • 1
    the jwt,io site decodes it, but there is no signature so it is invalid. – Crowcoder Jul 13 '16 at 01:53
  • Possible duplicate of [Decoding and verifying JWT token using System.IdentityModel.Tokens.Jwt](https://stackoverflow.com/questions/18677837/decoding-and-verifying-jwt-token-using-system-identitymodel-tokens-jwt) – Michael Freidgeim Sep 15 '17 at 11:32
  • 1
    @MichaelFreidgeim you're right it's duplicate question ... but answers are different because of version library you use – Cooxkie Sep 15 '17 at 12:05
  • You better do not share tokens on public webs, because we can get information that maybe is not secure but sencible – Ernesto Alfonso Mar 09 '22 at 14:52

11 Answers11

357

I found the solution, I just forgot to Cast the result:

var stream = "[encoded jwt]";  
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream);
var tokenS = jsonToken as JwtSecurityToken;

Or, without the cast:

var token = "[encoded jwt]";  
var handler = new JwtSecurityTokenHandler();
var jwtSecurityToken = handler.ReadJwtToken(token);

I can get Claims using:

var jti = tokenS.Claims.First(claim => claim.Type == "jti").Value;
JohnB
  • 18,046
  • 16
  • 98
  • 110
Cooxkie
  • 6,740
  • 6
  • 22
  • 26
  • 2
    I had to cast tokenS.Claims as a List of Claims first. `((List)tokenS.Claims).ForEach(a => Console.WriteLine(a.Type.ToString() + " " + a.Value));` – Rinaldi Segecin Apr 13 '17 at 22:44
  • For Registered Claims you can get the property value directly off of the `JwtSecurityToken`. For example, `tokenS.Id` will get you the jti value – user875318 Jan 30 '18 at 14:30
  • 13
    You can also do: handler.ReadJwtToken(tokenJwtReponse.access_token); – Thabiso Mofokeng Feb 20 '18 at 15:30
  • Also, don't use type-safe casting unless you are expecting it to NOT be of that type. Use `(JwtSecurityToken)handler.ReadToken(tokenJwtReponse.access_token)` so that you get `InvalidCastException` instead of some later `NullReferenceException`. See [this](https://codeblog.jonskeet.uk/2013/09/19/casting-vs-quot-as-quot-embracing-exceptions/) – oatsoda Jun 04 '18 at 08:42
  • 15
    Sorry if this should be obvious but where is `tokenJwtReponse.access_token` coming from? – Jeff Stapleton Mar 20 '19 at 04:02
  • 4
    Where is tokenJwtReponse.access_token coming from? – 3iL Mar 20 '19 at 12:34
  • 7
    As others have already questioned: where does "tokenJwtReponse.access_token" come from? There is no definition or declaration for it in the answer, making the answer useless and meaningless for many of us. – Zeek2 Apr 08 '19 at 15:38
  • I'm assuming `tokenJwtResponse` is a deserialized json response containing a key `access_token` with the actual JWT token. – Niklas Holm Apr 25 '19 at 09:14
  • replace tokenJwtReponse.access_token in the above with stream – Rob McFeely Jul 03 '19 at 13:16
  • Your examples should be self contained and testable. This doesn't build. – Timothy Gonzalez Nov 05 '19 at 04:45
  • 6
    I needed to include the following NuGet package to use it within my Azure Function: System.IdentityModel.Tokens.Jwt – David Yates Jan 16 '20 at 02:54
  • 1
    the tokenJwtReponse.access_token is simply the string of the access token (without "Bearer " in the start) – CodeMonkey Feb 15 '21 at 09:33
  • 1
    There are probably other ways to get the access token in other scenarios, but from within a Controller, I can get it using ---> var token = await HttpContext.GetTokenAsync("access_token"); – mathkid91 Aug 02 '21 at 12:10
60

new JwtSecurityTokenHandler().ReadToken("") will return a SecurityToken

new JwtSecurityTokenHandler().ReadJwtToken("") will return a JwtSecurityToken

If you just change the method you are using you can avoid the cast in the above answer

dpix
  • 2,765
  • 2
  • 16
  • 25
39

You need the secret string which was used to generate encrypt token. This code works for me:

protected string GetName(string token)
    {
        string secret = "this is a string used for encrypt and decrypt token"; 
        var key = Encoding.ASCII.GetBytes(secret);
        var handler = new JwtSecurityTokenHandler();
        var validations = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateIssuer = false,
            ValidateAudience = false
        };
        var claims = handler.ValidateToken(token, validations, out var tokenSecure);
        return claims.Identity.Name;
    }
jaycer
  • 2,941
  • 2
  • 26
  • 36
Pato Milán
  • 488
  • 5
  • 6
  • Why do you call `handler.ReadToken(token) as SecurityToken` when you're reassigning it as your `out` parameter later? Is there a possibility that `ValidateToken` fails and the original value is kept? – krillgar Feb 27 '19 at 15:49
  • Right krillgar is not nesessary the cast to SecurityToken – Pato Milán Apr 04 '19 at 21:22
  • 1
    Does ValidateToken check the expiration? Or do I need to validate that myself after it is decoded? – computrius Jun 03 '20 at 15:46
  • @computrius ValidateToken takes a `TokenValidationParameters`, which is constructed on the line before the call, as clearly seen in the answer. This object will tell the validator what to check for. – Zimano Apr 23 '21 at 09:23
26
  var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
  var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
  var claims = new[]
  {
      new Claim(JwtRegisteredClaimNames.Email, model.UserName),
      new Claim(JwtRegisteredClaimNames.NameId, model.Id.ToString()),
  };
  var token = new JwtSecurityToken(_config["Jwt:Issuer"],
      _config["Jwt:Issuer"],
      claims,
      expires: DateTime.Now.AddMinutes(30),
      signingCredentials: creds);

Then extract content

 var handler = new JwtSecurityTokenHandler();
 string authHeader = Request.Headers["Authorization"];
 authHeader = authHeader.Replace("Bearer ", "");
 var jsonToken = handler.ReadToken(authHeader);
 var tokenS = handler.ReadToken(authHeader) as JwtSecurityToken;
 var id = tokenS.Claims.First(claim => claim.Type == "nameid").Value;
SolarBear
  • 4,534
  • 4
  • 37
  • 53
Jinesh
  • 1,480
  • 2
  • 25
  • 52
18

Using .net core jwt packages, the Claims are available:

[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "Bearer")]
public class AbstractController: ControllerBase
{
    protected string UserId()
    {
        var principal = HttpContext.User;
        if (principal?.Claims != null)
        {
            foreach (var claim in principal.Claims)
            {
               log.Debug($"CLAIM TYPE: {claim.Type}; CLAIM VALUE: {claim.Value}");
            }

        }
        return principal?.Claims?.SingleOrDefault(p => p.Type == "username")?.Value;
    }
}
jenson-button-event
  • 18,101
  • 11
  • 89
  • 155
  • 1
    This is only feasible when using ASP.NET Core based middleware pipeline, OP asked specifically for the handler's implementation inside implementation `System.IdentityModel.Tokens.Jwt` which suits a broader set of use cases. – Beltway Nov 02 '21 at 13:12
14

I write this solution and it's work for me

    protected Dictionary<string, string> GetTokenInfo(string token)
    {
        var TokenInfo = new Dictionary<string, string>();

        var handler = new JwtSecurityTokenHandler();
        var jwtSecurityToken = handler.ReadJwtToken(token);
        var claims = jwtSecurityToken.Claims.ToList();

        foreach (var claim in claims)
        {
            TokenInfo.Add(claim.Type, claim.Value);
        }

        return TokenInfo;
    }
Adam
  • 309
  • 3
  • 8
3

Extending on cooxkie answer, and dpix answer, when you are reading a jwt token (such as an access_token received from AD FS), you can merge the claims in the jwt token with the claims from "context.AuthenticationTicket.Identity" that might not have the same set of claims as the jwt token.

To Illustrate, in an Authentication Code flow using OpenID Connect,after a user is authenticated, you can handle the event SecurityTokenValidated which provides you with an authentication context, then you can use it to read the access_token as a jwt token, then you can "merge" tokens that are in the access_token with the standard list of claims received as part of the user identity:

    private Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage,OpenIdConnectAuthenticationOptions> context)
    {
        //get the current user identity
        ClaimsIdentity claimsIdentity = (ClaimsIdentity)context.AuthenticationTicket.Identity;

        /*read access token from the current context*/
        string access_token = context.ProtocolMessage.AccessToken;

        JwtSecurityTokenHandler hand = new JwtSecurityTokenHandler();
        //read the token as recommended by Coxkie and dpix
        var tokenS = hand.ReadJwtToken(access_token);
        //here, you read the claims from the access token which might have 
        //additional claims needed by your application
        foreach (var claim in tokenS.Claims)
        {
            if (!claimsIdentity.HasClaim(claim.Type, claim.Value))
                claimsIdentity.AddClaim(claim);
        }

        return Task.FromResult(0);
    }
TamerDev
  • 79
  • 3
3

Use this:

    public static string Get_Payload_JWTToken(string token)
    {
        var handler = new JwtSecurityTokenHandler();
        var DecodedJWT = handler.ReadJwtToken(token);
        string payload = DecodedJWT.EncodedPayload;  // Gives Payload
        return Encoding.UTF8.GetString(FromBase64Url(payload));
    }
    static byte[] FromBase64Url(string base64Url)
    {
        string padded = base64Url.Length % 4 == 0
        ? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
        string base64 = padded.Replace("_", "/").Replace("-", "+");
        return Convert.FromBase64String(base64);
    }
2

Though this answer is not answering the original question but its a really very useful feature for C# developers, so adding it as the answer.

Visual Studio 2022 has added a feature to decode the value of a token at runtime.

You can check the feature in Visual Studio 2022 preview (version 17.5.0 preview 2.0)

Mouse over the variable containing the JWT and then select the string manipulation as JWT Decode, and you can see the token value.

enter image description here

enter image description here

Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
1
 public string getRoleFromJwt()
    {
        string jwtEncoded = Request.Headers.Authorization;
        jwtEncoded = jwtEncoded.Replace("Bearer ", "");
        var handler = new JwtSecurityTokenHandler();
        var jwtDecoded = handler.ReadToken(jwtEncoded) as JwtSecurityToken;
        var claim = jwtDecoded.Claims.FirstOrDefault(j => j.Type.EndsWith("/role"));
        if (claim == null)
            return "";
        return claim.Value;
    }
  • 2
    This is SolarBear's solution with a little modification. This assumes that you want to retrieve ClaimType.Role value. SolarBear's solution didn't work for me because Claim.Type contains more data than just the word "role" but it ends with "/role". See my modification below : var claim = jwtDecoded.Claims.FirstOrDefault(j => j.Type.EndsWith("/role")); – Mohammed S. Feb 25 '23 at 10:46
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 02 '23 at 00:47
  • 1
    Why not use `handler.ReadJwtToken(...)` and avoid casting `as JwtSecurityToken`? – Konrad Viltersten Jul 28 '23 at 16:46
0

with jose-jwt nuget package it can be done by the following call:

var decodedToken = Jose.JWT.Payload(encodedToken);

It will decode token in the same way as it is done e.g. on jwt.io.

alex
  • 187
  • 1
  • 9