title: jwt-auth

Summary

Name

jwt-auth is an authentication plugin that need to work with consumer. Add JWT Authentication to a service or route.

The consumer then adds its key to the query string parameter, request header, or cookie to verify its request.

For more information on JWT, refer to JWT for more information.

jwt-auth plugin can be integrated with HashiCorp Vault for storing and fetching secrets, RSA key pairs from its encrypted kv engine. See the examples below to have an overview of how things work.

Attributes

NameTypeRequirementDefaultValidDescription
keystringrequireddifferent consumer have different value, it's unique. different consumer use the same key, and there will be a request matching exception.
secretstringoptionalencryption key. if you do not specify, the value is auto-generated in the background.
public_keystringoptionalRSA public key, required when algorithm attribute selects RS256 algorithm.
private_keystringoptionalRSA private key, required when algorithm attribute selects RS256 algorithm.
algorithmstringoptional“HS256”[“HS256”, “HS512”, “RS256”]encryption algorithm.
expintegeroptional86400[1,...]token's expire time, in seconds
base64_secretbooleanoptionalfalsewhether secret is base64 encoded
vaultobjectoptionalwhether vault to be used for secret (secret for HS256/HS512 or public_key and private_key for RS256) storage and retrieval. The plugin by default uses the vault path as kv/apisix/consumer/<consumer name>/jwt-auth for secret retrieval.

Note: To enable vault integration, first visit the config.yaml update it with your vault server configuration, host address and access token. You can take a look of what APISIX expects from the config.yaml at config-default.yaml under the vault attributes.

API

This plugin will add /apisix/plugin/jwt/sign to sign. You may need to use interceptors to protect it.

How To Enable

  1. set a consumer and config the value of the jwt-auth option
curl http://127.0.0.1:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "username": "jack",
    "plugins": {
        "jwt-auth": {
            "key": "user-key",
            "secret": "my-secret-key"
        }
    }
}'

jwt-auth uses the HS256 algorithm by default, and if you use the RS256 algorithm, you need to specify the algorithm and configure the public key and private key, as follows:

curl http://127.0.0.1:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "username": "kerouac",
    "plugins": {
        "jwt-auth": {
            "key": "user-key",
            "public_key": "-----BEGIN PUBLIC KEY-----\n……\n-----END PUBLIC KEY-----",
            "private_key": "-----BEGIN RSA PRIVATE KEY-----\n……\n-----END RSA PRIVATE KEY-----",
            "algorithm": "RS256"
        }
    }
}'
  1. add a Route or add a Service, and enable the jwt-auth plugin
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "methods": ["GET"],
    "uri": "/index.html",
    "plugins": {
        "jwt-auth": {}
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "127.0.0.1:1980": 1
        }
    }
}'

Enable jwt-auth with Vault Compatibility

Sometimes, it‘s quite natural in production to have a centralized key management solution like vault where you don’t have to update the APISIX consumer each time some part of your organization changes the signing secret key (secret for HS256/HS512 or public_key and private_key for RS256) and/or for privacy concerns you don't want to use the key through APISIX admin APIs. APISIX got you covered here. The jwt-auth is capable of referencing keys from vault.

Note: For early version of this integration support, the plugin expects the key name of secrets stored into the vault path is among [ secret, public_key, private_key ] to successfully use the key. In future releases, we are going to add the support of referencing custom named keys.

To enable vault compatibility, just add the empty vault object inside the jwt-auth plugin.

  1. You have stored HS256 signing secret inside vault and you want to use it for jwt signing and verification.
curl http://127.0.0.1:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "username": "jack",
    "plugins": {
        "jwt-auth": {
            "key": "key-1",
            "vault": {}
        }
    }
}'

Here the plugin looks up for key secret inside vault path (<vault.prefix from conf.yaml>/consumer/jack/jwt-auth) for consumer username jack mentioned in the consumer config and uses it for subsequent signing and jwt verification. If the key is not found in the same path, the plugin logs error and fails to perform jwt authentication.

  1. RS256 rsa keypairs, both public and private keys are stored into vault.
curl http://127.0.0.1:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "username": "kowalski",
    "plugins": {
        "jwt-auth": {
            "key": "rsa-keypair",
            "algorithm": "RS256",
            "vault": {}
        }
    }
}'

The plugin looks up for public_key and private_key keys inside vault kv path (<vault.prefix from conf.yaml>/consumer/kowalski/jwt-auth) for username kowalski mentioned inside plugin vault configuration. If not found, authentication fails.

  1. public key in consumer configuration, while the private key is in vault.
curl http://127.0.0.1:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "username": "rico",
    "plugins": {
        "jwt-auth": {
            "key": "user-key",
            "algorithm": "RS256",
            "public_key": "-----BEGIN PUBLIC KEY-----\n……\n-----END PUBLIC KEY-----"
            "vault": {}
        }
    }
}'

This plugin uses rsa public key from consumer configuration and uses the private key directly fetched from vault.

You can use APISIX Dashboard to complete the above operations through the web console.

  1. Add a Consumer through the web console:

create a consumer

then add jwt-auth plugin in the Consumer page: enable jwt plugin

  1. Create a Route or Service object and enable the jwt-auth plugin:

enable jwt from route or service

Test Plugin

Get the Token in jwt-auth Plugin:

  • without extension payload:
$ curl http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i
HTTP/1.1 200 OK
Date: Wed, 24 Jul 2019 10:33:31 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX web server

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI
  • with extension payload:
$ curl -G --data-urlencode 'payload={"uid":10000,"uname":"test"}' http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i
HTTP/1.1 200 OK
Date: Wed, 21 Apr 2021 06:43:59 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.4

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmFtZSI6InRlc3QiLCJ1aWQiOjEwMDAwLCJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTYxOTA3MzgzOX0.jI9-Rpz1gc3u8Y6lZy8I43RXyCu0nSHANCvfn0YZUCY

Try Request with Token

  • without token:
$ curl http://127.0.0.1:9080/index.html -i
HTTP/1.1 401 Unauthorized
...
{"message":"Missing JWT token in request"}
  • request header with token:
$ curl http://127.0.0.1:9080/index.html -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI' -i
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 13175
...
Accept-Ranges: bytes

<!DOCTYPE html>
<html lang="cn">
...
  • request params with token:
$ curl http://127.0.0.1:9080/index.html?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -i
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 13175
...
Accept-Ranges: bytes

<!DOCTYPE html>
<html lang="cn">
...
  • request cookie with token:
$ curl http://127.0.0.1:9080/index.html --cookie jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -i
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 13175
...
Accept-Ranges: bytes

<!DOCTYPE html>
<html lang="cn">
...

Disable Plugin

When you want to disable the jwt-auth plugin, it is very simple, you can delete the corresponding json configuration in the plugin configuration, no need to restart the service, it will take effect immediately:

$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "methods": ["GET"],
    "uri": "/index.html",
    "id": 1,
    "plugins": {},
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "127.0.0.1:1980": 1
        }
    }
}'