All Products
Search
Document Center

API Gateway:jwt-logout

Last Updated:Jun 22, 2026

The jwt-logout plug-in uses Redis to implement weak state management for JSON Web Tokens (JWTs), enabling proactive JWT invalidation and single-device logon control. For example, when a user logs on from a new device, the previous session is automatically invalidated.

Plug-in type

Plug-in for authentication and authorization.

Fields

Field

Data type

Required

Default value

Description

jwks

string

No

-

JSON string for JWT verification. Not required when this plug-in is used with the jwt-auth plug-in. For more information, see JSON Web Key (JWK).

clock_skew

number

No

60

Allowed clock skew when the exp and iat fields in a JWT are verified. Unit: seconds.

token_header

string

No

Authorization

Request header from which the JWT is extracted.

token_prefix

string

No

"Bearer"

Prefix of the header value. After the prefix is removed, the remaining part is used as the JWT.

redis

Redis

Yes

-

Redis service configuration.

logout

Logout

No

-

Configuration for the JWT logoff feature. If not configured, JWT logoff is disabled.

login

Login

No

-

Configuration for the JWT single-device logon feature. If not configured, single-device logon is disabled.

The following table describes the configuration fields of the Redis type.

Field

Data type

Required

Default value

Description

service

string

Yes

-

Name of the Redis service. Examples:

  • Fixed address: my-redis.static

  • DNS domain name: my-redis.dns

  • ACK: my-redis.default.svc.cluster.local

port

number

Yes

-

Port number of the Redis service.

username

string

No

-

Username for the Redis AUTH command.

password

string

No

-

Password for the Redis AUTH command.

timeout

number

No

1000

Timeout period for Redis commands. Unit: milliseconds.

The following table describes the configuration fields of the Logout type.

Field

Data type

Required

Default value

Description

key_prefix

string

No

higress_jwt_logout_

Prefix of the key stored in Redis.

key

array of string

No

["jti"]

Key in the JWT payload that identifies a JWT. If the same key appears in multiple JWT payloads, the JWTs are treated as identical. If the key is absent from the JWT payload, a 401 invalid token error is returned.

path

string

No

/jwt_logout

String used to match the URL path suffix. If matched, the JWT in the current request is invalidated and can no longer be used.

error_status

number

No

401

HTTP status code returned when a logged-off JWT is used.

error_body

string

No

'{"message":"invalid token"}'

Response body returned when a logged-off JWT is used.

ttl

number

No

-

Time to live (TTL) of the key stored in Redis. Unit: seconds. Determines how long the JWT remains invalidated after logoff. If not specified, the TTL equals the value of the exp field in the payload minus the current time. If the payload does not contain the exp field, the default TTL is 86,400 seconds (24 hours).

The following table describes the configuration fields of the Login type.

Field

Data type

Required

Default value

Description

key_prefix

string

No

higress_jwt_logout_

Prefix of the key stored in Redis.

key

array of string

No

["iss","aud","sub"]

Single-device logon identifier in the JWT payload. If the current request JWT contains the same field values as a previously authenticated JWT but is not the exact same JWT, the request is rejected as a duplicate logon. Access is denied until the Redis key for the authenticated JWT expires. If the field is absent from the JWT payload, a 401 invalid token error is returned.

path

string

No

/jwt_login

String used to match the URL path suffix. If matched, the current request JWT becomes the active session token, and any previously authenticated JWT with the same payload characteristics is invalidated.

error_status

number

No

403

HTTP status code returned for duplicate logon attempts.

error_body

string

No

'{"message":"already login on other device"}'

Response body returned for duplicate logon attempts.

ttl

number

No

-

TTL of the key stored in Redis. Unit: seconds. Determines the validity period of a single-device logon JWT. If not specified, the TTL equals the value of the exp field in the payload minus the current time. If the payload does not contain the exp field, the default TTL is 86,400 seconds (24 hours).

Configuration examples

Use an ApsaraDB for Redis instance

  1. Create an ApsaraDB for Redis instance. For more information, see Overview.

  2. Enable the logoff and logon configurations. When the plug-in processes a request, one Redis read request for logoff configuration checking and two Redis read requests for logon configuration checking are generated. In rare cases such as a logoff or first-time logon, two additional Redis write requests are generated. To estimate the capacity of the ApsaraDB for Redis instance, you can multiply the throughput of requests processed by the plug-in by 2.

  3. After you configure the ApsaraDB for Redis instance, obtain the VPC endpoint of the instance. Example: r-xxxxxxx.redis.rds.aliyuncs.com.

  4. Add a service. Select DNS Domain Name from the Service Source drop-down list, enter the Redis port number (6379 in most cases) in the Service Port field, enter the VPC endpoint in the Domain Names field, and select Disabled from the TLS Mode drop-down list. For more information, see Create a service.

  5. Add the following content to the plug-in configuration to connect to the ApsaraDB for Redis instance:

    redis:
      service: redis.dns
      port: 6379

    If you configure a password for the Redis service, add the following content:

    redis:
      service: redis.dns
      port: 6379
      password: ****** # Enter the password that you specify.

