DEV Community

freakomonk
freakomonk

Posted on

JSON Web Tokens (JWTs) 101

JSON Web Tokens (JWT)

To understand the concept of JWT, we need to understand the authentication and authorisation.

  • Authentication
  • Authorisation
  • JWTs

Authentication

Authentication is a process in which a user is determined if he is exactly who he is claiming to be. For eg. a user "John Smith" requesting for his FB messages needs to be authenticated by the FB server that he is indeed John Smith, not someone impersonating him.

Username, password, OTP are common ways of authenticating a user.

Authorisation

John, say, needs to access messages of a group he is part of. Now server needs to verify if John is indeed an admin of the group and he is authorised to view the group's inbox.

Authorisation is the process of checking for the access privilege of the user. Server typically does this by verifying the user id against the roles mapped to it.

JSON Web Tokens

JWTs are used to handle both authentication and authorisation. Let us see how JWTs work before we dive into how it is used to ensure authentication and authorisation.

Like the name says, JWTs are JSON format based tokens used in the web. JWTs usually look like aaaaaaaa.bbbbbbb.ccccccc. Notice the . delimiter between sections. These three sections in a JWT are

  • Header
  • Payload
  • Signature respectively. Each section is in JSON format as specified above.

Header

A JWT header consists of two parts. The type of the token typ and the algorithm used to sign this token alg. This alg section contains an identifier for a hashing algorithm such as HMAC, SHA256 or RSA.

A typical header section looks like

{
    "typ": "JWT",
    "alg": "SHA256"
}
Enter fullscreen mode Exit fullscreen mode

Payload

JWT's payload contains claims related to the token. Claims are basically statements about a specific section of data. Examples of claims in a JWT as issuer_name, creation_time, expiration_time etc.

The claims are represented by either reserved keywords or custom keywords. The advtange of a reserved keyword is for universal interoperability. As in, any receiver can make a reserved claim mandatory and sender would know what keyword would use without explicit agreement.

Examples of reserved claims are iss for issuer, exp for expiry date, sub for subject. A JWT can contain both reserved claims and custom claims.

{
    "iss": "server_identifier",
    "sub": "login_auth",
    "exp": "1621177091", // unix epoch for standardization,
    "user_id": "IN876TY34"
}
Enter fullscreen mode Exit fullscreen mode

In this example, user_id is a custom claim.

Note: Both header and payload are Base64Url encoded.

Signature

Signature is what provides security to a JWT and prevents tampering of the data. Anyone can see the contents of a JWT payload if it is not encrypted, but any tampering will make the token invalid because tampering of the data changes the signature.

A signature of a JWT is created with the algorithm specified in the header section along with a secret, encoded sections of header and payload. Since signature is created based on the encoded payload, any changes in the payload will invalidate the signature.

Though attacker has access to encoded header, payload and algorithm from the JWT, he won't know the secret.

SHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)
Enter fullscreen mode Exit fullscreen mode

A JWT after creating these sections look like
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InNoYXNoYW5na2EiLCJwYXNzd29yZCI6IjEyMzQ1IiwiaWF0IjoxNTM2MjgwMjM1LCJleHAiOjE1MzYyODAyNjV9.iplar3jWiW8rh1gU1H6pYaPu6-njCfflrP8GLbx9Imw

Now that we have created a JWT, let us look into how it is used in authentication and authorisation.

How to use JWTs ?

JWTs are created during the authentication flow. Once the user logs in with username/password details, a JWT is generated by the server. This JWT is stored by client , usually in local storage, and is sent to server for each subsequent request as part of Authorisation header.

'Authorisation': 'Bearer <jwt>'

In the payload section of JWT, data related to the authentication and authorisation can be stored which is used by the server to authenticate the user and also verify the user's authorisation for various API access etc.

Example of creating JWT using Node.js

We use a npm package
npm install jsonwebtoken

const jwt = require('jsonwebtoken')

 const jwtSecretKey = '<JWT_SECRET_KEY_STORED_AS_ENVIRONMENT_VARIABLE>';
 const data = {
        "time": Date(),
        "iss": "server_identifier",
        "sub": "login_auth",
        "exp": "1621177091", 
        "user_id": "IN876TY34"
    }
   const token = jwt.sign(data, jwtSecretKey);
Enter fullscreen mode Exit fullscreen mode

A JWT is not to be confused with a cookie. More discussion into this comparison will be subject of next post. A JWT is usually used to store and transmit authorisation data.

One downside of using a JWT is all the data is stored in it as claims. Since it is passed to server from client for every request, there is lot of data being transmitted over the network everytime and this only gets worse as more and more data is stored in a JWT.

Discussion (0)