1. JWT is what

JSON Web Token (abbreviated JWT) is a cross-domain authentication solution. After authentication, the server generates a string and sends it back to the user. In order to prevent the user from tampering with the data, the server will add a signature when generating the string. In the future, the user will carry this string when communicating with the server. The server identifies the user solely on this string. The form of the string looks like this: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJ SMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

This string we can call JWT. The JWT string can be parsed on the jwt. IO/website. After parsing, there are three parts. Looking closely at the JWT string, there are two dots (.) I’ve separated the string, so it’s just one to one of the parsed structures.

These three parts are the data structures of JWT. Header, Payload, and Signature.

1.Header

The Header section is a JSON object that describes the JWT metadata.

{
  "alg": "HS256",
  "typ": "JWT"
}
Copy the code

The alG attribute indicates the algorithm of the signature. The default value is HMAC SHA256 (HS256).

The TYP attribute indicates the type of the token. JWT tokens are written as JWT.

The JSON object above is converted to a string using the Base64URL algorithm.

2.Payload

The Payload section is also a JSON object that holds the actual data that needs to be passed. Note that JWT is not encrypted by default and can be read by anyone. Do not put sensitive information such as passwords in it.

This data can be either JWT’s own fields or its own custom data, such as the name field in the example.

Iss (Issuer) : indicates the issuer

Expiration Time (exp) : expiration time

Sub (Subject) : the subject

Aud (audience) : audience

NBF (Not Before) : indicates the effective time

Iat (Issued At) : Issued time

Jti (JWT ID) : Indicates the ID

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

This JSON object is also converted to a string using the Base64URL algorithm.

3.Signature

The Signature section is the Signature to the first two sections to prevent data tampering. First, you need to specify a key (secret). This key is known only to the server and cannot be disclosed to the user. Then, using the signature algorithm specified in the Header (the default is HMAC SHA256), the following formula is used to generate the signature.

HMACSHA256( base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret) 

After the Signature is calculated, the Header, Payload, and Signature parts are combined into a string, with dots (.) between each part. You can return it to the user.

2. The characteristics of the JWT

  1. JWT does not encrypt by default, but it can be encrypted. After the original Token is generated, it can be encrypted again with the key.

  2. Secret data cannot be written to JWT without JWT encryption.

  3. JWT can be used not only for authentication but also for exchanging information. Effective use of JWT can reduce the number of times the server queries the database.

  4. The biggest drawback of JWT is that because the server does not hold session state, it cannot revoke a token during use or change the permission of the token. That is, once a JWT is issued, it remains in effect until it expires, unless the server has additional logical controls.

  5. The JWT itself contains authentication information, which, if exposed, allows anyone to gain full access to the token. To reduce theft, the validity period of JWT should be set to short. For some important permissions, the user should be authenticated again.

  6. To reduce theft, JWT should use HTTPS instead of HTTP.

3. What pain points have you solved

A common user authentication mode might be as follows:

  1. The user sends the user name and password to the server.

  2. After the server passes the authentication, it saves relevant data in the current session, such as the user role, login time, and so on.

  3. The server returns a session_ID to the user and writes the Cookie of the user.

  4. Each subsequent request from the user sends the Session_ID back to the server via Cookie.

  5. The server receives the Session_ID, finds the previously saved data, and knows the user’s identity.

The problem with this approach is that it doesn’t scale well. A single server is fine, but if it’s a server cluster or a cross-domain service oriented architecture, session data will be shared and each server will be able to read the session.

For example, site A and Site B are affiliated services of the same company. Now requires, the user only wants to be in one of the website to log in, again visits another website to be able to log in automatically, how to realize excuse me?

One solution is session data persistence, written to a database or other persistence layer. When the various services receive the request, they request data from the persistence layer. The advantage of this scheme is that the structure is clear, the disadvantage is that the amount of work is relatively large. In addition, if the persistence layer fails, it will have a single point of failure.

The other option is for the server to not keep session data at all. All data is stored on the client and sent back to the server on every request. JWT is an example of such a scheme. The server does not hold any session data, that is, the server becomes stateless, which makes scaling easier.

4.Base64URL

Header and Payload are stringed using Base64URL. This algorithm is basically similar to the Base64 algorithm, with some minor differences.

JWT acts as a token, and in some cases may be placed in a URL (such as api.example.com/?token=xxx). Base64 has three characters +, /, and =, which have special meanings in urls, so they need to be replaced: = is omitted, + is replaced with -, and/is replaced with _. This is the Base64URL algorithm.

5. Use of JWT

The client receives the JWT returned by the server, which can be stored in cookies or stored in localStorage. Thereafter, the client will carry this JWT with it every time it communicates with the server. You can put it in a Cookie and send it automatically, but that doesn’t cross domains, so it’s better to put it in the Authorization field of the HTTP request header.

6. Use it in the Node project

Just look at the concept, may just know a process, we need to according to this process, in the actual project to apply, deepen understanding. Download the jsonWebToken dependency first, but you can choose other libraries as well. For details on how to use the library, see the official example github.com/auth0/node-…

The sample code is a simplified version (after all, it’s a corporate project)

1.function sign(payload,secretOrPrivateKey,options,callback)

The sign method is used with four parameters.

Payload is the data returned.

SecretOrPrivateKey, this is the secret key.

Options is the configuration for JWT.

A callback is a callback method.

In the example, the payload contains the user name user_name and the user type user_type. SecretOrPrivateKey, you define it as you want. Just use the same key for signing and checking. Options, which expires one day after the configuration. Callback, which returns err on failure, and encoded on success, which is a JWT string.

const jwt = require('jsonwebtoken'); Const login = async ({userName, password}) => {const login = async ({userName, password}); Return new Promise((resolve, reject) => jwt.sign({user_name, user_type}, secret, {expiresIn: '1 days' }, (err, encoded) => { if (err) { reject(err); } resolve({ userToken: encoded }); })); };Copy the code

Ok, the client has got the JWT string, and I put it in localStorage.

localStorage.setItem(storage.token, token)
Copy the code

2.function decode(token)

As mentioned above, one of the features of JWT is that it can exchange information. Suppose I need to do permission control based on the user type. Without JWT, we might have to ask the background to find out what the type of the current user is. But we put the user type in JWT, so we just parse it out and use it.

const token = localStorage.getItem('userToken'); // Extract JWT from localStorage const userInfo = jwt.decode(token); // Payload const userType = userinfo.user_type; // Payload const userType = userInfo. // Find the user type fieldCopy the code

3.function verify(token,secretOrPublicKey,options,callback)

The token must be carried with each user request, and the server must verify that the token is valid. I use the Express framework to make token verification into a middleware for verification.

The token parameter, which is the JWT string, is going to be taken from headers, and I put it in the token field, so you can define it yourself.

Secret, which must be consistent with the secret value of the signature.

Options parameter, not used, omitted.

Return error message on failure, continue next on success.

const jwt = require('jsonwebtoken'); const token = ({ req, res, next }) => { const token = req.headers.token; jwt.verify(token, secret, (err, decoded) => { if (err) { logger.error(err); Res.status (400).json({message: 'Token invalid '}); return; } req.userInfo = decoded; next(); }); };Copy the code

To sum up, in combination with the principle of JWT, my application process in the project is as follows: after the user logs in successfully, the signature returns the token, and the client saves the token. Each time the client requests, it brings the token and checks whether the token is valid in the Express middleware.

If you have a better process and use, you can also share with me.

References:

JSON Web Token Introduction tutorial