Skip to content

Instantly share code, notes, and snippets.

@jdthorpe
Last active August 17, 2025 15:42
Show Gist options
  • Save jdthorpe/717f3246e0efdea903bdb35c31533e08 to your computer and use it in GitHub Desktop.
Save jdthorpe/717f3246e0efdea903bdb35c31533e08 to your computer and use it in GitHub Desktop.
Simple Auth Proxy / Auth Service with nginx-auth-jwt

Authentication with nginx-auth-jwt

These examples demonstrate how to use nginx-auth-jwt to validate tokens from your favorite auth service (e.g. Azure AD, Azure Entra and firends). As recommended, this validates the Audience (aud), Issuer (iss) Scope (scp) and Tenant Id (tid), and nginx-auth-jwt takes care of validating the signature and timestamps (nbf and exp)

Build the container image

The nginx-auth-jwt nginx container can be build like so:

git clone https://github.com/kjdev/nginx-auth-jwt.git
cd nginx-auth-jwt
docker build -t nginx-auth-jwt .

With that, the following examples can be used with the jwks_url option like so

docker run -p 80:80 -v $PWD/app.conf:/etc/nginx/http.d/default.conf  nginx-auth-jwt

or with by saving the JWT keys locally (keys.json) and mapping them into the container like so:

docker run -p 80:80 -v $PWD/app.conf:/etc/nginx/http.d/default.conf -v $PWD/keys.json:/etc/nginx/conf/keys.json nginx-auth-jwt

and then sending a request to the proxy server with your favorite tool, e.g.:

curl --header "Authorization: Bearer $my_access_token" http://localhost:80

Example 1: Use as Auth Proxy

For this example, you'll want to start up an echo server to inspect the proxied request and response headers

# Run jmalloc's echo server in the background
docker run --detach -p 10000:8080 jmalloc/echo-server

and use an app.conf like so:

# app.conf
server {
    listen 80;

    location / {
        auth_jwt "Protected API";

        # Fetch the JWT Keys from another server
        auth_jwt_key_request /_jwks_uri;
        # Alternatively, and read them from file:
        # auth_jwt_key_file /etc/nginx/conf/keys.json;

        # Validate Claims
        auth_jwt_require_claim aud eq "<Application Id URI>";
        auth_jwt_require_claim iss eq "<Issuer>";
        auth_jwt_require_claim scp eq "<Scope Name>";
        auth_jwt_require_claim tid eq "<Tenant Id>";

        # Proxy to another server (the echo server in this case)
        proxy_pass http://host.docker.internal:10000;

        # Add the claims (the oid in this case) to the request header if you want to supply it to the upstream server:
        proxy_set_header X-claim-oid $jwt_claim_oid;

        # Optionally prevent the Authorization header from being passed to the upstream service:
        proxy_set_header Authorization "";
        # Or prevent all the request headers from being passed on:
        # proxy_pass_request_headers off;
    }

    location = /_jwks_uri {
        proxy_pass "<JWKS URI>";
        subrequest_output_buffer_size 12k;

    }

}

Example 2: Use as Auth Service

# app.conf
server {
    listen 80;

    location / {
        auth_jwt "Protected API";

        # Fetch the JWT Keys from another server
        auth_jwt_key_request /_jwks_uri;
        # Alternatively, and read them from file:
        # auth_jwt_key_file /etc/nginx/conf/keys.json;

        # Validate Claims
        auth_jwt_require_claim aud eq "<Application Id URI>";
        auth_jwt_require_claim iss eq "<Issuer>";
        auth_jwt_require_claim scp eq "<Scope Name>";
        auth_jwt_require_claim tid eq "<Tenant Id>";

        # return a 200 OK to authenticated requests
        try_files /dev/null @ok;
    }

    location @ok {
        return 200 OK;
    }

    location = /_jwks_uri {
        proxy_pass "<JWKS URI>";
        subrequest_output_buffer_size 12k;
    }

}

Bonus: Caching JWT Keys

If you want nginx to pull the keys from the JWKS URI, and cache them locally, you'll need to rebuild the container adding this RUN command befor the switch to USER nginx:

RUN mkdir -p /data/www/cache \
 && chown -R nginx:nginx /data/www/cache \
 && chmod 755 /data/www/cache

and add a proxy_cache_path directive to the top of of the nginx.conf, like so:

proxy_cache_path /data/www/cache levels=1 keys_zone=jwtkeys:10m;

and use it in your /_jwks_uri locatoin block:

    location = /_jwks_uri {
        proxy_cache jwtkeys;
        ...
    }

Automatic builds

# create a temp directory to build the image in
TEMP_DIR=$(mktemp -d)
pushd $TEMP_DIR

# clone the nginx-auth-jwt repository
git clone https://github.com/kjdev/nginx-auth-jwt.git 
cd nginx-auth-jwt

# update the Dockerfile to create a cache directory
# (Note the extra '' is only required on osx)
sed -i '' -e '/^USER nginx$/i \
RUN mkdir -p /data/www/cache \\ \
 && chown -R nginx:nginx /data/www/cache \\ \
 && chmod 755 /data/www/cache/ \
 ' Dockerfile

# build the image
docker build -t nginx-auth-jwt .

# clean up 
popd
rm -rf $TEMP_DIR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment