jwt-logout

更新时间:
复制 MD 格式

The jwt-logout plug-in uses Redis to add weak state management to JSON Web Tokens (JWTs), enabling proactive logoff for otherwise stateless tokens. You can also use the plug-in to enforce single-device logon — for example, automatically logging off an account from one device when the account logs on from another.

Plug-in type

Authentication and authorization.

Fields

Field

Data type

Required

Default value

Description

jwks

string

No

-

The JSON string used to verify a JWT. When this plug-in is used together with the jwt-auth plug-in, you do not need to configure this field. For more information, see JSON Web Key (JWK).

clock_skew

number

No

60

The allowed clock skew when the exp and iat fields in a JWT are validated. Unit: seconds.

token_header

string

No

Authorization

The request header from which the JWT is extracted.

token_prefix

string

No

"Bearer"

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

redis

Redis

Yes

-

The Redis service configuration.

logout

Logout

No

-

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

login

Login

No

-

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

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

Field

Data type

Required

Default value

Description

service

string

Yes

-

The 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

-

The port number of the Redis service.

username

string

No

-

The username that is used in the Redis AUTH command.

password

string

No

-

The password that is used in the Redis AUTH command.

timeout

number

No

1000

The timeout period for a Redis command. 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_

The prefix of the key stored in Redis.

key

array of string

No

["jti"]

The key in the JWT payload that identifies the JWT. If multiple JWTs share the same key value, they are treated as the same token. If the key is absent from the JWT payload, a 401 invalid token error is returned.

path

string

No

/jwt_logout

The URL path suffix used to trigger logoff. When the URL path suffix matches the specified string, the account associated with the JWT in the current request is logged off. The JWT is then invalidated.

error_status

number

No

401

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

error_body

string

No

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

The response body returned when a logged-off JWT is used.

ttl

number

No

-

The 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_

The prefix of the key stored in Redis.

key

array of string

No

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

The single-device logon identifier in the JWT payload. If the JWT payload in the current request contains the same field values but a different JWT, the system treats it as a duplicate logon and rejects the request. The request is allowed once the Redis key for the previous JWT expires. If the JWT payload does not contain the field, a 401 invalid token error is returned.

path

string

No

/jwt_login

The URL path suffix used to trigger forced logon. When the URL path suffix matches the specified string, the account is force-logged on with the JWT in the current request. Any previously logged-on JWT with the same payload characteristics is invalidated.

error_status

number

No

403

The HTTP status code returned for duplicate logons.

error_body

string

No

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

The response body for duplicate logons.

ttl

number

No

-

The TTL of the key stored in Redis. Unit: seconds. Determines the validity period of a JWT used for single-device logon. 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. For DNS Domain Name, select DNS Domain Name. Set the service port to the Redis port (typically 6379), enter the VPC endpoint in the DNS Domain Name field, and for TLS Mode, select TLS Mode. 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 they expire. The jwt-logout plug-in lets you forcibly invalidate a specific JWT before expiration.

How it works

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

  • If the JWT payload in the request matches the characteristics of a key stored in the ApsaraDB for Redis instance, the JWT is treated as invalid and the request is rejected.

  • The default key expiration time is calculated from the exp field in the JWT payload, so the key persists until the JWT expires.

Note
  • The default recommended logoff key is ["jti"], where jti is the payload field that uniquely identifies a JWT. Per the JWT standard, if the jti value in the JWT payload matches the value recorded in the ApsaraDB for Redis instance, the JWT is the same token. Therefore, jti can 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 carried in the current request during logoff. You can also manually add a key in the ApsaraDB for Redis console using the key concatenation rule described above. If the gateway finds that key in the ApsaraDB for Redis instance, it rejects any access request based on the corresponding 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 with the same JWT is rejected.

    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 is logged on to multiple devices with JWT authentication, different JWTs may be issued on each device. The jwt-logout plug-in can restrict the account to a single active device at a time.

How it works

  • When a request arrives, the system extracts the JWT and constructs a Redis key from the configured prefix and the key-value pair in the JWT payload. It then queries the corresponding value in the ApsaraDB for Redis instance. If the stored value does not match the current JWT, the request is rejected.

  • If no value exists, the current JWT is written to the Redis key. The default key expiration time is calculated from the exp field in the JWT payload, so the key persists until the JWT expires. During the JWT's validity period, requests using other JWTs with the same payload characteristics are rejected.

  • If the request suffix matches the path in the plug-in configuration, the forced logon mechanism is triggered and the current JWT overwrites the associated Redis key. The previously logged-on JWT with the same payload characteristics is invalidated, ensuring single-device logon.

Note
  • The default recommended logon key is ["iss","aud","sub"]. In the key, iss indicates the JWT issuer, aud indicates the intended audience, and sub indicates the subject. In most cases, this combination is sufficient to enforce 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 JWTs with the same payload characteristics, the first JWT used in a request is automatically written to the ApsaraDB for Redis instance, enabling single-device logon without an explicit API call. You only need to call the forced logon API when you want to force-replace the active session.

  • When the logoff logic is triggered, the logon key of the current JWT stored in the ApsaraDB for Redis instance is also cleared. This 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 the request when a different JWT with the same payload characteristics is used.

    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 match those of the JWT in Step 1, but the jti field differs. Therefore, the request 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 has expired.

500

redis server error

The ApsaraDB for Redis instance timed out or is unreachable.