Setting up JWT Authentication (original) (raw)

  1. Home
  2. F5 NGINX Plus
  3. Admin Guide
  4. Security Controls Setting up JWT Authentication

With F5 NGINX Plus it is possible to control access to your resources using JWT authentication. JWT is data format for user information in the OpenID Connect standard, which is the standard identity layer on top of the OAuth 2.0 protocol. Deployers of APIs and microservices are also turning to the JWT standard for its simplicity and flexibility. With JWT authentication, a client provides a JSON Web Token, and the token will be validated against a local key file or a remote service.

NGINX Plus supports the following types of JWT:

Configuring NGINX Plus to Authenticate API

Let’s assume that NGINX Plus serves as a gateway (proxy_pass http://api_server) to a number of API servers (the upstream {} block), and requests passed to the API servers should be authenticated:

nginx

upstream api_server {
    server 10.0.0.1;
    server 10.0.0.2;
}

server {
    listen 80;

    location /products/ {
        proxy_pass http://api_server;
        #...
    }
}
upstream api_server {
    server 10.0.0.1;
    server 10.0.0.2;
}

server {
    listen 80;

    location /products/ {
        proxy_pass http://api_server;
        #...
    }
}

To implement JWT for authentication:

  1. First, it is necessary to create a JWT that will be issued to a client. You can use your identity provider (IdP) or your own service to create JWTs. For testing purposes, you can create your own JWT, see Authenticating API Clients with JWT and NGINX Plus blog post for details.
  2. Configure NGINX Plus to accept JWT: specify the auth_jwt directive that enables JWT authentication and also defines the authentication area (or “realm”, “API” in the example):
    nginx
server {  
    listen 80;  
    location /products/ {  
        proxy_pass http://api_server;  
        auth_jwt   "API";  
        #...  
    }  
}  
server {  
    listen 80;  
    location /products/ {  
        proxy_pass http://api_server;  
        auth_jwt   "API";  
        #...  
    }  
}  

NGINX Plus can also obtain the JWT from a query string parameter. To configure this, include the token= parameter to the auth_jwt directive:
nginx

   #...  
   auth_jwt "API" token=$arg_apijwt;  
   #...  
   #...  
   auth_jwt "API" token=$arg_apijwt;  
   #...  
  1. Specify the type of JWT - signed (JWS), encrypted (JWE) or nested (Nested JWT) - with the auth_jwt_type directive. The default value of the directive is signed, so for JWS, the directive can be omitted.
    nginx
server {  
    listen 80;  
    location /products/ {  
        proxy_pass        http://api_server;  
        auth_jwt          "API";  
        auth_jwt_type     encrypted;  
        #...  
    }  
}  
server {  
    listen 80;  
    location /products/ {  
        proxy_pass        http://api_server;  
        auth_jwt          "API";  
        auth_jwt_type     encrypted;  
        #...  
    }  
}  
  1. Specify the path to the JSON Web Key file that will be used to verify JWT signature or decrypt JWT content, depending on what you are using. This can be done with the auth_jwt_key_file and/or auth_jwt_key_request directives. Specifying both directives at the same time will allow you to specify more than one source for keys. If none of the directives are specified, JWS signature verification will be skipped.
    In this scenario, the keys will be taken from two files: the key.jwk file and the keys.json file:
    nginx
server {  
    listen 80;  
    location /products/ {  
        proxy_pass        http://api_server;  
        auth_jwt          "API";  
        auth_jwt_type     encrypted;  
        auth_jwt_key_file conf/key.jwk;  
        auth_jwt_key_file conf/keys.json;  
    }  
}  
server {  
    listen 80;  
    location /products/ {  
        proxy_pass        http://api_server;  
        auth_jwt          "API";  
        auth_jwt_type     encrypted;  
        auth_jwt_key_file conf/key.jwk;  
        auth_jwt_key_file conf/keys.json;  
    }  
}  

In this scenario, there are also two sources for the keys, but the private keys will be taken from the local file private_jwe_keys.jwk, while the public keys will be taken from the external identity provider service https://idp.example.com in a subrequest:
nginx

server {  
    listen 80;  
    location /products/ {  
        proxy_pass           http://api_server;  
        auth_jwt             "API";  
        auth_jwt_type        encrypted;  
        auth_jwt_key_file    private_jwe_keys.jwk;  
        auth_jwt_key_request /public_jws_keys;  
    }  
    location /public_jws_keys {  
        proxy_pass "https_//idp.example.com/keys";  
    }  
}  
server {  
    listen 80;  
    location /products/ {  
        proxy_pass           http://api_server;  
        auth_jwt             "API";  
        auth_jwt_type        encrypted;  
        auth_jwt_key_file    private_jwe_keys.jwk;  
        auth_jwt_key_request /public_jws_keys;  
    }  
    location /public_jws_keys {  
        proxy_pass "https_//idp.example.com/keys";  
    }  
}  

It is recommended to enable JWT key caching to get the optimal performance from the JWT module. For example, you can use the auth_jwt_key_cache directive for the above configuration, and enable the JWT key caching for one hour. Note that if the auth_jwt_key_request or auth_jwt_key_file are configured dynamically with variables, auth_jwt_key_cache cannot be used.
nginx

server {  
    listen 80;  
    location /products/ {  
        proxy_pass           http://api_server;  
        auth_jwt             "API";  
        auth_jwt_type        encrypted;  
        auth_jwt_key_file    private_jwe_keys.jwk;  
        auth_jwt_key_request /public_jws_keys;  
        auth_jwt_key_cache   1h;  
    }  
    location /public_jws_keys {  
        proxy_pass "https_//idp.example.com/keys";  
    }  
}  
server {  
    listen 80;  
    location /products/ {  
        proxy_pass           http://api_server;  
        auth_jwt             "API";  
        auth_jwt_type        encrypted;  
        auth_jwt_key_file    private_jwe_keys.jwk;  
        auth_jwt_key_request /public_jws_keys;  
        auth_jwt_key_cache   1h;  
    }  
    location /public_jws_keys {  
        proxy_pass "https_//idp.example.com/keys";  
    }  
}  

How NGINX Plus Validates a JWT

A JWT is considered to be valid when the following conditions are met:

Creating a JSON Web Key File

In order to validate the signature with a key or to decrypt data, a JSON Web Key (key.jwk) should be created. The file format is defined by JSON Web Key specification:

json

{"keys":
    [{
        "k":"ZmFudGFzdGljand0",
        "kty":"oct",
        "kid":"0001"
    }]
}
{"keys":
    [{
        "k":"ZmFudGFzdGljand0",
        "kty":"oct",
        "kid":"0001"
    }]
}

where:

shell

echo -n fantasticjwt | base64 | tr '+/' '-_' | tr -d '='
ZmFudGFzdGljand0
echo -n fantasticjwt | base64 | tr '+/' '-_' | tr -d '='
ZmFudGFzdGljand0

Getting JWKs from Subrequest

NGINX Plus can be configured to fetch JSON Web Keys from the remote location - usually an identity provider, especially when using OpenID Connect. The IdP URI where the subrequest will be sent to is configured with the auth_jwt_key_request directive:

nginx

http {
    #...

    server {
        listen 80;
            #...

        location / {
            auth_jwt "closed site";
            auth_jwt_key_request /_jwks_uri; # Keys will be fetched by subrequest

            proxy_pass http://my_backend;
        }
    }
}
http {
    #...

    server {
        listen 80;
            #...

        location / {
            auth_jwt "closed site";
            auth_jwt_key_request /_jwks_uri; # Keys will be fetched by subrequest

            proxy_pass http://my_backend;
        }
    }
}

The URI may refer to an internal location (_jwks_uri) so that the JSON Web Key Set can be cached (proxy_cache and proxy_cache_path directives) to avoid validation overhead. Turning on caching is recommended for high-load API gateways even if JWT key caching is used as it will help to avoid overwhelming a key server with key requests when a JWT key cache expires.

nginx

http {
    proxy_cache_path /var/cache/nginx/jwk levels=1 keys_zone=jwk:1m max_size=10m;
    #...

    server {
        listen 80;
            #...

        location = /_jwks_uri {
            internal;
            proxy_method      GET;
            proxy_cache       jwk; # Cache responses
            proxy_cache_valid 200 12h;
            proxy_pass        https://idp.example.com/oauth2/keys; # Obtain keys from here
        }
    }
}
http {
    proxy_cache_path /var/cache/nginx/jwk levels=1 keys_zone=jwk:1m max_size=10m;
    #...

    server {
        listen 80;
            #...

        location = /_jwks_uri {
            internal;
            proxy_method      GET;
            proxy_cache       jwk; # Cache responses
            proxy_cache_valid 200 12h;
            proxy_pass        https://idp.example.com/oauth2/keys; # Obtain keys from here
        }
    }
}

The full example of getting JWKs from a subrequest:

nginx

#
proxy_cache_path /var/cache/nginx/jwk levels=1 keys_zone=jwk:1m max_size=10m;

server {
    listen 80; # Use SSL/TLS in production

    location / {
        auth_jwt             "closed site";
        auth_jwt_key_cache   1h;
        auth_jwt_key_request /_jwks_uri;    # Keys will be fetched by subrequest

        proxy_pass http://my_backend;
    }

    location = /_jwks_uri {
        internal;
        proxy_method      GET;
        proxy_cache       jwk; # Cache responses
        proxy_cache_valid 200 12h;
        proxy_pass        https://idp.example.com/oauth2/keys; # Obtain keys from here
    }
}
#
proxy_cache_path /var/cache/nginx/jwk levels=1 keys_zone=jwk:1m max_size=10m;

server {
    listen 80; # Use SSL/TLS in production

    location / {
        auth_jwt             "closed site";
        auth_jwt_key_cache   1h;
        auth_jwt_key_request /_jwks_uri;    # Keys will be fetched by subrequest

        proxy_pass http://my_backend;
    }

    location = /_jwks_uri {
        internal;
        proxy_method      GET;
        proxy_cache       jwk; # Cache responses
        proxy_cache_valid 200 12h;
        proxy_pass        https://idp.example.com/oauth2/keys; # Obtain keys from here
    }
}

Arbitrary JWT Claims Validation

During JWT verification, NGINX Plus automatically validates only nbf (“not before”) and exp (“expires”) claims. However, in some cases you need to set more conditions for a successful JWT validation, in particular when dealing with application-specific or protocol level claims. For example, OpenID Connect Core requires validation of iss (“issuer”), aud (“audience”), sub (“subject”) claims for ID token.

Additional conditions for JWT validation can be set as variables with the map module and then evaluated with the auth_jwt_require directive.

In this scenario, we are verifying that:

The values of three resulting variables are evaluated in the auth_jwt_require directive, and if the value of each variable is 1, the JWT will be accepted:

nginx

upstream api_server {
    server 10.0.0.1;
    server 10.0.0.2;
}

map <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mi>w</mi><msub><mi>t</mi><mi>c</mi></msub><mi>l</mi><mi>a</mi><mi>i</mi><msub><mi>m</mi><mi>a</mi></msub><mi>u</mi><mi>d</mi></mrow><annotation encoding="application/x-tex">jwt_claim_aud </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">ai</span><span class="mord"><span class="mord mathnormal">m</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">u</span><span class="mord mathnormal">d</span></span></span></span>valid_app_id {    #map rule 1:
    "~api\d.example.com" 1;           #token issued only for target apps
}

map <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mi>w</mi><msub><mi>t</mi><mi>c</mi></msub><mi>l</mi><mi>a</mi><mi>i</mi><msub><mi>m</mi><mi>i</mi></msub><mi>s</mi><mi>s</mi></mrow><annotation encoding="application/x-tex">jwt_claim_iss </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">ai</span><span class="mord"><span class="mord mathnormal">m</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">ss</span></span></span></span>valid_issuer {    #map rule 2:
    "https://idp.example.com/sts" 1;  #token issued by trusted CA
}

map <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mi>w</mi><msub><mi>t</mi><mi>c</mi></msub><mi>l</mi><mi>a</mi><mi>i</mi><msub><mi>m</mi><mi>s</mi></msub><mi>c</mi><mi>o</mi><mi>p</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">jwt_claim_scope </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">ai</span><span class="mord"><span class="mord mathnormal">m</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">s</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">co</span><span class="mord mathnormal">p</span><span class="mord mathnormal">e</span></span></span></span>valid_scope {   #map rule 3:
    "access_as_admin" 1;              #access as admin only
}

server {
    listen 80;

    location /products/ {
        auth_jwt          "API";
        auth_jwt_key_file conf/api_secret.jwk;
        auth_jwt_require  <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi><mi>a</mi><mi>l</mi><mi>i</mi><msub><mi>d</mi><mi>a</mi></msub><mi>p</mi><msub><mi>p</mi><mi>i</mi></msub><mi>d</mi></mrow><annotation encoding="application/x-tex">valid_app_id </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">i</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">p</span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">d</span></span></span></span>valid_issuer $valid_scope;
        proxy_pass        http://api_server;
    }
}
upstream api_server {
    server 10.0.0.1;
    server 10.0.0.2;
}

map <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mi>w</mi><msub><mi>t</mi><mi>c</mi></msub><mi>l</mi><mi>a</mi><mi>i</mi><msub><mi>m</mi><mi>a</mi></msub><mi>u</mi><mi>d</mi></mrow><annotation encoding="application/x-tex">jwt_claim_aud </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">ai</span><span class="mord"><span class="mord mathnormal">m</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">u</span><span class="mord mathnormal">d</span></span></span></span>valid_app_id {    #map rule 1:
    "~api\d.example.com" 1;           #token issued only for target apps
}

map <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mi>w</mi><msub><mi>t</mi><mi>c</mi></msub><mi>l</mi><mi>a</mi><mi>i</mi><msub><mi>m</mi><mi>i</mi></msub><mi>s</mi><mi>s</mi></mrow><annotation encoding="application/x-tex">jwt_claim_iss </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">ai</span><span class="mord"><span class="mord mathnormal">m</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">ss</span></span></span></span>valid_issuer {    #map rule 2:
    "https://idp.example.com/sts" 1;  #token issued by trusted CA
}

map <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mi>w</mi><msub><mi>t</mi><mi>c</mi></msub><mi>l</mi><mi>a</mi><mi>i</mi><msub><mi>m</mi><mi>s</mi></msub><mi>c</mi><mi>o</mi><mi>p</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">jwt_claim_scope </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">ai</span><span class="mord"><span class="mord mathnormal">m</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">s</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">co</span><span class="mord mathnormal">p</span><span class="mord mathnormal">e</span></span></span></span>valid_scope {   #map rule 3:
    "access_as_admin" 1;              #access as admin only
}

server {
    listen 80;

    location /products/ {
        auth_jwt          "API";
        auth_jwt_key_file conf/api_secret.jwk;
        auth_jwt_require  <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi><mi>a</mi><mi>l</mi><mi>i</mi><msub><mi>d</mi><mi>a</mi></msub><mi>p</mi><msub><mi>p</mi><mi>i</mi></msub><mi>d</mi></mrow><annotation encoding="application/x-tex">valid_app_id </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">i</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">p</span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">d</span></span></span></span>valid_issuer $valid_scope;
        proxy_pass        http://api_server;
    }
}

In some cases the auth_jwt_require directive can be specified multiple times, for example, for the purpose of authentication and then for authorization. In case of an error, the 401 code will be displayed. Assigning the custom error code 403 to another auth_jwt_require directive makes ti possible to differentiate authentication and authorization usecases and handle corresponding failures appropriately:

nginx

    location /products/ {
        auth_jwt          "API";
        auth_jwt_key_file conf/api_secret.jwk;
        auth_jwt_require  <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi><mi>a</mi><mi>l</mi><mi>i</mi><msub><mi>d</mi><mi>a</mi></msub><mi>p</mi><msub><mi>p</mi><mi>i</mi></msub><mi>d</mi></mrow><annotation encoding="application/x-tex">valid_app_id </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">i</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">p</span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">d</span></span></span></span>valid_issuer $valid_scope;
        auth_jwt_require  $valid_scope error=403;
        proxy_pass        http://api_server;
    }
    location /products/ {
        auth_jwt          "API";
        auth_jwt_key_file conf/api_secret.jwk;
        auth_jwt_require  <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi><mi>a</mi><mi>l</mi><mi>i</mi><msub><mi>d</mi><mi>a</mi></msub><mi>p</mi><msub><mi>p</mi><mi>i</mi></msub><mi>d</mi></mrow><annotation encoding="application/x-tex">valid_app_id </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">i</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">p</span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">d</span></span></span></span>valid_issuer $valid_scope;
        auth_jwt_require  $valid_scope error=403;
        proxy_pass        http://api_server;
    }

A Nested JWT is a JWS token enclosed into JWE. In a Nested JWT, the sensitive information from JWS is protected with extra encryption of JWE.

Using Nested JWT may be preferable over JWE because:

To enable Nested tokens:

  1. Specify the nested type of JWT with the auth_jwt_type directive.
  2. Pass the decrypted payload (the $jwt_payload variable) to the application as the Bearer token value in the Authorization header:
proxy_set_header Authorization "Bearer $jwt_payload";
proxy_set_header Authorization "Bearer $jwt_payload";

This example sums up the previous steps into one configuration:

nginx

upstream api_server {
    server 10.0.0.1;
    server 10.0.0.2;
}

http {
    server {
        listen 80;

        auth_jwt          "API";
        auth_jwt_type     nested;
        auth_jwt_key_file conf/api_secret.jwk;

        proxy_pass       http://api_server;
        proxy_set_header Authorization "Bearer $jwt_payload";
    }
}
upstream api_server {
    server 10.0.0.1;
    server 10.0.0.2;
}

http {
    server {
        listen 80;

        auth_jwt          "API";
        auth_jwt_type     nested;
        auth_jwt_key_file conf/api_secret.jwk;

        proxy_pass       http://api_server;
        proxy_set_header Authorization "Bearer $jwt_payload";
    }
}