mikyll opened a new issue, #11262: URL: https://github.com/apache/apisix/issues/11262
### Current Behavior Note: I'm using Apisix Ingress Controller on Minikube, with Apisix CRDs. ### Case 1 (OK) - **ApisixConsumer** doesn't specify the `exp` configuration parameter; - the **JWT token** includes a `exp` claim, but it's expired; Result: the JWT validation fails due to `exp` claim, since the token is expired. ### Case 2 (?) - **ApisixConsumer** doesn't specify the `exp` configuration parameter; - the **JWT token** does not include a `exp` claim; Result: the JWT validation fails due to missing `exp`or `nbf` claims. ### Case 3 (OK) - **ApisixConsumer** specifies the `exp` configuration parameter; - the **JWT token** does not include a `exp` claim; Result: the JWT validation fails due to missing `exp`or `nbf` claims. ### Expected Behavior Do **not check** the `exp` and `nbf` claims _by default_, since the standard specification says they should be _optional_. Instead, verify these claims only if they are specifyied in ApisixConsumer fields, or maybe provide configuration parameters to enable/disable the check ([Kong does something similar](https://docs.konghq.com/hub/kong-inc/jwt/configuration/#config-claims_to_verify)). ### References - [RFC7519 # 4.1.4](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4): > **4.1.4. "exp" (Expiration Time) Claim** \ The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing. The processing of the "exp" claim requires that the current date/time MUST be before the expiration date/time listed in the "exp" claim. \ Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value MUST be a number containing a NumericDate value. **Use of this claim is OPTIONAL.** - [RFC7519 # 4.1.5](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5): > **4.1.5. "nbf" (Not Before) Claim** \ The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. The processing of the "nbf" claim requires that the current date/time MUST be after or equal to the not-before date/time listed in the "nbf" claim. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value MUST be a number containing a NumericDate value. **Use of this claim is OPTIONAL.** ### Error Logs _No response_ ### Steps to Reproduce **NB**: I'm setting Service `apisix-gateway` as a _LoadBalancer_ for simplicity. I'm also using some mock RS256 public/private keys. 1. Start a minikube cluster and launch tunnel command, leaving the terminal running in background: ```bash minikube start --driver=docker minikube tunnel ``` 2. Install Apisix Ingress Controller: ```bash # Update charts helm repo add apisix https://charts.apiseven.com helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update # Create namespace kubectl create ns ingress-apisix # Install Apisix helm install apisix apisix/apisix \ --set service.type=LoadBalancer \ --namespace ingress-apisix \ --set ingress-controller.enabled=true \ --set ingress-controller.config.apisix.serviceNamespace=ingress-apisix ``` Once the installation is completed, minikube tunnel should pick up the `apisix-gateway` service and we will be able to send a curl request to the proxy on localhost: ```bash curl -s -i "localhost:80/" HTTP/1.1 404 Not Found Date: Wed, 15 May 2024 14:07:06 GMT Content-Type: text/plain; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: APISIX/3.9.1 {"error_msg":"404 Route Not Found"} ``` 3. Declare Kubernetes resources used for testing: <details close> <summary>Show/Hide</summary> ```yaml # File 'resources.yaml' apiVersion: apps/v1 kind: Deployment metadata: name: httpbin spec: replicas: 1 selector: matchLabels: run: httpbin template: metadata: labels: run: httpbin spec: containers: - name: httpbin image: kennethreitz/httpbin ports: - containerPort: 80 protocol: TCP --- apiVersion: v1 kind: Service metadata: name: httpbin spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: httpbin --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: name: httpbin-test-auth-jwt spec: authParameter: jwtAuth: value: key: "my-key" algorithm: "RS256" base64_secret: false public_key: | -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo 4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u +qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ 0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc mwIDAQAB -----END PUBLIC KEY----- --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: name: httpbin-test-auth-jwt spec: http: - name: rule1 match: paths: - /* backends: - serviceName: httpbin servicePort: 80 authentication: enable: true type: jwtAuth ``` </details> 4. Create them inside the cluster: ```bash kubectl apply -f resources.yaml ``` 5. Test the route ```bash curl -s -i -X GET "localhost/get?foo1=bar1&foo2=bar2" HTTP/1.1 401 Unauthorized Date: Thu, 16 May 2024 10:05:55 GMT Content-Type: text/plain; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: APISIX/3.9.1 {"message":"Missing JWT token in request"} ``` 6. Use the following token: - header: ```json { "alg": "RS256", "typ": "JWT" } ``` - payload **without expiration claim**: ```json { "key": "my-key", "sub": "1234567890", "name": "John Doe", "iat": 1516239022 } ``` 7. Save the token in a variable: ```bash JWT_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJteS1rZXkiLCJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.kQ-h3S0wgwDWIaOV_JNOlpck8JXAxAAtIto3hzHee4PHisx8xZcajSaX6PXf5cQW-H8uIOf7UUJCr3_62LV2hy4sSLwXcpzK5QIYRu4GO6g4q9Lv3yhYw0h2rP0bcFmkoVM91S7T0BEFA9m3H8zyKpF6qy9GscC7xoNL49W7TVhoetm4GeiKpngLCvUbGEjLWUrzx1o9JRruOe6ydv4VhOi8angH4By7kcs-XKLepVr1HyzQacw8Lyoyu4CumviefpWkwzDfDINf0r3Ad-WqAsoOGBhJh4fybe6xpIO_uWOJ95JWHUaQE3HWM_Q9fUuZvyR1p7oizbmWUxipaYIaZA" ``` 8. Open `apisix` gateway logs in another terminal, to detect the "expiration check" message: ```bash kubectl logs -n "ingress-apisix" -f deployments/$(kubectl get deployment -n "ingress-apisix" --no-headers | cut -f1 -d' '| grep 'apisix$') ``` 9. Send a HTTP request with the token: ```bash curl -s -i -X GET "localhost/get?foo1=bar1&foo2=bar2" -H "Authorization: Bearer ${JWT_TOKEN}" HTTP/1.1 401 Unauthorized Date: Thu, 16 May 2024 10:14:35 GMT Content-Type: text/plain; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: APISIX/3.9.1 {"message":"failed to verify jwt"} ``` 10. We can see the warning message in apisix logs: ``` 2024/05/16 10:19:20 [warn] 72#72: *1053197 [lua] jwt-auth.lua:381: phase_func(): failed to verify jwt: Missing one of claims - [ nbf, exp ]., client: 10.244.0.1, server: _, request: "GET /get?foo1=bar1&foo2=bar2 HTTP/1.1", host: "localhost" 2024/05/16 10:19:20 [warn] 72#72: *1053197 [lua] plugin.lua:1160: run_plugin(): jwt-auth exits with http status code 401, client: 10.244.0.1, server: _, request: "GET /get?foo1=bar1&foo2=bar2 HTTP/1.1", host: "localhost" 10.244.0.1 - - [16/May/2024:10:19:20 +0000] localhost "GET /get?foo1=bar1&foo2=bar2 HTTP/1.1" 401 46 0.000 "-" "curl/8.2.1" - - - "http://localhost" ``` ### Environment - APISIX version (run `apisix version`): ``` /usr/local/openresty//luajit/bin/luajit ./apisix/cli/apisix.lua version 3.9.1 ``` - Operating system (run `uname -a`): ``` Linux apisix-69f8d49c7b-vdcvf 5.15.133.1-microsoft-standard-WSL2 #1 SMP Thu Oct 5 21:02:42 UTC 2023 x86_64 GNU/Linux ``` - OpenResty / Nginx version (run `openresty -V` or `nginx -V`): <details close> <summary>Show/Hide</summary> ``` nginx version: openresty/1.25.3.1 built by gcc 10.2.1 20210110 (Debian 10.2.1-6) built with OpenSSL 3.2.0 23 Nov 2023 TLS SNI support enabled configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt='-O2 -DAPISIX_RUNTIME_VER=1.2.0 -DNGX_GRPC_CLI_ENGI NE_PATH=/usr/local/openresty/libgrpc_engine.so -DNGX_HTTP_GRPC_CLI_ENGINE_PATH=/usr/local/openresty/libgrpc_engine.so -DNG X_LUA_ABORT_AT_PANIC -I/usr/local/openresty/zlib/include -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openss l3/include' --add-module=../ngx_devel_kit-0.3.3 --add-module=../echo-nginx-module-0.63 --add-module=../xss-nginx-module-0. 06 --add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.33 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.09 --add-module=../srcache-nginx-module-0.33 --add-module=../ngx_lua-0.1 0.26 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.37 --add-module=../array-var-nginx- module-0.06 --add-module=../memc-nginx-module-0.20 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-mo dule-0.3.9 --add-module=../ngx_stream_lua-0.0.14 --with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib -Wl,-rpath,/usr /local/openresty/wasmtime-c-api/lib -L/usr/local/openresty/zlib/lib -L/usr/local/openresty/pcre/lib -L/usr/local/openresty /openssl3/lib -Wl,-rpath,/usr/local/openresty/zlib/lib:/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl3/lib' -- add-module=/tmp/tmp.EQbG5FbABp/openresty-1.25.3.1/../mod_dubbo-1.0.2 --add-module=/tmp/tmp.EQbG5FbABp/openresty-1.25.3.1/. ./ngx_multi_upstream_module-1.2.0 --add-module=/tmp/tmp.EQbG5FbABp/openresty-1.25.3.1/../apisix-nginx-module-1.16.0 --add- module=/tmp/tmp.EQbG5FbABp/openresty-1.25.3.1/../apisix-nginx-module-1.16.0/src/stream --add-module=/tmp/tmp.EQbG5FbABp/op enresty-1.25.3.1/../apisix-nginx-module-1.16.0/src/meta --add-module=/tmp/tmp.EQbG5FbABp/openresty-1.25.3.1/../wasm-nginx- module-0.7.0 --add-module=/tmp/tmp.EQbG5FbABp/openresty-1.25.3.1/../lua-var-nginx-module-v0.5.3 --add-module=/tmp/tmp.EQbG 5FbABp/openresty-1.25.3.1/../grpc-client-nginx-module-v0.5.0 --add-module=/tmp/tmp.EQbG5FbABp/openresty-1.25.3.1/../lua-re sty-events-0.2.0 --with-poll_module --with-pcre-jit --with-stream --with-stream_ssl_module --with-stream_ssl_preread_modul e --with-http_v2_module --with-http_v3_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_mo dule --with-http_stub_status_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_secure_link_module --with-http_random_index_module --with-http_gzip_static_module --with-http_sub_module --wit h-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-threads --with-compat --w ith-stream --without-pcre2 --with-http_ssl_module ``` </details> -- 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]
