What is JWT

Json Web Token (JWT) is an open jSON-based standard (RFC 7519) implemented for the transfer of declarations between network application environments.

The token is designed to be compact and secure, especially suitable for single sign-on (SSO) scenarios in distributed sites.

The JWT declaration is generally used to pass authenticated user identity information between the identity provider and the service provider to obtain resources from the resource server, and to add some additional declaration information necessary for other business logic. The token can also be used directly for authentication or can be encrypted.

Ii. Composition of JWT

1. The appearance after JWT generation and coding

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.UQmqAUhUrpDVV2 ST7mZKyLTomVfg7sYkEjmdDI5XF8QCopy the code

2. JWT consists of three parts

The first part we call the header, the second part we call the payload, and the third part is the signature.

header

The header of the JWT carries two pieces of information:

  • Declare type, in this case JWT

  • Algorithms that declare encryption usually use HMAC SHA256 directly

The complete header looks like this JSON:

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

Base64 encryption of the header, which can be decrypted symmetrically, then forms the first part

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
Copy the code

playload

The payload is where the useful information is stored. The name seems to refer specifically to the cargo carried on the plane, and this valid information consists of three parts

  • A declaration of registration in a standard

  • Public statement

  • Private declaration

Declarations registered in the standard (recommended but not mandatory) :

  • Iss: JWT issuer

  • Sub: The user JWT is targeting

  • Aud: The side receiving the JWT

  • Exp: indicates the expiration time of the JWT. The expiration time must be greater than the issue time

  • NBF: defines the time before the JWT is unavailable.

  • Iat: issue time of JWT

  • Jti: Unique IDENTIFIER of the JWT. It is used as a one-time token to avoid replay attacks.

A public statement:

Public declarations can add any information, usually about the user or other information necessary for the business. However, it is not recommended to add sensitive information because this part can be decrypted on the client side.

Private declaration:

Private declarations are defined by both providers and consumers. Sensitive information is generally not recommended because Base64 is symmetrically decrypted, meaning that part of the information can be classified as plaintext information.

Define a payload:

{  "sub": "1234567890",  "name": "John Doe",  "admin": true}
Copy the code

It is then base64 encrypted to get the second part of the Jwt

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
Copy the code

signature

The third part of the JWT is a visa information, which consists of three parts:

  • Header (Base64)

  • Payload (base64)

  • secret

This part is used by the base64-encrypted header and the Base64-encrypted payload. The concatenated string (header first), then salted secret combined with the encryption method declared in the header, forms the third part of the JWT.

UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q
Copy the code

The secret key is stored on the server. The server generates token and authentication based on the secret key, so it must be protected.

3. Purpose of signature

The final step in the signing process is actually signing the header and payload contents. In general, encryption algorithms always produce different outputs for different inputs. For two different inputs, the probability of producing the same output is extremely small (probably less than my chances of becoming the richest person in the world). So, let’s take “different inputs produce different outputs” as a necessary event.

Therefore, if the contents of the header and payload are decoded and modified, then the signature of the new header and payload will be different from the previous signature. And if you don’t know the key the server used to encrypt it, the signature is bound to be different.

Upon receiving the JWT, the server application first re-signs the contents of the header and payload using the same algorithm. So how does the server application know which algorithm we’re using? Don’t forget that we already specify our encryption algorithm with the ALG field in the JWT header.

If the server uses the same method to sign the header and payload again and finds that the signature calculated by the server is different from the received signature, then the Token has been modified. We should reject the Token and return an HTTP 401 Unauthorized response.

Note: in JWT, you should not add any sensitive data to the payload, such as the user’s password.

4, how to apply

In general, the Authorization has been added to the header of the request and the Bearer has been labeled:

fetch('api/user/1', {  headers: {    'Authorization': 'Bearer ' + token  }})
Copy the code

The server validates the token and returns the corresponding resource if it succeeds.

5, safety related

  • Sensitive information should not be stored in the Payload part of the JWT because this part is decrypted by the client.

  • Protect the secret private key, which is very important.

  • If yes, use HTTPS

6. Five points about Token authentication

  • A Token is a collection of information;

  • Include enough information in the Token to reduce the chance of querying the database on subsequent requests;

  • The server needs to check the Token information of the cookie and HTTP Authrorization Header.

  • Based on the previous point, you can use a set of token authentication code for both browser and non-browser clients.

  • Since the token is signed, we can assume that a token that can be decoded and authenticated is issued by our system, and the information contained in it is legal and valid.

Traditional session authentication

As we know, the HTTP protocol itself is a stateless protocol, which means that if the user to our application provides a user name and password for user authentication, so the next time a request, the user will once again for user authentication, because based on HTTP protocol, we don’t know is which user requests, So in order for our application to be able to identify which user is making the request, we can only store a copy of the user’s login information on the server, and this login information is passed to the browser in response, telling it to save as a cookie, so that it can be sent to our application in the next request. So our application can identify the user from whom the request is coming, which is traditional session-based authentication.

