Token

JSON Web Token in ASP.NET Core 6

In this article, I’ll show a brief introduction about JSON Web Token and also a practical example of how JWT can be implemented using ASP.NET Core 6.

What is JSON Web Token

JSON Web Token ( JWT ) is an open standard based on JSON for creating a token that is used to send data between applications or services and ensure that it is valid and secure. This information can be verified and trusted because it is digitally signed.

When to use JSON Web Token?

When JWT is useful:

  • Authorization, most common usage. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources allowed with that token. Single Sign On (SSO) is a widely used feature in JWT today, due to its low overhead and ability to be easily used across different domains.
  • Information exchange, JWTs are a good way to transmit information securely between parties. Because JWTs can be signed, for example, using public/private key pairs, you can be sure that the senders are who they say they are. Also, since the signature is calculated using the header and payload, you can also verify that the content has not been tampered with.

How does JSON Web Token work?

In authentication, when the user successfully logs in with their credentials, a JSON web token will be returned. Since tokens are credentials, great care must be taken to avoid security issues. In general, you shouldn’t keep tokens longer than necessary.

Every time the user wants to access a protected route or resource, the user agent must send the JWT, usually in the Authorization header using the Bearer scheme.


Diagram shows how a JWT is obtained and used to access APIs or resources
  1. The application or client requests authorization from the authorization server.
  2. When authorization is granted, the authorization server returns an access token to the application.
  3. The application uses the access token to access a protected resource (such as an API).

JSON Web Token Structure

A JWT is separated by periods  (HEADER.PAYLOAD.SIGNATURE) into three encoded parts, a header, a content or payload, and a signature .

We can decode and see the content of the token using jwt.io without needing to know the key with which it was generated, although we will not be able to validate it without it.

  • Header: The type of token and the algorithm used for the signature.
{
  "alg": "HS256", // HS256 indica que este token está firmado utilizando HMAC-SHA256.
  "typ": "JWT"
}
  • Payload : Contains the claims that are data about an entity (usually the user) and additional data. The information is provided as key/value pairs ( key-value ). Do not include unencrypted sensitive data in claims . There are 3 types of claims :
    • Registered claims: predefined claims that are not mandatory. They are listed in the  IANA JSON Web Token Claim Register  and whose purpose is established in a standard. Like iss (sender), aud (receivers), exp (expiration time), sub (reason), among others.
    • Public claims: they can be defined at will, since they are not subject to restrictions. In order to avoid conflicts in the semantics of the claims, it is necessary to register the  claims  publicly in the IANA JSON Web Token Claim Register or assign them names that cannot match.
    • Private Claims: These are custom claims created to share information between parties who agree to use them and are not registered  or public claims. When naming them, it’s important to make sure they won’t conflict with any registered or public claims.
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}
  • Signature : is a signature that allows us to check if the token is valid, to create the signature part, you need to take the encoded header, the encoded payload, a secret, the algorithm specified in the header and sign it.
key =  'secret-key'
unsignedToken = base64Encode(header) + '.' + base64Encode(payload)
signature = SHA256(key, unsignedToken)
token = unsignedToken + '.' + signature

The signature is used to verify that the message was not modified along the way, and in the case of tokens signed with a private key, it can also verify that the sender of the JWT is who they say they are.

// JSON Web Token (HEADER.PAYLOAD.SIGNATURE):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Good practices using JSON Web Token

When generating tokens:

  • Always issue signed tokens
  • Use strong cryptographic algorithms
  • Put expiration date and unique identifier
  • Give value to the issuer (issuer) and to the recipients (audience)
  • Do not include unencrypted sensitive data in claims

When validating:

  • Do not accept unsigned tokens
  • Validate header claims
  • Always validate sender and recipients
  • Store signing keys by issuer and algorithm

Communication:

  • Communication between parties with HTTPS to encrypt traffic

Let’s go to code👇

We will build an application that illustrates how to use the JSON Web Token. This application will contain an API that generates the JWT and we will access a protected resource with this token.

Generating JSON Web Token

First, the code where we generate the JWT:

public async Task<string> GetTokenAsync(string userName)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_configuration["JwtSettings:Key"]);
    var issuer = _configuration["JwtSettings:Issuer"];
    var audience = _configuration["JwtSettings:Audience"];
    var user = await _userManager.FindByNameAsync(userName);
    var roles = await _userManager.GetRolesAsync(user);
    var claims = new List<Claim> { new Claim(ClaimTypes.Name, userName) };

    foreach (var role in roles)
    {
        claims.Add(new Claim(ClaimTypes.Role, role));
    }

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Issuer = issuer,
        Audience = audience,
        Subject = new ClaimsIdentity(claims.ToArray()),
        Expires = DateTime.UtcNow.AddDays(7),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    };
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

Code in the API where we check credentials and get JWT:

[HttpPost("authenticate")]
public async Task<ActionResult<AuthenticateResponse>> Authenticate([FromForm] AuthenticateRequest request)
{
    //...

    var succeeded = await _userManager.CheckPasswordAsync(user, request.Password);

    if (succeeded)
    {
        response.Succeeded = succeeded;
        response.Token = await _tokenClaimsService.GetTokenAsync(request.UserName);
    }

    //...
}

Testing our implementation

1. It requests authorization from the authorization server and the authorization server returns an access token to the application:

2. We introduce this token to access a protected resource (such as an API):

3. Now we can access protected routes, services and resources:

That’s all for now, I’ll keep updating and adding content in this post. I hope you found it interesting😉

Download

The source code for this article can be found on  GitHub

Links of interest

jwt.io

1