Alibaba Cloud API Gateway uses JSON Web Token (JWT) to authorize API access based on your user system. This lets you implement custom security measures.
1. Token-based authentication
Overview
Many public APIs must identify callers to determine whether to grant them access to the requested resources. A token is a mechanism used for identity verification. Using tokens, applications do not need to store user authentication or session information on the server. This enables stateless, distributed web application authorization and simplifies application scaling.
Workflow
The preceding figure shows the authentication workflow of the API Gateway JWT plug-in. The workflow is described in the following steps:
A client sends a request that contains a token to API Gateway.
API Gateway uses the public key configured in the JWT plug-in to verify the token in the request. If the token is valid, API Gateway passes the request to the backend service.
The backend service processes the request and returns a response.
API Gateway returns the response from the backend service to the client.
During this process, API Gateway uses the token authentication mechanism to authorize API access based on your user system. The following sections describe JWT, the structured token that API Gateway uses for authentication.
JWT
1.1 Overview
JWT is a JSON-based open standard (RFC 7519) for securely transmitting claims between parties in a web application environment. A JWT can serve as a self-contained authentication token. It can include information such as a user identity, user role, and permissions that allow a client to access resources from a resource server. A JWT can also contain additional claims required by business logic. JWTs are ideal for logon scenarios in distributed sites.
1.2 Composition of a JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQAs shown in the preceding example, a JWT is a string that consists of three parts:
Header
Payload
Signature
Header
The header contains two pieces of information:
The type of the token, which is JWT.
Specifies which encryption algorithm to use.
A complete header is a JSON object, as shown in the following example:
{
'typ': 'JWT',
'alg': 'HS256'
}The header is then Base64url-encoded to form the first part of the JWT.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9Payload
The payload contains the useful information. The details are as follows:
iss: The issuer of the token. This claim is a string that indicates who created the token.
sub: Subject Identifier. The identifier of the end user, provided by the issuer. It is unique within the issuer's scope, case-sensitive, and has a maximum length of 255 ASCII characters.
aud: Audience(s). The recipients that the token is intended for. This is a case-sensitive array of strings.
exp: Expiration time. The timestamp when the token expires. A token becomes invalid after this time. This claim is an integer that represents the number of seconds from 1970-01-01T00:00:00Z.
iat: Issued at. The time at which the token was issued. This claim is an integer that represents the number of seconds from 1970-01-01T00:00:00Z.
jti: JWT ID. The unique identifier for the token. The value of this claim is unique for each token created by the issuer. To prevent conflicts, it is usually a cryptographically random value. This value adds a random entropy component to the structured token that an attacker cannot obtain, which helps prevent token guessing and replay attacks.You can also add custom claims that your user system requires. For example, you can add a name claim for the user's nickname, as shown in the following code:
{
"sub": "1234567890",
"name": "John Doe"
}The payload is then Base64url-encoded to form the second part of the JWT:
JTdCJTBBJTIwJTIwJTIyc3ViJTIyJTNBJTIwJTIyMTIzNDU2Nzg5MCUyMiUyQyUwQSUyMCUyMCUyMm5hbWUlMjIlM0ElMjAlMjJKb2huJTIwRG9lJTIyJTBBJTdESignature
To create the signature, join the Base64-encoded header and the Base64-encoded payload with a period (.). Then, sign the resulting string with the algorithm specified in the header using the private key represented by $secret. This signature forms the third part of the JWT.
// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, '$secret');Concatenate these three parts with a period (.) to form the complete JWT string, as shown in the JWT example at the beginning of this section.
1.3 Authorization scope and validity period
API Gateway grants a token access to all APIs that are bound to the JWT plug-in within the same API group. For finer-grained permission management, your backend service must parse the token and perform its own permission checks. API Gateway validates the `exp` claim in the token. If a token is expired, API Gateway considers it invalid and rejects the request. You must set an expiration time, and the validity period must be less than seven days.
1.4 Characteristics of a JWT
By default, a JWT is not encrypted. Do not include sensitive data in a JWT.
A JWT can be used for authentication and information exchange. Effective use of JWTs can reduce the number of database queries on the server. The main disadvantage of a JWT is its stateless nature. This means you cannot revoke a token or change its permissions before it expires. Once a JWT is issued, it remains valid until its expiration, unless the server deploys additional logic to handle revocation.
A JWT contains authentication information. If it is leaked, anyone can obtain all the permissions associated with the token. To reduce this risk, set a short validity period for JWTs. For actions that require a high level of security, re-authenticate the user before granting access.
To reduce the risk of theft, do not transmit JWTs in plaintext over HTTP. Use HTTPS instead.
2. How to use a JWT plug-in to protect APIs
2.1 Generate a JWK pair
2.1.1 Online generation
You can visit https://tools.top/jwt-encode.html to generate a private key and a public key for token generation and verification. The private key is used by the authorization service to issue JSON Web Keys (JWKs). The public key is configured in the JWT plug-in for API Gateway to verify request signatures. API Gateway supports the RSA SHA256 algorithm and a key size of 2048 bits for key pairs.
2.1.2 Local generation
This section provides an example in Java. You can find similar tools in other programming languages to generate key pairs. First, create a Maven project and add the following dependency:
<dependency>
<groupId>org.bitbucket.b_c</groupId>
<artifactId>jose4j</artifactId>
<version>0.7.0</version>
</dependency>Use the following code to generate an RSA key pair:
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 the JWK to implement a token issuance service
Use the private key JWK JSON string generated online or the privateKeyString JSON string generated locally in Section 2.1 as the private key to issue tokens. These tokens authorize trusted users to access protected APIs. For more information, see Sample code for a token issuance service.
The method for issuing tokens depends on your business scenario. You can deploy the token issuance feature to a production environment and configure it as a standard API. Users can then obtain a token by providing a username and password. Alternatively, you can generate a token in a local environment and provide it directly to a specific user.
2.3 Configure the public key from the JWK in the JWT plug-in
Log on to the API Gateway console.
In the navigation pane on the left, choose .
On the plug-in management page, click Create Plug-in in the upper-right corner.
On the Create Plug-in page, set Plug-in Name and Plug-in Type. The following code shows an example configuration for a JWT authentication plug-in. For more information about the configuration, see JWT authentication plug-in.
---
parameter: X-Token # The parameter from which to obtain the JWT. This corresponds to a parameter of the API.
parameterLocation: header # The location from which to read the JWT. This parameter is optional if the API request mode is mapping. This parameter is required if the API request mode is pass-through. Valid values: query and header.
claimParameters: # Claim parameter conversion. The gateway maps JWT claims to backend parameters.
- claimName: aud # The name of the claim. Public and private claims are supported.
parameterName: X-Aud # The name of the mapped parameter.
location: header # The location of the mapped parameter. Valid values: query, header, path, and formData.
- claimName: userId # The name of the claim. Public and private claims are supported.
parameterName: userId # The name of the mapped parameter.
location: query # The location of the mapped parameter. Valid values: query, header, path, and formData.
preventJtiReplay: false # Specifies whether to enable anti-replay checks for jti. Default value: false.
#
# The public key of the JSON Web Key (JWK), which is the public key part generated in Section 2.1.
jwk:
kty: RSA
e: AQAB
use: sig
kid: uniq_key
alg: RS256
n: qSVxcknOm0uCq5vGsOmaorPDzHUubBmZZ4UXj-9do7w9X1uKFXAnqfto4TepSNuYU2bA_-tzSLAGBsR-BqvT6w9SjxakeiyQpVmexxnDw5WZwpWenUAcYrfSPEoNU-0hAQwFYgqZwJQMN8ptxkd0170PFauwACOx4Hfr-9FPGy8NCoIO4MfLXzJ3mJ7xqgIZp3NIOGXz-GIAbCf13ii7kSStpYqN3L_zzpvXUAos1FJ9IPXRV84tIZpFVh2lmRh0h8ImK-vI42dwlD_hOIzayL1Xno2R0T-d5AwTSdnep7g-Fwu8-sj4cCRWq3bd61Zs2QOJ8iustH0vSRMYdP5oYQ2.4 Bind a JWT plug-in to an API
On the Plug-in Management page, find the JWT authentication plug-in that you created and click Bind API. In the dialog box that appears, select the APIs from the specified group and environment, add them to the list on the right, and then click OK.

The API debugging feature in the API Gateway console does not support the JWT plug-in. To test APIs that are bound to the JWT plug-in, you can use a tool such as Postman or run the curl command.
3. Sample code for a token issuance service
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 API Gateway.
String keyId = "uniq_key";
// Use the key pair generated in Section 2.1.
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 be 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 custom parameters. All values must be of the String type.
claims.setClaim("userId", "1213234");
claims.setClaim("email", "userEm***@youapp.com");
JsonWebSignature jws = new JsonWebSignature();
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
// This parameter is required.
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);
}
}Note the following points about the preceding example:
The
keyIdmust be globally unique and consistent across the following locations:
The
keyIdthat you specify when you generate a key in the Generate a JSON Web Key (JWK) pair section.The
kidthat you configure in the Configure the public key from the JWK in the JWT plug-in section.The
keyIdin the code, which is the value of theKeyIdHeaderValueproperty of theJsonWebSignatureobject. This property is required.
The privateKeyJson parameter is the JWK JSON string of the public key, which is generated online as described in Section 2.1 or locally.
privateKeyStringJSON string.The validity period is required and must be less than seven days.
Use String values for all custom parameters.
4. API Gateway error responses
Status | Code | Message | Description |
400 | I400JR | JWT required | JWT parameter not found. |
403 | S403JI | Claim jti is required when preventJtiReplay:true | The request does not provide a valid jti when the anti-replay feature is enabled in the JWT authentication plug-in. |
403 | S403JU | Claim jti in JWT is used | The jti provided in the request has been used when the anti-replay feature is enabled in the JWT authentication plug-in. |
403 | A403JT | Invalid JWT: ${Reason} | The JWT provided in the request is invalid. |
400 | I400JD | JWT Deserialize Failed: ${Token} | Failed to parse the JWT provided in the request. |
403 | A403JK | No matching JWK, kid:${kid} not found | The kid in the request JWT does not match any JWK. |
403 | A403JE | JWT is expired at ${Date} | The JWT provided in the request has expired. |
400 | I400JP | Invalid JWT plugin config: ${JWT} | Incorrect JWT authentication plug-in configuration. |
If you receive an unexpected status code, check the X-Ca-Error-Code header in the HTTP response to obtain the ErrorCode and the X-Ca-Error-Message header to obtain the ErrorMessage. If the error code is A403JT or I400JD, you can use the jwt.io website to check the validity and format of your token.