Implement the JWT logoff feature

Use scenarios

JWTs are stateless tokens that remain valid until expiration. Use the jwt-logout plug-in to force-invalidate a specific JWT before it expires.

How it works

  • If the suffix of the request path matches the path in the plug-in configuration, the logoff mechanism is triggered. The ApsaraDB for Redis instance records the JWT for the logoff. The key stored in the ApsaraDB for Redis instance consists of the configured prefix and the key and value extracted from the current JWT payload.

  • If the payload of the JWT carried in the request matches the characteristics of the key stored in the ApsaraDB for Redis instance, the system considers the current JWT invalid and rejects the request.

  • The default expiration time of the key stored in the ApsaraDB for Redis instance is calculated based on the exp field in the JWT payload. This means that the key can be stored until the JWT expires.

Note
  • The default recommended logoff key of the plug-in is ["jti"], in which jti is the payload field that uniquely identifies a JWT. As specified in JWT standards, if the jti value in the JWT payload is the same as that recorded in the ApsaraDB for Redis instance, the entire JWT is exactly the same. Therefore, jti can be used to mark the logoff status of a JWT.

  • The concatenation rule of the key stored in the ApsaraDB for Redis instance: <key_prefix><PayloadKey>##<PayloadValue>. PayloadKey is a list of keys that are delimited by number signs (#). PayloadValue is a list of key values that are delimited by number signs (#). Example: higress_jwt_logout_jti#iss##xxxxx#abcde.

  • This plug-in can only invalidate the token that is carried in the current request during the logoff. You can also manually specify the token in the ApsaraDB for Redis console based on the preceding key concatenation rule. If the gateway finds that the key exists in the ApsaraDB for Redis instance, the gateway rejects the access request that is based on the relevant JWT.

Example

Plug-in configuration:

redis:
  service: redis.dns
  port: 6379
jwks: |
  {
    "keys": [
      {
        "kty": "oct",
        "kid": "123",
        "k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
        "alg": "HS256"
      }
    ]
  }
logout:
  path: "/jwt_logout"
  key: ["jti"]
  error_status: 401
  error_body: |
    {"message":"invalid token"}
  1. Trigger a logoff.

    curl  http://xxx.hello.com/test/jwt_logout -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ4eHh4IiwiaXNzIjoiYWJjZCIsInN1YiI6InRlc3QiLCJhdWQiOiJ3d3cudGVzdC5jb20iLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.tmKF6qc1mOWNyCCzBOT2XKNoEGeEgr3EbhTKAQfq1io'
    
    # The following result is returned:
    {"message": "logout success"}

    Token payload:

    {
        "jti": "xxxx",
        "iss": "abcd",
        "sub": "test",
        "aud": "www.test.com",
        "iat": 1665660527,
        "exp": 1865673819
    }

    In this case, the key higress_jwt_logout_jti##xxxx is stored in the ApsaraDB for Redis instance.

  2. After the logoff, access based on the JWT is not allowed.

    curl  http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ4eHh4IiwiaXNzIjoiYWJjZCIsInN1YiI6InRlc3QiLCJhdWQiOiJ3d3cudGVzdC5jb20iLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.tmKF6qc1mOWNyCCzBOT2XKNoEGeEgr3EbhTKAQfq1io'
    
    # The following result is returned:
    {"message":"invalid token"}

Implement forced logoff based on JWTs

Use scenarios

When an account logs on from multiple devices with JWT authentication, different JWTs may be issued for each device. Use the jwt-logout plug-in to enforce single-device logon so only one session remains active at a time.

How it works

  • When a request is initiated, the system extracts the JWT from the current request and constitutes a Redis key based on the configured prefix and the key and value extracted from the current JWT payload. Then, the system queries the value that corresponds to the key in the ApsaraDB for Redis instance. If the value is inconsistent with the key value of the current JWT, the system rejects the access request.

  • If the value does not exist, the current JWT is written to the Redis key. The default expiration time of the key in the ApsaraDB for Redis instance is calculated based on the exp field in the JWT payload. This means that the key can be stored until the JWT expires. During the validity period of the JWT, access requests based on other JWTs that have the same payload characteristics are not allowed.

  • If the request suffix matches the path in the plug-in configuration, the forced logoff mechanism is triggered and the current JWT is written to the value of the associated Redis key. The JWT that is used for a successful logon and has the same payload characteristics is invalidated upon logoff. This ensures single-device logon.

Note
  • The default recommended logon key of the plug-in is ["iss","aud","sub"]. In the key, iss indicates the JWT issuer, aud indicates the JWT use scenario, and sub indicates the subject of the JWT. In most cases, the combination can be used to ensure single-device logon.

  • The concatenation rule of the key stored in the ApsaraDB for Redis instance: <key_prefix><PayloadKey>##<PayloadValue>. PayloadKey is a list of keys that are delimited by number signs (#). PayloadValue is a list of key values that are delimited by number signs (#). Example: higress_jwt_login_iss#aud#sub##xxxxx#abcde#fffff.

  • For the JWTs that have the same payload characteristics, the first JWT used for requests is automatically written to the ApsaraDB for Redis instance. This helps implement the single-device logon feature of the plug-in. Therefore, you do not need to call the API operation for forced logon. You need to call the API operation only when forced logoff is required in logon scenarios.

  • When you trigger the logoff logic, the logon key of the current JWT stored in the ApsaraDB for Redis instance is cleared. This rule also applies when you enable the JWT logoff feature.

Example

Plug-in configuration:

redis:
  service: redis.dns
  port: 6379
jwks: |
  {
    "keys": [
      {
        "kty": "oct",
        "kid": "123",
        "k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
        "alg": "HS256"
      }
    ]
  }
login:
  path: "/jwt_login"
  key: ["iss","aud","sub"]
  error_status: 403
  error_body: |
    {"message":"already login on other device"}
  1. Perform a successful logon operation.

    curl  http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ6enp6IiwiaXNzIjoiYWJjZCIsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6InRlc3QiLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.WljMr5ucxfLF8SmeaaL25c0QG3IX04HoD0als9gglYg'

    Token payload:

    {
        "jti": "zzzz",
        "iss": "abcd",
        "aud": "www.example.com",
        "sub": "test",
        "iat": 1665660527,
        "exp": 1865673819
    }

    In this case, the key higress_jwt_login_iss#aud#sub##abcd#www.example.com#abcd is stored in the ApsaraDB for Redis instance and the value is the same as that in the current JWT.

  2. Reject an access request when the JWT payload in the request has the same payload characteristics.

    curl  http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ5eXl5eSIsImlzcyI6ImFiY2QiLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjY1NjYwNTI5LCJleHAiOjE4NjU2NzM4MTl9.6vi6eKPWSKHQxfzBPrj3-SWI4Q5zGtWhqp38JIN3FEo'
    
    # The following result is returned:
    {"message":"already login on other device"}

    Token payload:

    {
        "jti": "yyyyy",
        "iss": "abcd",
        "aud": "www.example.com",
        "sub": "test",
        "iat": 1665660527,
        "exp": 1865673819
    }

    The payload characteristics are the same for the current JWT and the JWT in Step 1. However, the non-characteristic field jti is different between the two JWTs. Therefore, the access request based on the JWT is rejected.

  3. Perform a forced logon.

    curl  http://xxx.hello.com/test/jwt_login -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ5eXl5eSIsImlzcyI6ImFiY2QiLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjY1NjYwNTI5LCJleHAiOjE4NjU2NzM4MTl9.6vi6eKPWSKHQxfzBPrj3-SWI4Q5zGtWhqp38JIN3FEo'
    
    # The following result is returned:
    {"message":"login success"}

    In this case, the key higress_jwt_login_iss#aud#sub##abcd#www.example.com#abcd is stored in the ApsaraDB for Redis instance and the value is replaced by the value in the current JWT.

    Use the current JWT to successfully access the page.

    curl  http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ5eXl5eSIsImlzcyI6ImFiY2QiLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjY1NjYwNTI5LCJleHAiOjE4NjU2NzM4MTl9.6vi6eKPWSKHQxfzBPrj3-SWI4Q5zGtWhqp38JIN3FEo'

    If you use the JWT in Step 1, a failure message is returned.

    curl  http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ4eHh4IiwiaXNzIjoiYWJjZCIsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6InRlc3QiLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.P0WtBTHJzUJvklu9q8XSRszfPbgojrZHg7t4ZaYfKGo'
    
    # The following result is returned:
    {"message":"already login on other device"}

Error codes

HTTP status code

Error message

Reason

401

invalid token

No JWT is provided in the request header, the JWT format is invalid, or the JWT is expired or has been invalidated.

500

redis server error

The ApsaraDB for Redis instance is unreachable or the connection timed out.