JWT based token authentication - API Gateway - alicloud

Posted by zplits on Thu, 04 Nov 2021 13:17:06 +0100

Alibaba cloud API gateway implements a set of mechanism for authorizing access to users' APIs based on user system on the basis of structured token such as Json Web Token (JWT), which meets the needs of users' personalized security settings.

Alibaba cloud API gateway implements a set of mechanism for authorizing access to users' APIs based on user system on the basis of structured token such as Json Web Token (JWT), which meets the needs of users' personalized security settings.

1, token based authentication

1.1 INTRODUCTION

Many open API s need to identify the identity of the requester and judge whether the requested resources can be returned to the requester. token is a mechanism for authentication. Based on this mechanism, the application does not need to retain the user's authentication information or session information at the server. It can realize stateless and distributed Web application authorization, which provides convenience for application expansion.

1.2 process description

The above figure is the sequence diagram of the whole business process of API gateway using JWT to realize authentication. Next, we will describe the steps marked in the diagram in detail with words:

  1. The client sends an authentication request to the API gateway, which generally carries the user name and password of the end user;

  1. The API gateway forwards the request directly to the back-end service;

  1. The back-end service reads the authentication information (such as user name and password) in the request for authentication. After passing the authentication, it uses the private key to generate a standard token and return it to the API gateway;

  1. The API gateway returns the response with the token to the client, and the client needs to cache the token locally;

  1. The client sends a service request to the API gateway, and the request carries a token;

  1. The API gateway uses the public key set by the user to verify the token in the request. After the verification is passed, the request is transmitted to the back-end service;

  1. The back-end service responds after business processing;

  1. The API gateway returns the service response to the client.

In the whole process, the API gateway uses the token authentication mechanism to realize the ability of users to authorize their APIs using their own user system. Next, we will introduce the structured token JSON web token (JWT) used by the API gateway to implement token authentication.

1.3 JWT

1.3.1 introduction

JSON web token (JWT) is a JSON based open standard implemented to transfer declarations between network application environments RFC7519 . JWT can generally be used as an independent authentication token, which can contain information such as user ID, user role and permission, so as to obtain resources from the resource server. It can also add some additional declaration information necessary for other business logic, especially suitable for the login scenario of distributed sites.

1.3.2 composition of JWT

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

As shown in the above example, JWT is a string composed of three parts:

  • Header

  • Payload (data)

  • Signature

Header

The header of the JWT carries two messages:

  • Declaration type, here is JWT

  • Algorithm for declaring encryption

The complete header is like the following JSON:

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

Then, the header is Base64 encoded (which can be decoded symmetrically) to form the first part.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

Payload

Payload is the place where valid information is stored. The definition details are as follows:

iss: token issuer. Indicates who created the token. The declaration is a string sub: Subject Identifier. The end user id provided by iss is unique within the scope of iss. The maximum length is 255 ASCII characters. It is case sensitive. aud: Audience(s), token audience, case sensitive string array exp: Expiration time, and token expiration timestamp. Tokens that exceed this time will be invalidated. The declaration is an integer, which is the number of seconds since January 1, 1970. iat: the issuing time of the token. The declaration is an integer, which is the number of seconds since January 1, 1970. jti: the unique identification of the token. The value of the declaration is unique in each token created by the token issuer. In order to prevent conflicts, It is usually a cryptographic random value. This value is equivalent to adding a random entropy component to the structured token that cannot be obtained by the attacker, which is helpful to prevent token guessing attack and replay attack

You can also add custom fields that the user system needs to use. For example, the following example adds name   User nickname:

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

Then it is Base64 encoded to obtain the second part of Jwt:

JTdCJTBBJTIwJTIwJTIyc3ViJTIyJTNBJTIwJTIyMTIzNDU2Nzg5MCUyMiUyQyUwQSUyMCUyMCUyMm5hbWUlMjIlM0ElMjAlMjJKb2huJTIwRG9lJTIyJTBBJTdE

Signature

This part needs to be used by Base64 encoded Header and Base64 encoded Payload  .  The string formed by the connection is then encrypted through the encryption method declared in the Header ($secret)   Represents the user's private key), which then forms the third part of jwt.

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, '$secret');

Use these three parts  .  Concatenation into a complete string constitutes the JWT example at the beginning of section 1.3.2.

1.3.3 scope and limitation of authorization

The API gateway will think that the token issued by the user has the right to access all APIs bound to JWT plug-ins under the whole group. If more detailed permission management is required, the back-end service needs to unlock the token for permission authentication. The API gateway will verify the exp field in the token. Once the field expires, the API gateway will consider the token invalid and call back the request directly. The expiration time value must be set, and the expiration time must be less than 7 days.

