jwt-auth
The jwt-auth
plugin supports the use of JSON Web Token (JWT) as a mechanism for clients to authenticate themselves before accessing upstream resources.
Once enabled, the plugin exposes an endpoint to create JWT credentials by consumers. The process generates a token that client requests should carry to identify themselves to APISIX. The token can be included in the request URL query string, request header, or cookie. APISIX will then verify the token to determine if a request should be allowed or denied to access upstream resources.
Examples
The examples below demonstrate how you can work with the jwt-auth
plugin for different scenarios.
Expose JWT Signing Endpoint
The following example demonstrates how to expose the JWT signing endpoint. This is a mandatory step regardless of how you plan to use the plugin.
The jwt-auth
plugin creates an internal endpoint at /apisix/plugin/jwt/sign
to sign JWT. Expose the endpoint with the public-api
plugin:
curl "http://127.0.0.1:9180/apisix/admin/routes/jwt-auth-api" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/apisix/plugin/jwt/sign",
"plugins": {
"public-api": {}
}
}'
Note that at this stage, the jwt-auth
plugin has not been enabled anywhere, so if you send a request to the signing endpoint, you are expected to get a 404 Not Found
. Follow the examples below to see how to use this endpoint in practice.
Use JWT for Consumer Authentication
The following example demonstrates how to implement JWT for consumer authentication and see the token expiration in effect.
Before proceeding, please ensure that the JWT signing endpoint has been exposed.
Create a consumer with jwt-auth
plugin and set the expiration time of the token to 30 seconds:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"exp": 30
}
}
}'
Create a route with jwt-auth
plugin:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "jwt-route",
"uri": "/headers",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Send a request to the signing endpoint to get JWT:
jwt_token=$(curl -s "http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=jack-key") && echo $jwt_token
You should see a token similar to the following:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTAyOTUxMX0.jdZ2iGtXqEMW6QIECTz8CWjBtLt3UMFS9R2j6dVuPJM
Send a request to the route with the JWT in the Authorization
header:
curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"
You should receive an HTTP/1.1 200 OK
response similar to the following:
{
"headers": {
"Accept": "*/*",
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTAyOTUxMX0.jdZ2iGtXqEMW6QIECTz8CWjBtLt3UMFS9R2j6dVuPJM",
"Host": "127.0.0.1",
"User-Agent": "curl/7.74.0",
"X-Amzn-Trace-Id": "Root=1-65081904-5a1f18143c29bd2d7d6be0d7",
"X-Forwarded-Host": "127.0.0.1"
}
}
In 30 seconds, the token should expire. Send a request with the same token to verify:
curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"
You should receive an HTTP/1.1 401 Unauthorized
response similar to the following:
{"message":"failed to verify jwt"}
Carry JWT in Request Header, Query String, or Cookie
The following example demonstrates how to accept JWT in specified header, query string, and cookie.
Before proceeding, please ensure that the JWT signing endpoint has been exposed.
Create a consumer with jwt-auth
plugin:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack",
"plugins": {
"jwt-auth": {
"key": "jack-key"
}
}
}'
Create a route with jwt-auth
plugin, and specify the request parameters carrying the token:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "jwt-route",
"uri": "/get",
"plugins": {
"jwt-auth": {
"header": "jwt-auth-header",
"query": "jwt-query",
"cookie": "jwt-cookie"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Send a request to the signing endpoint to get JWT:
jwt_token=$(curl -s "http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=jack-key") && echo $jwt_token
You should see a token similar to the following:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ
Verify With JWT in Header
Sending request with JWT in the header:
curl -i "http://127.0.0.1:9080/get" -H "jwt-auth-header: ${jwt_token}"
You should receive an HTTP/1.1 200 OK
response similar to the following:
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"Jwt-Auth-Header": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ",
...
},
...
}
Verify With JWT in Query String
Sending request with JWT in the query string:
curl -i "http://127.0.0.1:9080/get?jwt-query=${jwt_token}"
You should receive an HTTP/1.1 200 OK
response similar to the following:
{
"args": {
"jwt-query": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ"
},
"headers": {
"Accept": "*/*",
...
},
"origin": "127.0.0.1, 183.17.233.107",
"url": "http://127.0.0.1/get?jwt-query=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ"
}
Verify With JWT in Cookie
Sending request with JWT in the cookie:
curl -i "http://127.0.0.1:9080/get" --cookie jwt-cookie=${jwt_token}
You should receive an HTTP/1.1 200 OK
response similar to the following:
{
"args": {},
"headers": {
"Accept": "*/*",
"Cookie": "jwt-cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ",
...
},
...
}
Manage Secrets in Environment Variables
The following example demonstrates how to save jwt-auth
consumer key to an environment variable and reference it in configuration.
APISIX supports referencing system and user environment variables configured through the NGINX env
directive.
Before proceeding, please ensure that the JWT signing endpoint has been exposed.
Save the key to an environment variable:
JACK_JWT_AUTH_KEY=jack-key
Create a consumer with jwt-auth
plugin and reference the environment variable:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack",
"plugins": {
"jwt-auth": {
"key": "$ENV://JACK_JWT_AUTH_KEY"
}
}
}'
Create a route with jwt-auth
enabled:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "jwt-route",
"uri": "/get",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Send a request to the signing endpoint to get JWT:
jwt_token=$(curl -s "http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=jack-key") && echo $jwt_token
You should see a token similar to the following:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTUxMzMxNTUsImtleSI6Imp3dC1rZXkifQ.jiKuaAJqHNSSQCjXRomwnQXmdkC5Wp5VDPRsJlh1WAQ
Sending request with JWT in the header:
curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}"
You should receive an HTTP/1.1 200 OK
response similar to the following:
{
"args": {},
"headers": {
"Accept": "*/*",
"Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTUxMzMxNTUsImtleSI6Imp3dC1rZXkifQ.jiKuaAJqHNSSQCjXRomwnQXmdkC5Wp5VDPRsJlh1WAQ",
...
},
...
}
Manage Secrets in Secret Manager
The following example demonstrates how to manage jwt-auth
consumer key in HashiCorp Vault and reference it in plugin configuration.
Start a Vault development server in Docker:
docker run -d \
--name vault \
-p 8200:8200 \
--cap-add IPC_LOCK \
-e VAULT_DEV_ROOT_TOKEN_ID=root \
-e VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \
vault:1.9.0 \
vault server -dev
APISIX currently supports Vault KV engine version 1. Enable it in Vault:
docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault secrets enable -path=kv -version=1 kv"
You should see a response similar to the following:
Success! Enabled the kv secrets engine at: kv/
Create a secret and configure the Vault address and other connection information:
curl "http://127.0.0.1:9180/apisix/admin/secrets/vault/jwt" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "https://127.0.0.1:8200",
"prefix": "kv/apisix",
"token": "root"
}'
Create a consumer and reference the secret in the jwt-auth
plugin:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack",
"plugins": {
"jwt-auth": {
"key": "$secret://vault/jwt/jack/jwt-key"
}
}
}'
Create a route with jwt-auth
enabled:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "jwt-route",
"uri": "/get",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Set jwt-auth
key value to be jwt-vault-key
in Vault:
docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/jack jwt-key=jwt-vault-key"
You should see a response similar to the following:
Success! Data written to: kv/apisix/jack
Before proceeding, please ensure that the JWT signing endpoint has been exposed.
Send a request to the signing endpoint to get JWT:
jwt_token=$(curl -s "http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=jwt-vault-key") && echo $jwt_token
You should see a token similar to the following:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwiZXhwIjoxNjk1MTM4NjM1fQ.Au2liSZ8eQXUJR3SJESwNlIfqZdNyRyxIJK03L4dk_g
Sending request with the token as header:
curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}"
You should receive an HTTP/1.1 200 OK
response similar to the following:
{
"args": {},
"headers": {
"Accept": "*/*",
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwiZXhwIjoxNjk1MTM4NjM1fQ.Au2liSZ8eQXUJR3SJESwNlIfqZdNyRyxIJK03L4dk_g",
...
},
...
}