All Products
Search
Document Center

API Gateway:jwt-auth plugin

Last Updated:Jun 22, 2026

The jwt-auth plugin authenticates and authorizes requests based on JSON Web Tokens (JWT). It parses a JWT from URL parameters, request headers, or cookies and verifies the token to grant or deny access. Unlike JWT authentication and authorization, this plugin also identifies callers, allowing you to configure different JWT credentials for each caller.

Configuration fields

Authentication configuration

Name

Data type

Required

Default value

Description

consumers

array of object

Required

-

The service consumers used for request authentication.

global_auth

Array of strings

Optional (instance-level configuration only)

-

Can only be configured at the instance level. If set to true, authentication applies globally. If set to false, authentication applies only to configured domain names and routes. If not configured, authentication applies globally only when no domain name or route configurations exist, maintaining backward compatibility.

The following table describes the fields for each item in consumers.

Name

Data type

Required

Default value

Description

name

string

Required

-

The name of the consumer.

jwks

string

Optional. `jwks` or `remote_jwks` is required.

-

A JSON Web Key Set (JWKS) string as specified by JSON Web Key (JWK), containing the public key or symmetric key used to verify the JWT signature.

remote_jwks

object

Optional. Choose either `jwks` or `remote_jwks`.

{"uri":"http://127.0.0.1/keys","service":"test.static","port":"80","ttl":30000,"timeout":3000}

Periodically pulls the JWKS from a specified service URI. If both `jwks` and `remote_jwks` are configured, the remotely pulled JWKS takes precedence.

Note

The size of the JWKS returned by `remote_jwks` should be less than 1 MB. If the size exceeds this limit and an error occurs, join DingTalk group 88010006189 or submit a ticket for support.

issuer

string

Optional

-

The issuer of the JWT. This must match the `iss` field in the payload.

claims

object

Optional

-

The key-value pairs that correspond to the key-value pairs in the payload, used to verify that multiple fields match the payload. For example, if you configure `aud: mobile-site`, the `aud` field in the payload must be `mobile-site`.

claims_to_headers

array of object

Optional

-

Extracts specified fields from the JWT payload and sets them as request headers before forwarding to the backend.

from_headers

array of object

Optional

[{"name":"Authorization","value_prefix":"Bearer"}]

Extracts the JWT from the specified request headers.

from_params

array of string

Optional

access_token

Extracts the JWT from the specified URL parameters.

from_cookies

array of string

Optional

-

Extracts the JWT from the specified cookies.

clock_skew_seconds

number

Optional

60

The allowed clock skew in seconds when verifying the `exp` and `iat` fields of the JWT.

keep_token

bool

Optional

true

Whether to keep the JWT when forwarding the request to the backend.

Note

The default values are used only when from_headers, from_params, and from_cookies are not configured.

  • The following table describes the fields for each item in from_headers.

    Name

    Data type

    Required

    Default value

    Description

    name

    string

    Required

    -

    The request header from which the JWT is extracted.

    value_prefix

    string

    required

    -

    The prefix to remove from the header value. The remaining part is treated as the JWT.

  • The following table describes the fields for each item in claims_to_headers.

    Name

    Data type

    Required

    Default value

    Description

    claim

    string

    Required

    -

    A specified field in the JWT payload. The value must be a string or unsigned integer.

    header

    string

    Required

    -

    The request header to populate with the extracted claim value and forward to the backend.

    override

    bool

    Optional

    true

    • If true, overwrites the request header if it has the same name.

    • If false, appends the value as a duplicate request header.

  • The following table describes the fields for each item in remote_jwks.

    Name

    Data type

    Required

    Default value

    Description

    uri

    string

    Required

    -

    The request URL.

    service

    string

    Required

    -

    • Example for a Kubernetes service: foo.default.svc.cluster.local.

    • Example for a Nacos service: foo.DEFAULT-GROUP.public.nacos.

    • For a DNS service named test, enter test.dns.

    • For a static IP service named test, enter test.static.

    port

    bool

    Required

    -

    The service port.

    timeout

    bool

    Optional

    3000

    The service request timeout in milliseconds.

    ttl

    bool

    Optional

    30000

    The cache duration in milliseconds.

Authorization configuration (optional)

Name

Data type

Required

Default value

Description

allow

array of string

Optional (not for instance-level configuration)

-

Can only be configured on fine-grained rules such as routes or domain names. Specifies which consumers are allowed to access the matched resource.

Important
  • Authorization and authentication configurations cannot be used in the same rule.

  • For requests that pass authentication and authorization, an X-Mse-Consumer header is added to the request to identify the caller's name.

Configuration examples

Configure global authentication and route-level authorization

This example enables global JWT authentication at the instance level and restricts route-level access to specific consumers.

Note

If a JWT can match multiple JWKS, the first matching consumer in the configuration order is used.

Plugin configuration

Configure the plugin at the instance level as follows:

consumers:
- name: consumer1
  issuer: abcd
  jwks: |
    {
      "keys": [
        {
          "kty": "oct",
          "kid": "123",
          "k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
          "alg": "HS256"
        }
      ]
    }
- name: consumer2
  issuer: abc
  jwks: |
    {
      "keys": [
        {
          "kty": "RSA",
          "e": "AQAB",
          "use": "sig",
          "kid": "123",
          "alg": "RS256",
          "n": "i0B67f1jggT9QJlZ_8QL9QQ56LfurrqDhpuu8BxtVcfxrYmaXaCtqTn7OfCuca7cGHdrJIjq99rz890NmYFZuvhaZ-LMt2iyiSb9LZJAeJmHf7ecguXS_-4x3hvbsrgUDi9tlg7xxbqGYcrco3anmalAFxsbswtu2PAXLtTnUo6aYwZsWA6ksq4FL3-anPNL5oZUgIp3HGyhhLTLdlQcC83jzxbguOim-0OEz-N4fniTYRivK7MlibHKrJfO3xa_6whBS07HW4Ydc37ZN3Rx9Ov3ZyV0idFblU519nUdqp_inXj1eEpynlxH60Ys_aTU2POGZh_25KXGdF_ZC_MSRw"
        }
      ]
    }

