nginx-openid-connect / nginx-oidc-core

Reference implementation of OpenID Connect integration for NGINX Plus
BSD 2-Clause "Simplified" License
1 stars 2 forks source link
amazon-cognito authentication authorization azure-ad identity-provider identity-providers idp jwt keycloak nginx nginx-oidc nginx-openid-connect nginxplus oauth2 oidc okta onelogin openid-connect

nginx-openid-connect

Reference implementation of NGINX Plus as relying party for OpenID Connect authentication

Description

This repository describes how to enable OpenID Connect integration for NGINX Plus. The solution depends on NGINX Plus components (auth_jwt module and key-value store) and as such is not suitable for open source NGINX.

OpenID Connect components

Figure 1. High level components of an OpenID Connect environment

This implementation assumes the following environment:

With this environment, both the client and NGINX Plus communicate directly with the IdP at different stages during the initial authentication event.

OpenID Connect protocol diagram Figure 2. OpenID Connect authorization code flow protocol

NGINX Plus is configured to perform OpenID Connect authentication. Upon a first visit to a protected resource, NGINX Plus initiates the OpenID Connect authorization code flow and redirects the client to the OpenID Connect provider (IdP). When the client returns to NGINX Plus with an authorization code, NGINX Plus exchanges that code for a set of tokens by communicating directly with the IdP.

The ID Token received from the IdP is validated. NGINX Plus then stores the ID token in the key-value store, issues a session cookie to the client using a random string, (which becomes the key to obtain the ID token from the key-value store) and redirects the client to the original URI requested prior to authentication.

Subsequent requests to protected resources are authenticated by exchanging the session cookie for the ID Token in the key-value store. JWT validation is performed on each request, as normal, so that the ID Token validity period is enforced.

For more information on OpenID Connect and JWT validation with NGINX Plus, see Authenticating Users to Existing Applications with OpenID Connect and NGINX Plus.

Refresh Tokens

If a refresh token was received from the IdP then it is also stored in the key-value store. When validation of the ID Token fails (typically upon expiry) then NGINX Plus sends the refresh token to the IdP. If the user's session is still valid at the IdP then a new ID token is received, validated, and updated in the key-value store. The refresh process is seamless to the client.

Logout

Requests made to the /logout location invalidate both the ID token and refresh token by erasing them from the key-value store. Therefore, subsequent requests to protected resources will be treated as a first-time request and send the client to the IdP for authentication. Note that the IdP may issue cookies such that an authenticated session still exists at the IdP.

Multiple IdPs

Where NGINX Plus is configured to proxy requests for multiple websites or applications, or user groups, these may require authentication by different IdPs. Separate IdPs can be configured, with each one matching on an attribute of the HTTP request, for example, hostname or part of the URI path.

Note: When validating OpenID Connect tokens, NGINX Plus can be configured to read the signing key (JWKS) from disk, or a URL. When using multiple IdPs, each one must be configured to use the same method. It is not possible to use a mix of both disk and URLs for the map…$oidc_jwt_keyfile variable.

Installation

Start by installing NGINX Plus. In addition, the NGINX JavaScript module (njs) is required for handling the interaction between NGINX Plus and the OpenID Connect provider (IdP). Install the njs module after installing NGINX Plus by running one of the following:

$ sudo apt install nginx-plus-module-njs for Debian/Ubuntu

$ sudo yum install nginx-plus-module-njs for CentOS/RHEL

The njs module needs to be loaded by adding the following configuration directive near the top of nginx.conf.

load_module modules/ngx_http_js_module.so;

Finally, create a clone of the GitHub repository.

$ git clone https://github.com/nginxinc/nginx-openid-connect

Note: There is a branch for each NGINX Plus release. Switch to the correct branch to ensure compatibility with the features and syntax of each release. The main branch works with the most recent NGINX Plus and JavaScript module releases.

All files can be copied to /etc/nginx/conf.d

Non-standard directories

The GitHub repository contains include files for NGINX configuration, and JavaScript code for token exchange and initial token validation. These files are referenced with a relative path (relative to /etc/nginx). If NGINX Plus is running from a non-standard location then copy the files from the GitHub repository to /path/to/conf/conf.d and use the -p flag to start NGINX with a prefix path that specifies the location where the configuration files are located.