However, session-based authentication makes it difficult to expand the application itself. With the increase of different client users, the independent server can no longer bear more users, and the problems of session-based authentication applications will be exposed.

Problems with session-based authentication

Session: After each user is authenticated by our application, our application makes a record on the server to facilitate the identification of the user’s next request. Generally speaking, sessions are stored in memory. However, as the number of authenticated users increases, the overhead on the server will increase significantly.

Scalability: After the user is authenticated, the server makes authentication records. If the authentication records are stored in memory, it means that the user’s next request must be made on this server to obtain authorized resources, which limits the capacity of the load balancer in distributed applications. This also means limiting the application’s ability to scale.

CSRF: Because user identification is based on cookies, if cookies are intercepted, users will be vulnerable to cross-site request forgery.

Token-based authentication mechanism

Similar to HTTP, token-based authentication is stateless and does not need to retain user authentication information or session information on the server. This means that token-based applications do not need to consider which server users log in to, which facilitates application expansion.

The process looks like this:

  • The user requests the server using a username and password

  • The server authenticates the user’s information

  • The server sends the user a token through authentication

  • The client stores the token and supplies it with each request

  • The server validates the token value and returns data

Access-control-allow-origin :* This token must be passed to the server on every request. It should be stored in the header of the request. In addition, the server must support the CORS policy.

Four, the advantages of token

  • Cross-domain access: Cookies do not allow cross-domain access, which does not exist for the Token mechanism, provided that the user authentication information is transmitted through HTTP headers.

  • Stateless (also called server extensible line): The Token mechanism does not need to store session information on the server, because the Token itself contains information about all login users. The status information only needs to be stored in the cookie or local media of the client.

  • More suitable for CDN: you can request all the data (javascript, HTML, images, etc.) from your server via content distribution network, as long as your server provides the API.

  • Decoupling: There is no need to bind to a specific authentication scheme. Tokens can be generated anywhere, as long as you can make Token generation calls when your API is called.

  • More suitable for mobile applications: When your client is a native platform (iOS, Android, Windows 8, etc.), cookies are not supported (you need to use Cookie containers for processing), then Token authentication is much easier.

  • CSRF: Because you no longer rely on cookies, you don’t need to worry about defending against CSRF (cross-site request forgery).

  • Performance: A network round-trip time (query session information from the database) is always much more time-consuming than a Token verification and resolution of HMACSHA256 calculation.

  • No special handling for the login page: If you are functional testing with the Protractor, there is no special handling for the login page.

  • Standardisation based: Your API can use standardised JSON Web tokens (JWT). The standard already exists in several back-end libraries (.NET, Ruby, Java,Python, PHP) and is supported by several companies (e.g. Firebase,Google, Microsoft).

  • Json’s generality. As a result, JWT can be cross language support, like JAVA, JavaScript, NodeJS, many languages such as PHP can be used.

  • With the payload part, the JWT can store itself non-sensitive information that is necessary for other business logic.

  • Easy to transport, JWT is very simple to build and has a small byte footprint, so it is very easy to transport.

  • It does not need to store session information on the server, so it is easy to apply extensions.

JAVA implementation of JWT

JWT support in Java can be considered using the JJWT open source library; JJWT implements the JWT, JWS, JWE, and JWA RFC specifications;

Here is a simple example to illustrate its use:

1. Generate the Token code

import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; import java.security.Key; import io.jsonwebtoken.*; import java.util.Date; //Sample method to construct a JWT private String createJWT(String id, String issuer, String subject, long ttlMillis) { //The JWT signature algorithm we will be using to sign the tokenSignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); //We will sign our JWT with our ApiKey secretbyte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(apiKey.getSecret()); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); //Let's set the JWT ClaimsJwtBuilder builder = Jwts.builder().setId(id) .setIssuedAt(now) .setSubject(subject) .setIssuer(issuer) .signWith(signatureAlgorithm, signingKey); //if it has been specified, let's add the expirationif (ttlMillis >= 0) { long expMillis = nowMillis + ttlMillis; Date exp = new Date(expMillis); builder.setExpiration(exp); } //Builds the JWT and serializes it to a compact, URL-safe stringreturn builder.compact(); }Copy the code

2. Decode and verify Token code

import javax.xml.bind.DatatypeConverter; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Claims; //Sample method to validate and read the JWTprivate void parseJWT(String jwt) {//This line will throw an exception if it  is not a signed JWS (as expected)Claims claims = Jwts.parser() .setSigningKey(DatatypeConverter.parseBase64Binary(apiKey.getSecret())) .parseClaimsJws(jwt).getBody(); System.out.println("ID: " + claims.getId()); System.out.println("Subject: " + claims.getSubject()); System.out.println("Issuer: " + claims.getIssuer()); System.out.println("Expiration: " + claims.getExpiration()); }Copy the code