Yilialinn commented on code in PR #11865: URL: https://github.com/apache/apisix/pull/11865#discussion_r2000485887
########## docs/en/latest/plugins/jwt-auth.md: ########## @@ -28,48 +28,55 @@ description: This document contains information about the Apache APISIX jwt-auth # --> +<head> + <link rel="canonical" href="https://docs.api7.ai/hub/jwt-auth" /> +</head> + ## Description -The `jwt-auth` Plugin is used to add [JWT](https://jwt.io/) authentication to a [Service](../terminology/service.md) or a [Route](../terminology/route.md). +The `jwt-auth` plugin supports the use of [JSON Web Token (JWT)](https://jwt.io/) 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](../terminology/consumer.md). 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. -A [Consumer](../terminology/consumer.md) of the service then needs to provide a key through a query string, a request header or a cookie to verify its request. +When a Consumer is successfully authenticated, APISIX adds additional headers, such as `X-Consumer-Username`, `X-Credential-Indentifier`, and other Consumer custom headers if configured, to the request, before proxying it to the Upstream service. The Upstream service will be able to differentiate between consumers and implement additional logics as needed. If any of these values is not available, the corresponding header will not be added. ## Attributes -For Consumer: +For Consumer/Credential: | Name | Type | Required | Default | Valid values | Description | |---------------|---------|-------------------------------------------------------|---------|-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | key | string | True | | | Unique key for a Consumer. | Review Comment: ```suggestion | key | string | True | | non-empty | Unique key for a Consumer. | ``` ########## docs/en/latest/plugins/jwt-auth.md: ########## @@ -28,48 +28,55 @@ description: This document contains information about the Apache APISIX jwt-auth # --> +<head> + <link rel="canonical" href="https://docs.api7.ai/hub/jwt-auth" /> +</head> + ## Description -The `jwt-auth` Plugin is used to add [JWT](https://jwt.io/) authentication to a [Service](../terminology/service.md) or a [Route](../terminology/route.md). +The `jwt-auth` plugin supports the use of [JSON Web Token (JWT)](https://jwt.io/) as a mechanism for clients to authenticate themselves before accessing Upstream resources. Review Comment: ```suggestion The `jwt-auth` Plugin supports the use of [JSON Web Token (JWT)](https://jwt.io/) as a mechanism for clients to authenticate themselves before accessing Upstream resources. ``` ########## docs/en/latest/plugins/jwt-auth.md: ########## @@ -28,48 +28,55 @@ description: This document contains information about the Apache APISIX jwt-auth # --> +<head> + <link rel="canonical" href="https://docs.api7.ai/hub/jwt-auth" /> +</head> + ## Description -The `jwt-auth` Plugin is used to add [JWT](https://jwt.io/) authentication to a [Service](../terminology/service.md) or a [Route](../terminology/route.md). +The `jwt-auth` plugin supports the use of [JSON Web Token (JWT)](https://jwt.io/) as a mechanism for clients to authenticate themselves before accessing Upstream resources. Review Comment: Update accordingly ########## docs/en/latest/plugins/jwt-auth.md: ########## @@ -78,154 +85,827 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ::: +### Use JWT for Consumer Authentication + +The following example demonstrates how to implement JWT for Consumer key authentication. + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } + } + }' +``` + +Create a Route with `jwt-auth` plugin: + ```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d ' +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/headers", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` + +Send a request to the Route with the JWT in the `Authorization` header: + +```shell +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: + +```text { - "username": "jack", + "headers": { + "Accept": "*/*", + "Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjUvYzWLt4lFr546PNsr9TXuf0Az5opoM", + "Host": "127.0.0.1", + "User-Agent": "curl/8.6.0", + "X-Amzn-Trace-Id": "Root=1-66ea951a-4d740d724bd2a44f174d4daf", + "X-Consumer-Username": "jack", + "X-Credential-Identifier": "cred-jack-jwt-auth", + "X-Forwarded-Host": "127.0.0.1" + } +} +``` + +In 30 seconds, the token should expire. Send a request with the same token to verify: + +```shell +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: + +```text +{"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. + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", "plugins": { - "jwt-auth": { - "key": "user-key", - "secret": "my-secret-key" - } + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } } -}' + }' ``` -:::note +Create a Route with `jwt-auth` plugin, and specify that the request can either carry the token in the header, query, or the cookie: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_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 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` -The `jwt-auth` Plugin uses the HS256 algorithm by default. To use the RS256 algorithm, you can configure the public key and specify the algorithm: +#### Verify With JWT in Header + +Sending request with JWT in the header: + +```shell +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: + +```text +{ + "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: + +```shell +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: + +```text +{ + "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: ```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d ' +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: + +```text { - "username": "kerouac", + "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](https://nginx.org/en/docs/ngx_core_module.html#env). + +Save the key to an environment variable: + +```shell +JACK_JWT_AUTH_KEY=jack-key +``` + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the Consumer and reference the environment variable in the key: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", "plugins": { - "jwt-auth": { - "key": "user-key", - "public_key": "-----BEGIN PUBLIC KEY-----\n……\n-----END PUBLIC KEY-----", - "algorithm": "RS256" - } + "jwt-auth": { + "key": "$env://JACK_JWT_AUTH_KEY", + "secret": "jack-hs256-secret" + } } -}' + }' ``` -::: +Create a Route with `jwt-auth` enabled: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/get", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` -Once you have created a Consumer object, you can configure a Route to authenticate requests: +Sending request with JWT in the header: ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' +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: + +```text { - "methods": ["GET"], - "uri": "/index.html", + "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](https://www.vaultproject.io) and reference it in plugin configuration. + +Start a Vault development server in Docker: + +```shell +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](https://developer.hashicorp.com/vault/docs/secrets/kv#kv-version-1). Enable it in Vault: + +```shell +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: + +```text +Success! Enabled the kv secrets engine at: kv/ +``` + +Create a secret and configure the Vault address and other connection information: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/secrets/vault/jwt" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "uri": "https://127.0.0.1:8200", + "prefix": "kv/apisix", + "token": "root" + }' +``` + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the Consumer and reference the secret in the key: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "$secret://vault/jwt/jack/jwt-key", + "secret": "vault-hs256-secret" + } + } + }' +``` + +Create a Route with `jwt-auth` enabled: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/get", "plugins": { - "jwt-auth": {} + "jwt-auth": {} }, "upstream": { - "type": "roundrobin", - "nodes": { - "127.0.0.1:1980": 1 - } + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } } -}' + }' ``` -<!-- - - - ---> +Set `jwt-auth` key value to be `jwt-vault-key` in Vault: -## Example usage +```shell +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 need first to issue a JWT token using some tool such as [JWT.io's debugger](https://jwt.io/#debugger-io) or a programming language. +You should see a response similar to the following: -:::note +```text +Success! Data written to: kv/apisix/jack +``` -When you are issuing a JWT token, you have to update the payload with `key` matching the credential key you would like to use; and `exp` or `nbf` in UNIX timestamp. +To issue a JWT, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: -e.g. payload=`{"key": "user-key", "exp": 1727274983}` +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `vault-hs256-secret`. +* Update payload with Consumer key `jwt-vault-key`; and add `exp` or `nbf` in UNIX timestamp. -::: + Your payload should look similar to the following: + + ```json + { + "key": "jwt-vault-key", + "nbf": 1729132271 + } + ``` -You can now use this token while making requests: +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwibmJmIjoxNzI5MTMyMjcxfQ.faiN93LNP1lGSXqAb4empNJKMRWop8-KgnU58VQn1EE +``` + +Sending request with the token as header: ```shell -curl http://127.0.0.1:9080/index.html -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI' -i +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: + +```text +{ + "args": {}, + "headers": { + "Accept": "*/*", + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwiZXhwIjoxNjk1MTM4NjM1fQ.Au2liSZ8eQXUJR3SJESwNlIfqZdNyRyxIJK03L4dk_g", + ... + }, + ... +} ``` -HTTP/1.1 200 OK -Content-Type: text/html -Content-Length: 13175 -... -Accept-Ranges: bytes -<!DOCTYPE html> -<html lang="cn"> -... +### Sign JWT with RS256 Algorithm + +The following example demonstrates how you can use asymmetric algorithms, such as RS256, to sign and validate JWT when implementing JWT for Consumer authentication. You will be generating RSA key pairs using [openssl](https://openssl-library.org/source/) and generating JWT using [JWT.io](https://jwt.io/#debugger-io) to better understand the composition of JWT. + +Generate a 2048-bit RSA private key and extract the corresponding public key in PEM format: + +```shell +openssl genrsa -out jwt-rsa256-private.pem 2048 +openssl rsa -in jwt-rsa256-private.pem -pubout -out jwt-rsa256-public.pem ``` -Without the token, you will receive an error: +You should see `jwt-rsa256-private.pem` and `jwt-rsa256-public.pem` generated in your current working directory. + +Visit [JWT.io's debugger](https://jwt.io/#debugger-io) and do the following: + +* Select __RS256__ in the __Algorithm__ dropdown. +* Copy and paste the key content into the __Verify Signature__ section. +* Update the payload with `key` matching the Consumer key you would like to use; and `exp` or `nbf` in UNIX timestamp. + +The configuration should look similar to the following: + +<br /> +<div style={{textAlign: 'center'}}> +<img + src="https://static.apiseven.com/uploads/2024/12/12/SRe7AXMw_jwt_token.png" + alt="complete configuration of JWT generation on jwt.io" + width="70%" +/> +</div> +<br /> + +Copy the JWT on the left and save to an environment variable: ```shell -HTTP/1.1 401 Unauthorized -... -{"message":"Missing JWT token in request"} +jwt_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsImV4cCI6MTczNDIzMDQwMH0.XjqM0oszmCggwZs-8PUIlJv8wPJON1la2ET5v70E6TCE32Yq5ibrl-1azaK7IreAer3HtnVHeEfII2rR02v8xfR1TPIjU_oHov4qC-A4tLTbgqGVXI7fCy2WFm3PFh6MEKuRe6M3dCQtCAdkRRQrBr1gWFQZhV3TNeMmmtyIfuJpB7cp4DW5pYFsCcoE1Nw6Tz7dt8k0tPBTPI2Mv9AYfMJ30LHDscOaPNtz8YIk_TOkV9b9mhQudUJ7J_suCZMRxD3iL655jTp2gKsstGKdZa0_W9Reu4-HY3LSc5DS1XtfjuftpuUqgg9FvPU0mK_b0wT_Rq3lbYhcHb9GZ72qiQ ``` -You can also pass the token as query parameters: +Create a Consumer `jack`: ```shell -curl http://127.0.0.1:9080/index.html?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -i +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' ``` +Create `jwt-auth` Credential for the Consumer and configure the RSA keys: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "jack-key", + "algorithm": "RS256", + "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnE0h4k/GWfEbYO/yE2MPjHtNKDLNz4mv1KNIPLxY2ccjPYOtjuug+iZ4MujLV59YfrHriTs0H8jweQfff3pRSMjyEK+4qWTY3TeKBXIEa3pVDeoedSJrgjLBVio6xH7et8ir+QScScfLaJHGB4/l3DDGyEhO782a9teY8brn5hsWX5uLmDJvxtTGAHYi847XOcx2UneW4tZ8wQ6JGBSiSg5qAHan4dFZ7CpixCNNqEcSK6EQ7lKOLeFGG8ys/dHBIEasU4oMlCuJH77+XQQ/shchy+vm9oZfP+grLZkV+nKAd8MQZsid7ZJ/fiB/BmnhGrjtIfh98jwxSx4DgdLhdwIDAQAB\n-----END PUBLIC KEY-----", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCcTSHiT8ZZ8Rtg7/ITYw+Me00oMs3Pia/Uo0g8vFjZxyM9g62O66D6Jngy6MtXn1h+seuJOzQfyPB5B99/elFIyPIQr7ipZNjdN4oFcgRrelUN6h51ImuCMsFWKjrEft63yKv5BJxJx8tokcYHj+XcMMbISE7vzZr215jxuufmGxZfm4uYMm/G1MYAdiLzjtc5zHZSd5bi1nzBDokYFKJKDmoAdqfh0VnsKmLEI02oRxIroRDuUo4t4UYbzKz90cEgRqxTigyUK4kfvv5dBD+yFyHL6+b2hl8/6CstmRX6coB3wxBmyJ3tkn9+IH8GaeEauO0h+H3yPDFLHgOB0uF3AgMBAAECggEARpY68Daw0Funzq5uN70r/3iLztSqx8hZpQEclXlF8wwQ6S33iqz1JSOMcwlZE7g9wfHd+jrHfndDypT4pVx7KxC86TZCghWuLrFvXqgwQM2dbcxGdwXVYZZEZAJsSeM19+/jYnFnl5ZoUVBMC4w79aX9j+O/6mKDUmjphHmxUuRCFjN0w7BRoYwmS796rSf1eoOcSXh2G9Ycc34DUFDfGpOzabndbmMfOz7W0DyUBG23fgLhNChTUGq8vMaqKXkQ8JKeKdEugSmRGz42HxjWoNlIGBDyB8tPNPT6SXsu/JBskdf9Gb71OWiub381oXC259sz+1K1REb1KSkgyC+bkQKBgQDKCnwXaf8aOIoJPCG53EqQfKScCIYQrvp1Uk3bs5tfYN4HcI3yAUnOqQ3Ux3eY9PfS37urlJXCfCbCnZ6P6xALZnN+aL2zWvZArlHvD6vnXiyevwK5IY+o2EW02h3A548wrGznQSsfX0tum22bEVlRuFfBbpZpizXwrV4ODSNhTwKBgQDGC27QQxah3yq6EbOh JJlJegjawVXEaEp/j4fD3qe/unLbUIFvCz6j9BAbgocDKzqXxlpTtIbnsesdLo7KM3MtYL0XO/87HIsBj9XCVgMkFCcM6YZ6fHnkJl0bs3haU4N9uI/wpokvfvXJp7iC9LUCseBdBj+N6T230HWiSbPjWQKBgQC8zzGKO/8vRNkSqkQmSczQ2/qE6p5G5w6eJy0lfOJdLswvDatJFpUf8PJA/6svoPYb9gOO5AtUNeuPAfeVLSnQTYzu+/kTrJTme0GMdAvE60gtjfmAgvGa64mw6gjWJk+1P92B+2/OIKMAmXXDbWIYMXqpBKzBs1vUMF/uJ68BlwKBgQDEivQem3YKj3/HyWmLstatpP7EmrqTgSzuC3OhX4b7L/5sySirG22/KKgTpSZ4bp5noeJiz/ZSWrAK9fmfkg/sKOV/+XsDHwCVPDnX86SKWbWnitp7FK2jTq94nlQC0H7edhvjqGLdUBJ9XoYu8MvzMLSJnXnVTHSDx832kU6FgQKBgQCbw4Eiu2IcOduIAokmsZl8Smh9ZeyhP2B/UBa1hsiPKQ6bw86QJr2OMbRXLBxtx+HYIfwDo4vXEE862PfoQyu6SjJBNmHiid7XcV06Z104UQNjP7IDLMMF+SASMqYoQWg/5chPfxBgIXnfWqw6TMmND3THY4Oj4Nhf4xeUg3HsaA==\n-----END PRIVATE KEY-----" + } + } + }' ``` -HTTP/1.1 200 OK -Content-Type: text/html -Content-Length: 13175 -... -Accept-Ranges: bytes -<!DOCTYPE html> -<html lang="cn"> -... +:::tip + +You should add a newline character after the opening line and before the closing line, for example `-----BEGIN PRIVATE KEY-----\n......\n-----END PRIVATE KEY-----`. + +The key content can be directly concatenated. + +::: + +Create a Route with the `jwt-auth` plugin: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/headers", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' ``` -And also as cookies: +To verify, send a request to the Route with the JWT in the `Authorization` header: ```shell -curl http://127.0.0.1:9080/index.html --cookie jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -i +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: + +```json +{ + "headers": { + "Accept": "*/*", + "Authorization": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsImV4cCI6MTczNDIzMDQwMH0.XjqM0oszmCggwZs-8PUIlJv8wPJON1la2ET5v70E6TCE32Yq5ibrl-1azaK7IreAer3HtnVHeEfII2rR02v8xfR1TPIjU_oHov4qC-A4tLTbgqGVXI7fCy2WFm3PFh6MEKuRe6M3dCQtCAdkRRQrBr1gWFQZhV3TNeMmmtyIfuJpB7cp4DW5pYFsCcoE1Nw6Tz7dt8k0tPBTPI2Mv9AYfMJ30LHDscOaPNtz8YIk_TOkV9b9mhQudUJ7J_suCZMRxD3iL655jTp2gKsstGKdZa0_W9Reu4-HY3LSc5DS1XtfjuftpuUqgg9FvPU0mK_b0wT_Rq3lbYhcHb9GZ72qiQ", + ... + } +} ``` -HTTP/1.1 200 OK -Content-Type: text/html -Content-Length: 13175 -... -Accept-Ranges: bytes -<!DOCTYPE html> -<html lang="cn"> -... +### Add Consumer Custom ID to Header + +The following example demonstrates how you can attach a Consumer custom ID to authenticated request in the `Consumer-Custom-Id` header, which can be used to implement additional logics as needed. + +Create a Consumer `jack` with a custom ID label: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack", + "labels": { + "custom_id": "495aec6a" + } + }' ``` -## Delete Plugin +Create `jwt-auth` Credential for the consumer: Review Comment: ```suggestion Create `jwt-auth` Credential for the Consumer: ``` ########## docs/en/latest/plugins/jwt-auth.md: ########## @@ -78,154 +85,827 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ::: +### Use JWT for Consumer Authentication + +The following example demonstrates how to implement JWT for Consumer key authentication. + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } + } + }' +``` + +Create a Route with `jwt-auth` plugin: + ```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d ' +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/headers", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` + +Send a request to the Route with the JWT in the `Authorization` header: + +```shell +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: + +```text { - "username": "jack", + "headers": { + "Accept": "*/*", + "Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjUvYzWLt4lFr546PNsr9TXuf0Az5opoM", + "Host": "127.0.0.1", + "User-Agent": "curl/8.6.0", + "X-Amzn-Trace-Id": "Root=1-66ea951a-4d740d724bd2a44f174d4daf", + "X-Consumer-Username": "jack", + "X-Credential-Identifier": "cred-jack-jwt-auth", + "X-Forwarded-Host": "127.0.0.1" + } +} +``` + +In 30 seconds, the token should expire. Send a request with the same token to verify: + +```shell +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: + +```text +{"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. + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", "plugins": { - "jwt-auth": { - "key": "user-key", - "secret": "my-secret-key" - } + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } } -}' + }' ``` -:::note +Create a Route with `jwt-auth` plugin, and specify that the request can either carry the token in the header, query, or the cookie: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_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 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` -The `jwt-auth` Plugin uses the HS256 algorithm by default. To use the RS256 algorithm, you can configure the public key and specify the algorithm: +#### Verify With JWT in Header + +Sending request with JWT in the header: + +```shell +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: + +```text +{ + "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: + +```shell +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: + +```text +{ + "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: ```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d ' +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: + +```text { - "username": "kerouac", + "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](https://nginx.org/en/docs/ngx_core_module.html#env). + +Save the key to an environment variable: + +```shell +JACK_JWT_AUTH_KEY=jack-key +``` + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the Consumer and reference the environment variable in the key: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", "plugins": { - "jwt-auth": { - "key": "user-key", - "public_key": "-----BEGIN PUBLIC KEY-----\n……\n-----END PUBLIC KEY-----", - "algorithm": "RS256" - } + "jwt-auth": { + "key": "$env://JACK_JWT_AUTH_KEY", + "secret": "jack-hs256-secret" + } } -}' + }' ``` -::: +Create a Route with `jwt-auth` enabled: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/get", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` -Once you have created a Consumer object, you can configure a Route to authenticate requests: +Sending request with JWT in the header: ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' +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: + +```text { - "methods": ["GET"], - "uri": "/index.html", + "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](https://www.vaultproject.io) and reference it in plugin configuration. + +Start a Vault development server in Docker: + +```shell +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](https://developer.hashicorp.com/vault/docs/secrets/kv#kv-version-1). Enable it in Vault: + +```shell +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: + +```text +Success! Enabled the kv secrets engine at: kv/ +``` + +Create a secret and configure the Vault address and other connection information: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/secrets/vault/jwt" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "uri": "https://127.0.0.1:8200", + "prefix": "kv/apisix", + "token": "root" + }' +``` + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the Consumer and reference the secret in the key: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "$secret://vault/jwt/jack/jwt-key", + "secret": "vault-hs256-secret" + } + } + }' +``` + +Create a Route with `jwt-auth` enabled: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/get", "plugins": { - "jwt-auth": {} + "jwt-auth": {} }, "upstream": { - "type": "roundrobin", - "nodes": { - "127.0.0.1:1980": 1 - } + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } } -}' + }' ``` -<!-- - - - ---> +Set `jwt-auth` key value to be `jwt-vault-key` in Vault: -## Example usage +```shell +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 need first to issue a JWT token using some tool such as [JWT.io's debugger](https://jwt.io/#debugger-io) or a programming language. +You should see a response similar to the following: -:::note +```text +Success! Data written to: kv/apisix/jack +``` -When you are issuing a JWT token, you have to update the payload with `key` matching the credential key you would like to use; and `exp` or `nbf` in UNIX timestamp. +To issue a JWT, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: -e.g. payload=`{"key": "user-key", "exp": 1727274983}` +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `vault-hs256-secret`. +* Update payload with Consumer key `jwt-vault-key`; and add `exp` or `nbf` in UNIX timestamp. -::: + Your payload should look similar to the following: + + ```json + { + "key": "jwt-vault-key", + "nbf": 1729132271 + } + ``` -You can now use this token while making requests: +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwibmJmIjoxNzI5MTMyMjcxfQ.faiN93LNP1lGSXqAb4empNJKMRWop8-KgnU58VQn1EE +``` + +Sending request with the token as header: ```shell -curl http://127.0.0.1:9080/index.html -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI' -i +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: + +```text +{ + "args": {}, + "headers": { + "Accept": "*/*", + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwiZXhwIjoxNjk1MTM4NjM1fQ.Au2liSZ8eQXUJR3SJESwNlIfqZdNyRyxIJK03L4dk_g", + ... + }, + ... +} ``` -HTTP/1.1 200 OK -Content-Type: text/html -Content-Length: 13175 -... -Accept-Ranges: bytes -<!DOCTYPE html> -<html lang="cn"> -... +### Sign JWT with RS256 Algorithm + +The following example demonstrates how you can use asymmetric algorithms, such as RS256, to sign and validate JWT when implementing JWT for Consumer authentication. You will be generating RSA key pairs using [openssl](https://openssl-library.org/source/) and generating JWT using [JWT.io](https://jwt.io/#debugger-io) to better understand the composition of JWT. + +Generate a 2048-bit RSA private key and extract the corresponding public key in PEM format: + +```shell +openssl genrsa -out jwt-rsa256-private.pem 2048 +openssl rsa -in jwt-rsa256-private.pem -pubout -out jwt-rsa256-public.pem ``` -Without the token, you will receive an error: +You should see `jwt-rsa256-private.pem` and `jwt-rsa256-public.pem` generated in your current working directory. + +Visit [JWT.io's debugger](https://jwt.io/#debugger-io) and do the following: + +* Select __RS256__ in the __Algorithm__ dropdown. +* Copy and paste the key content into the __Verify Signature__ section. +* Update the payload with `key` matching the Consumer key you would like to use; and `exp` or `nbf` in UNIX timestamp. + +The configuration should look similar to the following: + +<br /> +<div style={{textAlign: 'center'}}> +<img + src="https://static.apiseven.com/uploads/2024/12/12/SRe7AXMw_jwt_token.png" + alt="complete configuration of JWT generation on jwt.io" + width="70%" +/> +</div> +<br /> + +Copy the JWT on the left and save to an environment variable: ```shell -HTTP/1.1 401 Unauthorized -... -{"message":"Missing JWT token in request"} +jwt_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsImV4cCI6MTczNDIzMDQwMH0.XjqM0oszmCggwZs-8PUIlJv8wPJON1la2ET5v70E6TCE32Yq5ibrl-1azaK7IreAer3HtnVHeEfII2rR02v8xfR1TPIjU_oHov4qC-A4tLTbgqGVXI7fCy2WFm3PFh6MEKuRe6M3dCQtCAdkRRQrBr1gWFQZhV3TNeMmmtyIfuJpB7cp4DW5pYFsCcoE1Nw6Tz7dt8k0tPBTPI2Mv9AYfMJ30LHDscOaPNtz8YIk_TOkV9b9mhQudUJ7J_suCZMRxD3iL655jTp2gKsstGKdZa0_W9Reu4-HY3LSc5DS1XtfjuftpuUqgg9FvPU0mK_b0wT_Rq3lbYhcHb9GZ72qiQ ``` -You can also pass the token as query parameters: +Create a Consumer `jack`: ```shell -curl http://127.0.0.1:9080/index.html?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -i +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' ``` +Create `jwt-auth` Credential for the Consumer and configure the RSA keys: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "jack-key", + "algorithm": "RS256", + "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnE0h4k/GWfEbYO/yE2MPjHtNKDLNz4mv1KNIPLxY2ccjPYOtjuug+iZ4MujLV59YfrHriTs0H8jweQfff3pRSMjyEK+4qWTY3TeKBXIEa3pVDeoedSJrgjLBVio6xH7et8ir+QScScfLaJHGB4/l3DDGyEhO782a9teY8brn5hsWX5uLmDJvxtTGAHYi847XOcx2UneW4tZ8wQ6JGBSiSg5qAHan4dFZ7CpixCNNqEcSK6EQ7lKOLeFGG8ys/dHBIEasU4oMlCuJH77+XQQ/shchy+vm9oZfP+grLZkV+nKAd8MQZsid7ZJ/fiB/BmnhGrjtIfh98jwxSx4DgdLhdwIDAQAB\n-----END PUBLIC KEY-----", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCcTSHiT8ZZ8Rtg7/ITYw+Me00oMs3Pia/Uo0g8vFjZxyM9g62O66D6Jngy6MtXn1h+seuJOzQfyPB5B99/elFIyPIQr7ipZNjdN4oFcgRrelUN6h51ImuCMsFWKjrEft63yKv5BJxJx8tokcYHj+XcMMbISE7vzZr215jxuufmGxZfm4uYMm/G1MYAdiLzjtc5zHZSd5bi1nzBDokYFKJKDmoAdqfh0VnsKmLEI02oRxIroRDuUo4t4UYbzKz90cEgRqxTigyUK4kfvv5dBD+yFyHL6+b2hl8/6CstmRX6coB3wxBmyJ3tkn9+IH8GaeEauO0h+H3yPDFLHgOB0uF3AgMBAAECggEARpY68Daw0Funzq5uN70r/3iLztSqx8hZpQEclXlF8wwQ6S33iqz1JSOMcwlZE7g9wfHd+jrHfndDypT4pVx7KxC86TZCghWuLrFvXqgwQM2dbcxGdwXVYZZEZAJsSeM19+/jYnFnl5ZoUVBMC4w79aX9j+O/6mKDUmjphHmxUuRCFjN0w7BRoYwmS796rSf1eoOcSXh2G9Ycc34DUFDfGpOzabndbmMfOz7W0DyUBG23fgLhNChTUGq8vMaqKXkQ8JKeKdEugSmRGz42HxjWoNlIGBDyB8tPNPT6SXsu/JBskdf9Gb71OWiub381oXC259sz+1K1REb1KSkgyC+bkQKBgQDKCnwXaf8aOIoJPCG53EqQfKScCIYQrvp1Uk3bs5tfYN4HcI3yAUnOqQ3Ux3eY9PfS37urlJXCfCbCnZ6P6xALZnN+aL2zWvZArlHvD6vnXiyevwK5IY+o2EW02h3A548wrGznQSsfX0tum22bEVlRuFfBbpZpizXwrV4ODSNhTwKBgQDGC27QQxah3yq6EbOh JJlJegjawVXEaEp/j4fD3qe/unLbUIFvCz6j9BAbgocDKzqXxlpTtIbnsesdLo7KM3MtYL0XO/87HIsBj9XCVgMkFCcM6YZ6fHnkJl0bs3haU4N9uI/wpokvfvXJp7iC9LUCseBdBj+N6T230HWiSbPjWQKBgQC8zzGKO/8vRNkSqkQmSczQ2/qE6p5G5w6eJy0lfOJdLswvDatJFpUf8PJA/6svoPYb9gOO5AtUNeuPAfeVLSnQTYzu+/kTrJTme0GMdAvE60gtjfmAgvGa64mw6gjWJk+1P92B+2/OIKMAmXXDbWIYMXqpBKzBs1vUMF/uJ68BlwKBgQDEivQem3YKj3/HyWmLstatpP7EmrqTgSzuC3OhX4b7L/5sySirG22/KKgTpSZ4bp5noeJiz/ZSWrAK9fmfkg/sKOV/+XsDHwCVPDnX86SKWbWnitp7FK2jTq94nlQC0H7edhvjqGLdUBJ9XoYu8MvzMLSJnXnVTHSDx832kU6FgQKBgQCbw4Eiu2IcOduIAokmsZl8Smh9ZeyhP2B/UBa1hsiPKQ6bw86QJr2OMbRXLBxtx+HYIfwDo4vXEE862PfoQyu6SjJBNmHiid7XcV06Z104UQNjP7IDLMMF+SASMqYoQWg/5chPfxBgIXnfWqw6TMmND3THY4Oj4Nhf4xeUg3HsaA==\n-----END PRIVATE KEY-----" + } + } + }' ``` -HTTP/1.1 200 OK -Content-Type: text/html -Content-Length: 13175 -... -Accept-Ranges: bytes -<!DOCTYPE html> -<html lang="cn"> -... +:::tip + +You should add a newline character after the opening line and before the closing line, for example `-----BEGIN PRIVATE KEY-----\n......\n-----END PRIVATE KEY-----`. + +The key content can be directly concatenated. + +::: + +Create a Route with the `jwt-auth` plugin: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/headers", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' ``` -And also as cookies: +To verify, send a request to the Route with the JWT in the `Authorization` header: ```shell -curl http://127.0.0.1:9080/index.html --cookie jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -i +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: + +```json +{ + "headers": { + "Accept": "*/*", + "Authorization": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsImV4cCI6MTczNDIzMDQwMH0.XjqM0oszmCggwZs-8PUIlJv8wPJON1la2ET5v70E6TCE32Yq5ibrl-1azaK7IreAer3HtnVHeEfII2rR02v8xfR1TPIjU_oHov4qC-A4tLTbgqGVXI7fCy2WFm3PFh6MEKuRe6M3dCQtCAdkRRQrBr1gWFQZhV3TNeMmmtyIfuJpB7cp4DW5pYFsCcoE1Nw6Tz7dt8k0tPBTPI2Mv9AYfMJ30LHDscOaPNtz8YIk_TOkV9b9mhQudUJ7J_suCZMRxD3iL655jTp2gKsstGKdZa0_W9Reu4-HY3LSc5DS1XtfjuftpuUqgg9FvPU0mK_b0wT_Rq3lbYhcHb9GZ72qiQ", + ... + } +} ``` -HTTP/1.1 200 OK -Content-Type: text/html -Content-Length: 13175 -... -Accept-Ranges: bytes -<!DOCTYPE html> -<html lang="cn"> -... +### Add Consumer Custom ID to Header + +The following example demonstrates how you can attach a Consumer custom ID to authenticated request in the `Consumer-Custom-Id` header, which can be used to implement additional logics as needed. + +Create a Consumer `jack` with a custom ID label: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack", + "labels": { + "custom_id": "495aec6a" + } + }' ``` -## Delete Plugin +Create `jwt-auth` Credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } + } + }' +``` -To remove the `jwt-auth` Plugin, you can delete the corresponding JSON configuration from the Plugin configuration. APISIX will automatically reload and you do not have to restart for this to take effect. +Create a Route with `jwt-auth`: ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-auth-route", + "uri": "/anything", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` + +To verify, send a request to the Route with the JWT in the `Authorization` header: + +```shell +curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}" +``` + +You should see an `HTTP/1.1 200 OK` response similar to the following, where `X-Consumer-Custom-Id` is attached: + +```json { - "methods": ["GET"], - "uri": "/index.html", - "id": 1, - "plugins": {}, + "headers": { + "Accept": "*/*", + "Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjUvYzWLt4lFr546PNsr9TXuf0Az5opoM", + "Host": "127.0.0.1", + "User-Agent": "curl/8.6.0", + "X-Amzn-Trace-Id": "Root=1-66ea951a-4d740d724bd2a44f174d4daf", + "X-Consumer-Username": "jack", + "X-Credential-Identifier": "cred-jack-jwt-auth", + "X-Consumer-Custom-Id": "495aec6a", + "X-Forwarded-Host": "127.0.0.1" + } +} +``` + +### Rate Limit with Anonymous Consumer + +The following example demonstrates how you can configure different rate limiting policies by regular and anonymous consumers, where the anonymous Consumer does not need to authenticate and has less quotas. + +Create a regular Consumer `jack` and configure the `limit-count` plugin to allow for a quota of 3 within a 30-second window: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack", + "plugins": { + "limit-count": { + "count": 3, + "time_window": 30, + "rejected_code": 429 + } + } + }' +``` + +Create the `jwt-auth` Credential for the Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } + } + }' +``` + +Create an anonymous user `anonymous` and configure the `limit-count` plugin to allow for a quota of 1 within a 30-second window: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "anonymous", + "plugins": { + "limit-count": { + "count": 1, + "time_window": 30, + "rejected_code": 429 + } + } + }' +``` + +Create a Route and configure the `jwt-auth` plugin to accept anonymous Consumer `anonymous` from bypassing the authentication: Review Comment: ```suggestion Create a Route and configure the `jwt-auth` Plugin to accept anonymous Consumer `anonymous` from bypassing the authentication: ``` ########## docs/en/latest/plugins/jwt-auth.md: ########## @@ -78,154 +85,827 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ::: +### Use JWT for Consumer Authentication + +The following example demonstrates how to implement JWT for Consumer key authentication. + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } + } + }' +``` + +Create a Route with `jwt-auth` plugin: + ```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d ' +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/headers", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` + +Send a request to the Route with the JWT in the `Authorization` header: + +```shell +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: + +```text { - "username": "jack", + "headers": { + "Accept": "*/*", + "Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjUvYzWLt4lFr546PNsr9TXuf0Az5opoM", + "Host": "127.0.0.1", + "User-Agent": "curl/8.6.0", + "X-Amzn-Trace-Id": "Root=1-66ea951a-4d740d724bd2a44f174d4daf", + "X-Consumer-Username": "jack", + "X-Credential-Identifier": "cred-jack-jwt-auth", + "X-Forwarded-Host": "127.0.0.1" + } +} +``` + +In 30 seconds, the token should expire. Send a request with the same token to verify: + +```shell +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: + +```text +{"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. + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", "plugins": { - "jwt-auth": { - "key": "user-key", - "secret": "my-secret-key" - } + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } } -}' + }' ``` -:::note +Create a Route with `jwt-auth` plugin, and specify that the request can either carry the token in the header, query, or the cookie: Review Comment: ```suggestion Create a Route with `jwt-auth` Plugin, and specify that the request can either carry the token in the header, query, or the cookie: ``` ########## docs/en/latest/plugins/jwt-auth.md: ########## @@ -28,48 +28,55 @@ description: This document contains information about the Apache APISIX jwt-auth # --> +<head> + <link rel="canonical" href="https://docs.api7.ai/hub/jwt-auth" /> +</head> + ## Description -The `jwt-auth` Plugin is used to add [JWT](https://jwt.io/) authentication to a [Service](../terminology/service.md) or a [Route](../terminology/route.md). +The `jwt-auth` plugin supports the use of [JSON Web Token (JWT)](https://jwt.io/) 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](../terminology/consumer.md). 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. -A [Consumer](../terminology/consumer.md) of the service then needs to provide a key through a query string, a request header or a cookie to verify its request. +When a Consumer is successfully authenticated, APISIX adds additional headers, such as `X-Consumer-Username`, `X-Credential-Indentifier`, and other Consumer custom headers if configured, to the request, before proxying it to the Upstream service. The Upstream service will be able to differentiate between consumers and implement additional logics as needed. If any of these values is not available, the corresponding header will not be added. ## Attributes -For Consumer: +For Consumer/Credential: | Name | Type | Required | Default | Valid values | Description | |---------------|---------|-------------------------------------------------------|---------|-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | key | string | True | | | Unique key for a Consumer. | -| secret | string | False | | | The encryption key. If unspecified, auto generated in the background. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | +| secret | string | False | | | Shared key used to sign and verify the JWT when the algorithm is symmetric. Required when using `HS256` or `HS512` as the algorithm. If unspecified, the secret will be auto-generated. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | | public_key | string | True if `RS256` or `ES256` is set for the `algorithm` attribute. | | | RSA or ECDSA public key. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | -| algorithm | string | False | "HS256" | ["HS256", "HS512", "RS256", "ES256"] | Encryption algorithm. | +| algorithm | string | False | HS256 | ["HS256", "HS512", "RS256", "ES256"] | Encryption algorithm. | | exp | integer | False | 86400 | [1,...] | Expiry time of the token in seconds. | | base64_secret | boolean | False | false | | Set to true if the secret is base64 encoded. | -| lifetime_grace_period | integer | False | 0 | [0,...] | Define the leeway in seconds to account for clock skew between the server that generated the jwt and the server validating it. Value should be zero (0) or a positive integer. | +| lifetime_grace_period | integer | False | 0 | [0,...] | Grace period in seconds. Used to account for clock skew between the server generating the JWT and the server validating the JWT. | +| key_claim_name | string | False | key | | The claim in the JWT payload that identifies the associated secret, such as `iss`. | NOTE: `encrypt_fields = {"secret"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). For Route: Review Comment: ```suggestion For Routes or Services: ``` ########## docs/en/latest/plugins/jwt-auth.md: ########## @@ -28,48 +28,55 @@ description: This document contains information about the Apache APISIX jwt-auth # --> +<head> + <link rel="canonical" href="https://docs.api7.ai/hub/jwt-auth" /> +</head> + ## Description -The `jwt-auth` Plugin is used to add [JWT](https://jwt.io/) authentication to a [Service](../terminology/service.md) or a [Route](../terminology/route.md). +The `jwt-auth` plugin supports the use of [JSON Web Token (JWT)](https://jwt.io/) 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](../terminology/consumer.md). 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. -A [Consumer](../terminology/consumer.md) of the service then needs to provide a key through a query string, a request header or a cookie to verify its request. +When a Consumer is successfully authenticated, APISIX adds additional headers, such as `X-Consumer-Username`, `X-Credential-Indentifier`, and other Consumer custom headers if configured, to the request, before proxying it to the Upstream service. The Upstream service will be able to differentiate between consumers and implement additional logics as needed. If any of these values is not available, the corresponding header will not be added. ## Attributes -For Consumer: +For Consumer/Credential: | Name | Type | Required | Default | Valid values | Description | |---------------|---------|-------------------------------------------------------|---------|-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | key | string | True | | | Unique key for a Consumer. | -| secret | string | False | | | The encryption key. If unspecified, auto generated in the background. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | +| secret | string | False | | | Shared key used to sign and verify the JWT when the algorithm is symmetric. Required when using `HS256` or `HS512` as the algorithm. If unspecified, the secret will be auto-generated. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | Review Comment: ```suggestion | secret | string | False | | non-empty | Shared key used to sign and verify the JWT when the algorithm is symmetric. Required when using `HS256` or `HS512` as the algorithm. If unspecified, the secret will be auto-generated. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | ``` ########## docs/en/latest/plugins/jwt-auth.md: ########## @@ -78,154 +85,827 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ::: +### Use JWT for Consumer Authentication + +The following example demonstrates how to implement JWT for Consumer key authentication. + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } + } + }' +``` + +Create a Route with `jwt-auth` plugin: + ```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d ' +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/headers", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` + +Send a request to the Route with the JWT in the `Authorization` header: + +```shell +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: + +```text { - "username": "jack", + "headers": { + "Accept": "*/*", + "Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjUvYzWLt4lFr546PNsr9TXuf0Az5opoM", + "Host": "127.0.0.1", + "User-Agent": "curl/8.6.0", + "X-Amzn-Trace-Id": "Root=1-66ea951a-4d740d724bd2a44f174d4daf", + "X-Consumer-Username": "jack", + "X-Credential-Identifier": "cred-jack-jwt-auth", + "X-Forwarded-Host": "127.0.0.1" + } +} +``` + +In 30 seconds, the token should expire. Send a request with the same token to verify: + +```shell +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: + +```text +{"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. + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", "plugins": { - "jwt-auth": { - "key": "user-key", - "secret": "my-secret-key" - } + "jwt-auth": { + "key": "jack-key", + "secret": "jack-hs256-secret" + } } -}' + }' ``` -:::note +Create a Route with `jwt-auth` plugin, and specify that the request can either carry the token in the header, query, or the cookie: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_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 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` -The `jwt-auth` Plugin uses the HS256 algorithm by default. To use the RS256 algorithm, you can configure the public key and specify the algorithm: +#### Verify With JWT in Header + +Sending request with JWT in the header: + +```shell +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: + +```text +{ + "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: + +```shell +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: + +```text +{ + "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: ```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d ' +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: + +```text { - "username": "kerouac", + "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](https://nginx.org/en/docs/ngx_core_module.html#env). + +Save the key to an environment variable: + +```shell +JACK_JWT_AUTH_KEY=jack-key +``` + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the Consumer and reference the environment variable in the key: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", "plugins": { - "jwt-auth": { - "key": "user-key", - "public_key": "-----BEGIN PUBLIC KEY-----\n……\n-----END PUBLIC KEY-----", - "algorithm": "RS256" - } + "jwt-auth": { + "key": "$env://JACK_JWT_AUTH_KEY", + "secret": "jack-hs256-secret" + } } -}' + }' ``` -::: +Create a Route with `jwt-auth` enabled: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/get", + "plugins": { + "jwt-auth": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +To issue a JWT for `jack`, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: + +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `jack-hs256-secret`. +* Update payload with Consumer key `jack-key`; and add `exp` or `nbf` in UNIX timestamp. + + Your payload should look similar to the following: + + ```json + { + "key": "jack-key", + "nbf": 1729132271 + } + ``` + +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I +``` -Once you have created a Consumer object, you can configure a Route to authenticate requests: +Sending request with JWT in the header: ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' +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: + +```text { - "methods": ["GET"], - "uri": "/index.html", + "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](https://www.vaultproject.io) and reference it in plugin configuration. + +Start a Vault development server in Docker: + +```shell +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](https://developer.hashicorp.com/vault/docs/secrets/kv#kv-version-1). Enable it in Vault: + +```shell +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: + +```text +Success! Enabled the kv secrets engine at: kv/ +``` + +Create a secret and configure the Vault address and other connection information: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/secrets/vault/jwt" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "uri": "https://127.0.0.1:8200", + "prefix": "kv/apisix", + "token": "root" + }' +``` + +Create a Consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `jwt-auth` Credential for the Consumer and reference the secret in the key: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "$secret://vault/jwt/jack/jwt-key", + "secret": "vault-hs256-secret" + } + } + }' +``` + +Create a Route with `jwt-auth` enabled: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "jwt-route", + "uri": "/get", "plugins": { - "jwt-auth": {} + "jwt-auth": {} }, "upstream": { - "type": "roundrobin", - "nodes": { - "127.0.0.1:1980": 1 - } + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } } -}' + }' ``` -<!-- - - - ---> +Set `jwt-auth` key value to be `jwt-vault-key` in Vault: -## Example usage +```shell +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 need first to issue a JWT token using some tool such as [JWT.io's debugger](https://jwt.io/#debugger-io) or a programming language. +You should see a response similar to the following: -:::note +```text +Success! Data written to: kv/apisix/jack +``` -When you are issuing a JWT token, you have to update the payload with `key` matching the credential key you would like to use; and `exp` or `nbf` in UNIX timestamp. +To issue a JWT, you could use [JWT.io's debugger](https://jwt.io/#debugger-io) or other utilities. If you are using [JWT.io's debugger](https://jwt.io/#debugger-io), do the following: -e.g. payload=`{"key": "user-key", "exp": 1727274983}` +* Select __HS256__ in the __Algorithm__ dropdown. +* Update the secret in the __Verify Signature__ section to be `vault-hs256-secret`. +* Update payload with Consumer key `jwt-vault-key`; and add `exp` or `nbf` in UNIX timestamp. -::: + Your payload should look similar to the following: + + ```json + { + "key": "jwt-vault-key", + "nbf": 1729132271 + } + ``` -You can now use this token while making requests: +Copy the generated JWT under the __Encoded__ section and save to a variable: + +```text +jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwibmJmIjoxNzI5MTMyMjcxfQ.faiN93LNP1lGSXqAb4empNJKMRWop8-KgnU58VQn1EE +``` + +Sending request with the token as header: ```shell -curl http://127.0.0.1:9080/index.html -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI' -i +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: + +```text +{ + "args": {}, + "headers": { + "Accept": "*/*", + "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwiZXhwIjoxNjk1MTM4NjM1fQ.Au2liSZ8eQXUJR3SJESwNlIfqZdNyRyxIJK03L4dk_g", + ... + }, + ... +} ``` -HTTP/1.1 200 OK -Content-Type: text/html -Content-Length: 13175 -... -Accept-Ranges: bytes -<!DOCTYPE html> -<html lang="cn"> -... +### Sign JWT with RS256 Algorithm + +The following example demonstrates how you can use asymmetric algorithms, such as RS256, to sign and validate JWT when implementing JWT for Consumer authentication. You will be generating RSA key pairs using [openssl](https://openssl-library.org/source/) and generating JWT using [JWT.io](https://jwt.io/#debugger-io) to better understand the composition of JWT. + +Generate a 2048-bit RSA private key and extract the corresponding public key in PEM format: + +```shell +openssl genrsa -out jwt-rsa256-private.pem 2048 +openssl rsa -in jwt-rsa256-private.pem -pubout -out jwt-rsa256-public.pem ``` -Without the token, you will receive an error: +You should see `jwt-rsa256-private.pem` and `jwt-rsa256-public.pem` generated in your current working directory. + +Visit [JWT.io's debugger](https://jwt.io/#debugger-io) and do the following: + +* Select __RS256__ in the __Algorithm__ dropdown. +* Copy and paste the key content into the __Verify Signature__ section. +* Update the payload with `key` matching the Consumer key you would like to use; and `exp` or `nbf` in UNIX timestamp. + +The configuration should look similar to the following: + +<br /> +<div style={{textAlign: 'center'}}> +<img + src="https://static.apiseven.com/uploads/2024/12/12/SRe7AXMw_jwt_token.png" + alt="complete configuration of JWT generation on jwt.io" + width="70%" +/> +</div> +<br /> + +Copy the JWT on the left and save to an environment variable: ```shell -HTTP/1.1 401 Unauthorized -... -{"message":"Missing JWT token in request"} +jwt_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsImV4cCI6MTczNDIzMDQwMH0.XjqM0oszmCggwZs-8PUIlJv8wPJON1la2ET5v70E6TCE32Yq5ibrl-1azaK7IreAer3HtnVHeEfII2rR02v8xfR1TPIjU_oHov4qC-A4tLTbgqGVXI7fCy2WFm3PFh6MEKuRe6M3dCQtCAdkRRQrBr1gWFQZhV3TNeMmmtyIfuJpB7cp4DW5pYFsCcoE1Nw6Tz7dt8k0tPBTPI2Mv9AYfMJ30LHDscOaPNtz8YIk_TOkV9b9mhQudUJ7J_suCZMRxD3iL655jTp2gKsstGKdZa0_W9Reu4-HY3LSc5DS1XtfjuftpuUqgg9FvPU0mK_b0wT_Rq3lbYhcHb9GZ72qiQ ``` -You can also pass the token as query parameters: +Create a Consumer `jack`: ```shell -curl http://127.0.0.1:9080/index.html?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -i +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' ``` +Create `jwt-auth` Credential for the Consumer and configure the RSA keys: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-jwt-auth", + "plugins": { + "jwt-auth": { + "key": "jack-key", + "algorithm": "RS256", + "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnE0h4k/GWfEbYO/yE2MPjHtNKDLNz4mv1KNIPLxY2ccjPYOtjuug+iZ4MujLV59YfrHriTs0H8jweQfff3pRSMjyEK+4qWTY3TeKBXIEa3pVDeoedSJrgjLBVio6xH7et8ir+QScScfLaJHGB4/l3DDGyEhO782a9teY8brn5hsWX5uLmDJvxtTGAHYi847XOcx2UneW4tZ8wQ6JGBSiSg5qAHan4dFZ7CpixCNNqEcSK6EQ7lKOLeFGG8ys/dHBIEasU4oMlCuJH77+XQQ/shchy+vm9oZfP+grLZkV+nKAd8MQZsid7ZJ/fiB/BmnhGrjtIfh98jwxSx4DgdLhdwIDAQAB\n-----END PUBLIC KEY-----", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCcTSHiT8ZZ8Rtg7/ITYw+Me00oMs3Pia/Uo0g8vFjZxyM9g62O66D6Jngy6MtXn1h+seuJOzQfyPB5B99/elFIyPIQr7ipZNjdN4oFcgRrelUN6h51ImuCMsFWKjrEft63yKv5BJxJx8tokcYHj+XcMMbISE7vzZr215jxuufmGxZfm4uYMm/G1MYAdiLzjtc5zHZSd5bi1nzBDokYFKJKDmoAdqfh0VnsKmLEI02oRxIroRDuUo4t4UYbzKz90cEgRqxTigyUK4kfvv5dBD+yFyHL6+b2hl8/6CstmRX6coB3wxBmyJ3tkn9+IH8GaeEauO0h+H3yPDFLHgOB0uF3AgMBAAECggEARpY68Daw0Funzq5uN70r/3iLztSqx8hZpQEclXlF8wwQ6S33iqz1JSOMcwlZE7g9wfHd+jrHfndDypT4pVx7KxC86TZCghWuLrFvXqgwQM2dbcxGdwXVYZZEZAJsSeM19+/jYnFnl5ZoUVBMC4w79aX9j+O/6mKDUmjphHmxUuRCFjN0w7BRoYwmS796rSf1eoOcSXh2G9Ycc34DUFDfGpOzabndbmMfOz7W0DyUBG23fgLhNChTUGq8vMaqKXkQ8JKeKdEugSmRGz42HxjWoNlIGBDyB8tPNPT6SXsu/JBskdf9Gb71OWiub381oXC259sz+1K1REb1KSkgyC+bkQKBgQDKCnwXaf8aOIoJPCG53EqQfKScCIYQrvp1Uk3bs5tfYN4HcI3yAUnOqQ3Ux3eY9PfS37urlJXCfCbCnZ6P6xALZnN+aL2zWvZArlHvD6vnXiyevwK5IY+o2EW02h3A548wrGznQSsfX0tum22bEVlRuFfBbpZpizXwrV4ODSNhTwKBgQDGC27QQxah3yq6EbOh JJlJegjawVXEaEp/j4fD3qe/unLbUIFvCz6j9BAbgocDKzqXxlpTtIbnsesdLo7KM3MtYL0XO/87HIsBj9XCVgMkFCcM6YZ6fHnkJl0bs3haU4N9uI/wpokvfvXJp7iC9LUCseBdBj+N6T230HWiSbPjWQKBgQC8zzGKO/8vRNkSqkQmSczQ2/qE6p5G5w6eJy0lfOJdLswvDatJFpUf8PJA/6svoPYb9gOO5AtUNeuPAfeVLSnQTYzu+/kTrJTme0GMdAvE60gtjfmAgvGa64mw6gjWJk+1P92B+2/OIKMAmXXDbWIYMXqpBKzBs1vUMF/uJ68BlwKBgQDEivQem3YKj3/HyWmLstatpP7EmrqTgSzuC3OhX4b7L/5sySirG22/KKgTpSZ4bp5noeJiz/ZSWrAK9fmfkg/sKOV/+XsDHwCVPDnX86SKWbWnitp7FK2jTq94nlQC0H7edhvjqGLdUBJ9XoYu8MvzMLSJnXnVTHSDx832kU6FgQKBgQCbw4Eiu2IcOduIAokmsZl8Smh9ZeyhP2B/UBa1hsiPKQ6bw86QJr2OMbRXLBxtx+HYIfwDo4vXEE862PfoQyu6SjJBNmHiid7XcV06Z104UQNjP7IDLMMF+SASMqYoQWg/5chPfxBgIXnfWqw6TMmND3THY4Oj4Nhf4xeUg3HsaA==\n-----END PRIVATE KEY-----" + } + } + }' ``` -HTTP/1.1 200 OK -Content-Type: text/html -Content-Length: 13175 -... -Accept-Ranges: bytes -<!DOCTYPE html> -<html lang="cn"> -... +:::tip + +You should add a newline character after the opening line and before the closing line, for example `-----BEGIN PRIVATE KEY-----\n......\n-----END PRIVATE KEY-----`. + +The key content can be directly concatenated. + +::: + +Create a Route with the `jwt-auth` plugin: Review Comment: ```suggestion Create a Route with the `jwt-auth` Plugin: ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