$ nginx -p /path/to/conf -c /path/to/conf/nginx.conf

Running in containers

This implementation is suitable for running in a container provided that the base image includes the NGINX JavaScript module. The GitHub repository is designed to facilitate testing with a container by binding the cloned repository to a mount volume on the container.

$ cd nginx-openid-connect
$ docker run -d -p 8010:8010 -v $PWD:/etc/nginx/conf.d nginx-plus nginx -g 'daemon off; load_module modules/ngx_http_js_module.so;'

Running locally in containers

This implementation supports that you could locally test in a container. You could find the details what to set up here before running docker-compose up.

$ cd nginx-openid-connect
$ docker-compose up

Running behind another proxy or load balancer

When NGINX Plus is deployed behind another proxy, the original protocol and port number are not available. NGINX Plus needs this information to construct the URIs it passes to the IdP and for redirects. By default NGINX Plus looks for the X-Forwarded-Proto and X-Forwarded-Port request headers to construct these URIs.

Configuring your IdP

Configuring NGINX Plus

Configuration can typically be completed automatically by using the configure.sh script.

Manual configuration involves reviewing the following files so that they match your IdP(s) configuration.

Configuring the Key-Value Store

The key-value store is used to maintain persistent storage for ID tokens, access tokens, and refresh tokens. The default configuration should be reviewed so that it suits the environment. This is part of the advanced configuration in oidc_nginx_http.conf. Modify the directory of key-value store in state field per your system requirement.

keyval_zone zone=oidc_id_tokens:1M     state=conf.d/oidc_id_tokens.json     timeout=1h;
keyval_zone zone=oidc_access_tokens:1M state=conf.d/oidc_access_tokens.json timeout=1h;
keyval_zone zone=refresh_tokens:1M     state=conf.d/refresh_tokens.json     timeout=8h;
keyval_zone zone=oidc_pkce:128K                                             timeout=90s;

Each of the keyval_zone parameters are described below.

Session Management

The NGINX Plus API is enabled in oidc_nginx_server.conf so that sessions can be monitored. The API can also be used to manage the current set of active sessions.

To query the current sessions in the key-value store:

$ curl localhost:8010/api/6/http/keyvals/oidc_id_tokens
$ curl localhost:8010/api/6/http/keyvals/oidc_access_tokens
$ curl localhost:8010/api/6/http/keyvals/oidc_refresh_tokens

To delete a single session:

$ curl -iX PATCH -d '{"<session ID>":null}' localhost:8010/api/6/http/keyvals/oidc_id_tokens
$ curl -iX PATCH -d '{"<session ID>":null}' localhost:8010/api/6/http/keyvals/oidc_access_tokens
$ curl -iX PATCH -d '{"<session ID>":null}' localhost:8010/api/6/http/keyvals/refresh_tokens

To delete all sessions:

$ curl -iX DELETE localhost:8010/api/6/http/keyvals/oidc_id_tokens
$ curl -iX DELETE localhost:8010/api/6/http/keyvals/oidc_access_tokens
$ curl -iX DELETE localhost:8010/api/6/http/keyvals/refresh_tokens

Real time monitoring

The oidc_nginx_server.conf file defines several status_zone directives to collect metrics about OpenID Connect activity and errors. Separate metrics counters are recorded for:

To obtain the current set of metrics:

$ curl localhost:8010/api/6/http/location_zones

In addition, the NGINX Plus Dashboard can be configured to visualize the monitoring metrics in a GUI.

Troubleshooting

Any errors generated by the OpenID Connect flow are logged to the error log, /var/log/nginx/error.log. Check the contents of this file as it may include error responses received by the IdP. The level of detail recorded can be modified by adjusting the severity level of the error_log directive.

    proxy_set_header Accept-Encoding "gzip";
proxy_set_header Host <IdP hostname>;
proxy_ssl_name        <IdP hostname>;

Support

This reference implementation for OpenID Connect is supported for NGINX Plus subscribers.

Changelog