How should JWT be used?

Keywords: Javascript JSON Session axios

I. overview

JWT, which is called JSON Web Token in full, is an open-source standard protocol. It defines a JSON based, lightweight and secure data transmission method.

Two, details

Each JWT is composed of three parts: Header, Payload and signature. At the same time, the JWT is spliced with dots in the form of:

Header.Payload.Signature

Header

The Header part is a Base64 encoded JSON object. The content of an object usually consists of two fields in the form of:

{
  "typ": "JWT",
  "alg": "HS256"
}

Where, typ (full name is type) indicates that the current Token type is JWT, and alg (full name is algorithm) indicates that the current signature algorithm is HS256.

Payload

The Payload part is also a JSON object encoded by Base64. The properties of the object can be divided into three parts: reserved field, public field and private field.

Reserved fields are JWT internal declarations and have special functions, including

  • iss (full name issuer), indicating who issued JWT
  • Subject (full name subject), indicating the subject of JWT (also understood as user oriented type)
  • aud (full name: audience), indicating who JWT wants to sign in
  • exp (full name: expiration time), indicating the expiration time of JWT, which should be greater than the issuing time
  • nbf (full name is not before time), indicating when JWT will take effect
  • iat (full name issued at time), indicating the issuing time of JWT
  • jti (full name: JWT ID), indicating the unique ID of JWT to avoid replay attack

Public fields and private fields are fields that users can add at will. The difference is that public fields are conventional and commonly used fields, while private fields are more suitable for practical application scenarios.

Currently existing public fields can be accessed from the JSON Web Token Claims Found in.

The structure of Payload is as follows:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Signature

The Signature part is generated by JWT according to the existing fields. Its calculation method is to use the algorithm defined in the Header and the user-defined key to encrypt the string composed of the Base64 encoded Header and Payload. The form is as follows:

HMACSHA256(base64(header) + '.' + base64(payload))

3, Application scenario

Generally accepted application scenarios in the industry are as follows:

Prevent transmission data tampering

Data tampering refers to the behavior that data is intercepted and modified in the process of transmission.

JWT itself can use encryption algorithm to sign the transmission content. Even if the data is intercepted, it is difficult to tamper with the signature and the transmission content at the same time.

authentication

Authentication refers to verifying whether users have access to the system.

Some people use JWT to replace the traditional Session + Cookie for the following reasons:

  • Small server overhead. Using Session + Cookie requires the server to cache the user data. Using JWT, the user data is directly distributed to the client and sent to the server with each request.
  • Good expansibility. The advantage of server not caching user data is that it can be easily expanded horizontally
  • For single sign on. JWT is very suitable for single sign on in cross domain situation
  • It is suitable for use with RESTFul API. The API based on RESTFul architecture design needs to follow the stateless principle of RESTFul, and JWT based authentication just transfers the state to the client

The general processing logic of authentication based on JWT is as follows:

There are also some disputes on the authentication scheme based on JWT:

  • After the server issues JWT, it can't log off actively. If there is malicious request, it is difficult to stop it. In fact, it can be solved by Token blacklist.
  • JWT reduces the cost of the server, but increases the cost of the bandwidth. The Token generated by JWT is much larger than the SessionID in volume, which means that each request carries more data than before. This is true, so try to put only the necessary data in JWT.
  • JWT is not completely superior to session cookie in authentication. For example, session ID can also be signed to prevent tampering.

Four, use

The following uses Node.js and JavaScript to demonstrate the application of JWT in authentication. The libraries involved are:

How to generate Token

The generation of Token is generally that the client sends the login request, and the server uses the key to generate Token and put it into the response body. The following is the Token generation logic of the server.

// File location: controller/v1/token.js
const config = require('config') // Load server configuration
const jwt = require('jsonwebtoken') // Implementation of loading jwt Node.js

/**
 * Create Token controller
 * @param {Object} ctx Request context
 */
async function create(ctx) {
  const username = ctx.request.body.username
  const password = ctx.request.body.password
  
  if (!username || !password) {
    ctx.throw(400, 'Parameter error')
    return
  }
  
  // Omitted: user name password database verification
  const user = { id: '5e54c02a2b073de564fe8034' } // User information
  const secret = config.get('secret') // Get the key saved in the configuration
  const opt = { expiresIn: '2d' } // Set Token expiration time to 2 days
  
  ctx.body = jwt.sign(user, secret, opt) // Generate and return token
}

module.exports = {
  create,
}

Client carries Token for request

In general, the client places the Token in the Authorization of Http Header and sends it to the server along with the request.

// File location: views/index.pug
var request = axios.create({ baseURL: '/api/v1' }) // Create request instance
var token // In order to facilitate the use of global variables here, it should normally be placed in other storage media, such as localStorage, where the acquisition logic is omitted

// Listen to the normal request button click event to initiate a request
document.querySelector('#normal').addEventListener('click', function() {
  if (!token) {
    alert('Please login')
    return
  }
  
  request.get('/users', {
    headers: {
      Authorization: 'Bearer ' + token, // Bind token to header
    },
  }).then(function({ data }) {
    document.querySelector('#response').innerHTML = JSON.stringify(data)
  }).catch(function(err) {
    console.log('Request Error: ', err)
  })
})

How to verify Token by server

The verification operation is generally placed in the middleware of the server.

const config = require('config') // Load server configuration
const jwt = require('jsonwebtoken') // Implementation of loading jwt Node.js

// Define middleware functions
module.exports = async (ctx, next) => {
  const path = ctx.url // Get request URL
  const method = ctx.method.toLowerCase() // Get request method
  
  // Request white list. The requests in the white list do not go through middleware token verification
  const whiteList = [
    { path: /^\/api\/v[1-9]\/tokens/, method: 'post' },
    { path: /^\/api/, reverse: true }, // Resources that do not start with the / api do not need to be verified by the request
  ]
  
  // Request whitelist check function  
  const checker = (i) => {
    const matchPath = i.path.test(path)
    const matchMethod = i.method ? i.method === method : true
    return (i.reverse ? !matchPath : matchPath) && matchMethod
  }
  
  // Logical judgment of white list
  if (whiteList.some(checker)) {
    await next()
    return
  }
  
  // Get token in http header
  const token = (ctx.header.authorization || '').replace('Bearer ', '')
  
  // token validation
  try {
    const data = jwt.verify(token, config.secret)
    ctx.userInfo = data
  } catch (e) {
    ctx.throw(400, 'Token error')
  }
  
  await next()
}

For complete code, please go to GitHub to search for user yo squirrel
If you feel good, you can focus on the official account of WeChat public squirrel column.

Posted by Dale_G on Mon, 23 Mar 2020 20:35:25 -0700