Route and domain name configuration

For the route-a and route-b routes, configure the plugin as follows:

allow:
- consumer1

For the *.example.com and test.com domain names, configure the plugin as follows:

allow:
- consumer2
Note
  • In this example, route-a and route-b are the route names entered when you create the gateway routes. When a request matches these routes, callers with the name consumer1 are allowed access. Other callers are denied access.

  • In this example, *.example.com and test.com are used to match the request's domain name. When the domain name matches, callers with the name consumer2 are allowed access. Other callers are denied access.

Request examples

The following requests are allowed under this configuration. These examples assume the requests match the `route-a` route.

  • Set the JWT in a URL parameter.

    curl  'http://xxx.hello.com/test?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEy****.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
  • Set the JWT in an HTTP request header.

    curl  http://xxx.hello.com/test -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'

Verify the result

After successful authentication, the X-Mse-Consumer header is added to the request with the caller's name. In this example, its value is consumer1.

The following requests will be denied.

  • The request does not provide a JWT, so a 401 error is returned.

  • The caller matched by the provided JWT does not have access permission, so a 403 error is returned.

Enable at the gateway instance level but disable for a specific route

Configure the plugin at the instance level as follows:

global_auth: true
consumers:
- name: consumer1
  issuer: abcd
  jwks: |
    {
      "keys": [
        {
          "kty": "oct",
          "kid": "123",
          "k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
          "alg": "HS256"
        }
      ]
    }
- name: consumer2
  issuer: abc
  jwks: |
    {
      "keys": [
        {
          "kty": "RSA",
          "e": "AQAB",
          "use": "sig",
          "kid": "123",
          "alg": "RS256",
          "n": "i0B67f1jggT9QJlZ_8QL9QQ56LfurrqDhpuu8BxtVcfxrYmaXaCtqTn7OfCuca7cGHdrJIjq99rz890NmYFZuvhaZ-LMt2iyiSb9LZJAeJmHf7ecguXS_-4x3hvbsrgUDi9tlg7xxbqGYcrco3anmalAFxsbswtu2PAXLtTnUo6aYwZsWA6ksq4FL3-anPNL5oZUgIp3HGyhhLTLdlQcC83jzxbguOim-0OEz-N4fniTYRivK7MlibHKrJfO3xa_6whBS07HW4Ydc37ZN3Rx9Ov3ZyV0idFblU519nUdqp_inXj1eEpynlxH60Ys_aTU2POGZh_25KXGdF_ZC_MSRw"
        }
      ]
    }

For the route-b route, configure the plugin as follows:

_disable_: true

In this example, route-b is the route name entered when you create the gateway route. Because _disable_ is set to true, when a request matches this route, the plugin is disabled. No JWT authentication is performed, and all users are allowed access.

For requests that do not match the route-b route, JWT authentication is performed because global_auth is set to true at the instance level. Both consumer1 and consumer2 are allowed access.

Enable at the domain name level but disable for a specific route

Configure the plugin at the instance level as follows:

consumers:
- name: consumer1
  issuer: abcd
  jwks: |
    {
      "keys": [
        {
          "kty": "oct",
          "kid": "123",
          "k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
          "alg": "HS256"
        }
      ]
    }
- name: consumer2
  issuer: abc
  jwks: |
    {
      "keys": [
        {
          "kty": "RSA",
          "e": "AQAB",
          "use": "sig",
          "kid": "123",
          "alg": "RS256",
          "n": "i0B67f1jggT9QJlZ_8QL9QQ56LfurrqDhpuu8BxtVcfxrYmaXaCtqTn7OfCuca7cGHdrJIjq99rz890NmYFZuvhaZ-LMt2iyiSb9LZJAeJmHf7ecguXS_-4x3hvbsrgUDi9tlg7xxbqGYcrco3anmalAFxsbswtu2PAXLtTnUo6aYwZsWA6ksq4FL3-anPNL5oZUgIp3HGyhhLTLdlQcC83jzxbguOim-0OEz-N4fniTYRivK7MlibHKrJfO3xa_6whBS07HW4Ydc37ZN3Rx9Ov3ZyV0idFblU519nUdqp_inXj1eEpynlxH60Ys_aTU2POGZh_25KXGdF_ZC_MSRw"
        }
      ]
    }

For the route-b route, configure the plugin as follows:

_disable_: true

For the *.example.com domain name, configure the plugin as follows:

allow:
- consumer1
- consumer2

In this example, route-b is the route name entered when you create the gateway route. Because _disable_ is set to true, when a request matches this route, the plugin is disabled. No JWT authentication is performed, and all users are allowed access.

In this example, *.example.com is used to match the request's domain name. When the domain name matches, callers with the name consumer1 or consumer2 are allowed access. Other callers are denied access.

Rules are matched sequentially: the first match is applied and no further rules are evaluated. Route rules take priority over domain name rules, so you can enable the plugin for a domain name but disable it for a specific route under that domain.

Related error codes

HTTP status code

Error message

Cause

401

Jwt missing

The request header does not provide a JWT.

401

Jwt expired

The JWT has expired.

401

Jwt verification fails

JWT payload validation failed. For example, the `iss` does not match.

403

Access Denied

No permission to access the current route.