1.3.4 several characteristics of JWT

  1. JWT is not encrypted by default and cannot write secret data to JWT.

  1. JWT can be used not only for authentication, but also for exchanging information. Using JWT effectively can reduce the number of times the server queries the database. JWT's security feature 3. The biggest disadvantage of JWT is that the server does not save the session state, so it is impossible to revoke a token or change the permission of the token during use. That is, once the JWT is issued, it will remain valid until it expires, unless the server deploys additional logic.

  1. JWT itself contains authentication information. Once it is leaked, anyone can obtain all the permissions of the token. In order to reduce embezzlement, the validity period of JWT should be set relatively short. For some important permissions, users should be authenticated again.

  1. In order to reduce embezzlement, JWT should not use HTTP protocol for explicit transmission, but HTTPS protocol for transmission.

2, How does the user system apply the JWT plug-in protection API

2.1 generate a pair of JWK (JSON Web key)

Method 1: Online generation:

Users can be on this site https://mkjwk.org   Generate the private key and public key for token generation and verification. The private key is used to authorize the service to issue JWT. The public key is configured in the JWT plug-in for API gateway to request signature verification. At present, the encryption algorithm of the key pair supported by API gateway is RSA SHA256, and the number of bits of encryption of the key pair is 2048.

Method 2: local generation:

This article applies Java examples to illustrate that users of other languages can also find relevant tools to generate key pairs. Create a Maven project and add the following dependencies:

<dependency>
     <groupId>org.bitbucket.b_c</groupId>
    <artifactId>jose4j</artifactId>
    <version>0.7.0</version>
</dependency>

Generate a pair of RSA keys using the following code:

RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
rsaJsonWebKey.setKeyId("authServer");
final String publicKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.PUBLIC_ONLY);
final String privateKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);

2.2 use the private key in JWK to realize the authentication service of issuing token

Online generated in Section 2.1 is required   Keypair   JSON string (the first of the three boxes) or locally generated   privateKeyString   The JSON string is used as the private key to issue the token, which is used to authorize trusted users to access the protected API. For the specific implementation, please refer to the example in Section 4 of this article. The form of issuing a token to a customer is determined by the user according to the specific business scenario. The function of issuing a token can be deployed to the production environment, configured as a common API, and obtained by the visitor through the user name and password. It can also be directly copied to the specified user after the token is generated in the local environment.

2.3 configure the public key in JWK into JWT plug-in

  1. Sign in

    API gateway console

    .

  1. On the left navigation bar, click plug in management.

  1. On the plug-in management page, click in the upper right corner

    Create plug-in

    .

  1. On the create plug-in page, select the plug-in type

    JWT authentication

    , the following is the configuration and description of a JWT authentication plug-in. Refer to the document for specific configuration instructions

    JWT certification plug-in

    .

---
parameter: X-Token         # Obtain the JWT from the specified parameters, corresponding to the parameters of the API
parameterLocation: header  # Optional when the API is in mapping mode. The API is required in transparent mode. It is used to specify the reading location of JWT. Only 'query' and 'header' are supported`
claimParameters:           # When the claims parameter is converted, the gateway will map the jwt claims to the back-end parameters
- claimName: aud           # claim name, supporting public and private
  parameterName: X-Aud     # Parameter name after mapping
  location: header         # The mapped parameter position supports ` query, header, path and formdata`
- claimName: userId        # claim name, supporting public and private
  parameterName: userId    # Parameter name after mapping
  location: query          # The mapped parameter position supports ` query, header, path and formdata`
preventJtiReplay: false    # Enable anti replay check for 'jti'; default: false
#
# `The 'Public Key' of Json Web Key is the Public Key generated in Section 2.1 of this article
jwk:
  kty: RSA
  e: AQAB
  use: sig
  alg: RS256
  n: qSVxcknOm0uCq5vGsOmaorPDzHUubBmZZ4UXj-9do7w9X1uKFXAnqfto4TepSNuYU2bA_-tzSLAGBsR-BqvT6w9SjxakeiyQpVmexxnDw5WZwpWenUAcYrfSPEoNU-0hAQwFYgqZwJQMN8ptxkd0170PFauwACOx4Hfr-9FPGy8NCoIO4MfLXzJ3mJ7xqgIZp3NIOGXz-GIAbCf13ii7kSStpYqN3L_zzpvXUAos1FJ9IPXRV84tIZpFVh2lmRh0h8ImK-vI42dwlD_hOIzayL1Xno2R0T-d5AwTSdnep7g-Fwu8-sj4cCRWq3bd61Zs2QOJ8iustH0vSRMYdP5oYQ

2.4 JWT plug-in binding API

Find the JWT authentication plug-in just created on the plug-in list page, click bind API, add the API under the specified group and environment in the pop-up box to the API list on the right side of the pop-up box, and click OK to finish binding.

At present, the API debugging function of the console does not support JWT plug-ins. It is recommended that users test the API binding JWT plug-ins through Postman or directly apply curl command on the system command line.

3, API gateway error response list

Status

Code

Message

Description

400

I400JR

JWT required

JWT parameter not found

403

S403JI

Claim jti is required when preventJtiReplay:true

When the anti replay function is configured in the JWT authorization plug-in, the request does not provide a valid jti

403

S403JU

Claim jti in JWT is used

When the anti replay function is configured in the JWT authorization plug-in, the requested jti has been used

403

A403JT

Invalid JWT: ${Reason}

The JWT provided in the request is illegal

400

I400JD

JWT Deserialize Failed: ${Token}

The JWT provided in the request failed to resolve

403

A403JK

No matching JWK, kid:${kid} not found

The kid in the request JWT does not have a matching JWK

403

A403JE

JWT is expired at ${Date}

The JWT provided in the request has expired

400

I400JP

Invalid JWT plugin config: ${JWT}

JWT authorization plug-in configuration error

In case of unexpected response code, please check the X-Ca-Error-Code header in the HTTP response to obtain the ErrorCode, and obtain the ErrorMessage from the X-Ca-Error-Message header. In case of A403JT or I400JD error code, you can visit the jwt.io website to check your Token legitimacy and format.

4, Example code of authentication service issuing token

import java.security.PrivateKey; 
import org.jose4j.json.JsonUtil;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jwk.RsaJwkGenerator;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.NumericDate;
import org.jose4j.lang.JoseException;
public class GenerateJwtDemo {
    public static void main(String[] args) throws JoseException  {
          //Use the keyId set in the API gateway
        String keyId = "uniq_key";
          //Use the keyware generated in Section 3.2 of this article
        String privateKeyJson = "{\n"
            + "  \"kty\": \"RSA\",\n"
            + "  \"d\": "
            +
            "\"O9MJSOgcjjiVMNJ4jmBAh0mRHF_TlaVva70Imghtlgwxl8BLfcf1S8ueN1PD7xV6Cnq8YenSKsfiNOhC6yZ_fjW1syn5raWfj68eR7cjHWjLOvKjwVY33GBPNOvspNhVAFzeqfWneRTBbga53Agb6jjN0SUcZdJgnelzz5JNdOGaLzhacjH6YPJKpbuzCQYPkWtoZHDqWTzCSb4mJ3n0NRTsWy7Pm8LwG_Fd3pACl7JIY38IanPQDLoighFfo-Lriv5z3IdlhwbPnx0tk9sBwQBTRdZ8JkqqYkxUiB06phwr7mAnKEpQJ6HvhZBQ1cCnYZ_nIlrX9-I7qomrlE1UoQ\",\n"
            + "  \"e\": \"AQAB\",\n"
            + "  \"kid\": \"myJwtKey\",\n"
            + "  \"alg\": \"RS256\",\n"
            + "  \"n\": \"vCuB8MgwPZfziMSytEbBoOEwxsG7XI3MaVMoocziP4SjzU4IuWuE_DodbOHQwb_thUru57_Efe"
            +
            "--sfATHEa0Odv5ny3QbByqsvjyeHk6ZE4mSAV9BsHYa6GWAgEZtnDceeeDc0y76utXK2XHhC1Pysi2KG8KAzqDa099Yh7s31AyoueoMnrYTmWfEyDsQL_OAIiwgXakkS5U8QyXmWicCwXntDzkIMh8MjfPskesyli0XQD1AmCXVV3h2Opm1Amx0ggSOOiINUR5YRD6mKo49_cN-nrJWjtwSouqDdxHYP-4c7epuTcdS6kQHiQERBd1ejdpAxV4c0t0FHF7MOy9kw\"\n"
            + "}";
        JwtClaims claims = new JwtClaims();
        claims.setGeneratedJwtId();
        claims.setIssuedAtToNow();
        //The expiration time must be set and less than 7 days
        NumericDate date = NumericDate.now();
        date.addSeconds(120*60);
        claims.setExpirationTime(date);
        claims.setNotBeforeMinutesInThePast(1);
        claims.setSubject("YOUR_SUBJECT");
        claims.setAudience("YOUR_AUDIENCE");
        //Add a custom parameter. Please use String type for all values
        claims.setClaim("userId", "1213234");
        claims.setClaim("email", "userEmail@youapp.com");
        JsonWebSignature jws = new JsonWebSignature();
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
          //Must be set
        jws.setKeyIdHeaderValue(keyId);
        jws.setPayload(claims.toJson());
        PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyJson)).getPrivateKey();
        jws.setKey(privateKey);
        String jwtResult = jws.getCompactSerialization();
        System.out.println("Generate Json Web token , result is " + jwtResult);
    }
}

In the above example, the following areas need to be focused:

  1. The keyId needs to be consistent in all three phases and globally unique:

  • keyId filled in when using Section 2.1 to generate key;

  • keyId set in section 3.2.1 of this document;

  • The keyId in the code and the value of KeyIdHeaderValue of JsonWebSignature object. This property is required

  1. Privatekeyjason uses the online generated in Section 2.1

    Keypair

    JSON string (the first of the three boxes) or locally generated

    privateKeyString

    JSON string;

  1. The expiration time must be set and less than 7 days;

  1. Add a custom parameter. Please use String type for all values.

Topics: Java Tomcat