Requirements
Install
Follow the nginx-openid-connect installation instructions.
NGINX (nginx-openid-connect) - Installation
Install the jq
command-line JSON processor. There is a dependency for this but it is not automatically installed.
SELinux Issue Workaround
There is an issue with NGINIX’s permissions for the directory “/etc/nginx/conf.d
". The simplest workaround for this is to change the owner and group of that directory to "nginix
".
A better solution would be to fix SELinux httpd_t
context to allow the nginix process to create files in that directory.
https://www.nginx.com/blog/using-nginx-plus-with-selinux/
Configuring the SurePassID Identity Provider
NGINX (nginx-openid-connect) - Configuring your IdP
NGINX OpenID Connect Client Configuration
Use the following SurePassID Identity Provider OpenID Connect client configuration for the NGNIX replying party.
Update the following properties as required.
ClientId
ClientName
ClientSecrets.Value
RedirectUris
PostLogoutRedirectUris
Properties.*
See Client Object Reference for more details.
NGINX OpenID Connect Client
{
"Enabled": true,
"ProtocolType": "oidc",
"ClientId": "nginx-client-id",
"ClientName": "NGINX Client Name",
"ClientSecrets": [
{
"Value": "bmdpbngtY2xpbmV0LXNlY3JldA==",
"Type": "SharedSecret"
}
],
"AllowedGrantTypes": [
"authorization_code"
],
"RedirectUris": [
"https://app-proxy.example.com/_codexch"
],
"PostLogoutRedirectUris": [
"https://app-proxy.example.com/_logout"
],
"RequireClientSecret": true,
"RequireConsent": true,
"AllowRememberConsent": true,
"RequirePkce": false,
"AllowPlainTextPkce": false,
"AllowAccessTokensViaBrowser": false,
"FrontChannelLogoutSessionRequired": true,
"BackChannelLogoutSessionRequired": true,
"AllowOfflineAccess": false,
"AllowedScopes": [
"profile",
"openid"
],
"AlwaysIncludeUserClaimsInIdToken": true,
"IdentityTokenLifetime": 300,
"AccessTokenLifetime": 3600,
"AuthorizationCodeLifetime": 300,
"AbsoluteRefreshTokenLifetime": 2592000,
"SlidingRefreshTokenLifetime": 1296000,
"RefreshTokenUsage": 1,
"UpdateAccessTokenClaimsOnRefresh": false,
"RefreshTokenExpiration": 1,
"AccessTokenType": 0,
"EnableLocalLogin": true,
"IdentityProviderRestrictions": [],
"IncludeJwtId": false,
"Claims": [],
"AlwaysSendClientClaims": false,
"ClientClaimsPrefix": "client_",
"DeviceCodeLifetime": 300,
"AllowedCorsOrigins": [],
"Properties": {
"MfaButtons.ALL": "PushApp,IvrQuestion,SmsQuestion,SmsOtp,EmailOtp,CallWithOtp",
"MfaButtonsDefault": "SmsOtp,EmailOtp,CallWithOtp",
"AllowOtpDefault": "true",
"TenantDomain.0": "tenant0.com",
"TenantId.0": "<TENANT_0_API_ID>",
"TenantKey.0": "<TENANT_0_API_KEY>",
"TenantAllowOtp.0": "true",
"TenantMfaButtons.0": "PushApp,IvrQuestion,SmsQuestion",
"TenantDomain.1": "tenant1.com",
"TenantId.1": "<TENANT_1_API_ID>",
"TenantKey.1": "<TENANT_1_API_KEY>",
"TenantAllowOtp.1": "true",
"TenantMfaButtons.1": "PushApp,IvrQuestion,SmsQuestion,SmsOtp,EmailOtp,CallWithOtp"
}
}
Configuring NGINIX Plus
NGINX (nginx-openid-connect) - Configuring NGINX Plus
Run the configure.sh
script using the SurePassID OpenID Connect Discovery URL.
Make the following changes to the openid_connect_configuration.conf
file.
Added the following end session endpoint mapping.
map $host $oidc_endsession_endpoint {
default https://oidc.surepassid.com/connect/endsession;
}
Add the following to the file so that the JWKS URL can be used to automatically keep the keys up-to-date.
map $host $oidc_jwks_uri {
default https://oidc.surepassid.com/.well-known/openid-configuration/jwks;
}
Set the Client ID and Client Secret in the mappings as shown.
map $host $oidc_client {
default "<OIDC_CLIENT_ID>";
}
map $host $oidc_client_secret {
default "<OIDC_CLIENT_SECRET>";
}
Modify the $oidc_logout_redirect
to use the URI "/oidc_logout
". This will be configured in the next section
map $host $oidc_logout_redirect {
# Where to send browser after requesting /logout location. This can be
# replaced with a custom logout page, or complete URL.
default "/oidc_logout";
}
This is a complete example of the updated openid_connect_configuration.conf
file.
openid_connect_configuration.conf
# OpenID Connect configuration
#
# Each map block allows multiple values so that multiple IdPs can be supported,
# the $host variable is used as the default input parameter but can be changed.
#
map $host $oidc_authz_endpoint {
default https://oidc.surepassid.com/connect/authorize;
}
map $host $oidc_token_endpoint {
default https://oidc.surepassid.com/connect/token;
}
map $host $oidc_endsession_endpoint {
default https://oidc.surepassid.com/connect/endsession;
}
map $host $oidc_jwks_uri {
default https://oidc.surepassid.com/.well-known/openid-configuration/jwks;
}
map $host $oidc_jwt_keyfile {
default conf.d/idp_jwk.json;
}
map $host $oidc_client {
default "<OIDC_CLIENT_ID>";
}
map $host $oidc_pkce_enable {
default 0;
}
map $host $oidc_client_secret {
default "<OIDC_CLIENT_SECRET>";
}
map $host $oidc_scopes {
default "openid+profile+email+offline_access";
}
map $host $oidc_logout_redirect {
# Where to send browser after requesting /logout location. This can be
# replaced with a custom logout page, or complete URL.
default "/oidc_logout";
}
map $host $oidc_hmac_key {
# This should be unique for every NGINX instance/cluster
default <UNIQUE_GENERATED_OIDC_HMCA_KEY>;
}
map $proto $oidc_cookie_flags {
http "Path=/; SameSite=lax;"; # For HTTP/plaintext testing
https "Path=/; SameSite=lax; HttpOnly; Secure;"; # Production recommendation
}
map $http_x_forwarded_port $redirect_base {
"" $proto://$host:$server_port;
default $proto://$host:$http_x_forwarded_port;
}
map $http_x_forwarded_proto $proto {
"" $scheme;
default $http_x_forwarded_proto;
}
# ADVANCED CONFIGURATION BELOW THIS LINE
# Additional advanced configuration (server context) in openid_connect.server_conf
# JWK Set will be fetched from $oidc_jwks_uri and cached here - ensure writable by nginx user
proxy_cache_path /var/cache/nginx/jwk levels=1 keys_zone=jwk:64k max_size=1m;
# Change timeout values to at least the validity period of each token type
keyval_zone zone=oidc_id_tokens:1M state=conf.d/oidc_id_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; # Temporary storage for PKCE code verifier.
keyval $cookie_auth_token $session_jwt zone=oidc_id_tokens; # Exchange cookie for JWT
keyval $cookie_auth_token $refresh_token zone=refresh_tokens; # Exchange cookie for refresh token
keyval $request_id $new_session zone=oidc_id_tokens; # For initial session creation
keyval $request_id $new_refresh zone=refresh_tokens; # ''
keyval $pkce_id $pkce_code_verifier zone=oidc_pkce;
auth_jwt_claim_set $jwt_audience aud; # In case aud is an array
js_import oidc from conf.d/openid_connect.js;
# vim: syntax=nginx
Make the following changes to the frontend.conf
file. This is where the backend application server is configured.
Configure the upstream (backend) servers.
upstream directive
upstream backend_app_server {
zone backend_app_server 64k;
# Server Private IP Address
server 10.1.2.3:443;
# DNS
#resolver 8.8.8.8;
#server app-proxy.example.com:443;
}
If applicable, configure SSL.
http://nginx.org/en/docs/http/ngx_http_ssl_module.html
server {
...
#####################
# SSL Configuration #
#####################
server_name app-proxy.example.com;
listen 443 ssl;
ssl_certificate ssl/example.com.crt;
ssl_certificate_key ssl/example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
}
Add the /oidc_logout
location. Place this in the server
block before the /
location.
server {
...
location = /oidc_logout {
# https://identityserver4.readthedocs.io/en/latest/endpoints/endsession.html
proxy_ssl_server_name on; # For SNI to the IdP
# $oidc_endsession_endpoint? // Defined in openid_connect_configuration.conf
# id_token_hint=$arg_token&
# post_logout_redirect_uri=https://app-proxy.example.com:433/_logout // The URL value must be URL encoded.
proxy_pass $oidc_endsession_endpoint?id_token_hint=$arg_token&post_logout_redirect_uri=https%3a%2f%2fapp-proxy.example.com%3a433%2f_logout;
}
location / {
...
}
}
Configure the reverse proxy to the backend application server.
server {
...
location / {
# This site is protected with OpenID Connect
auth_jwt "" token=$session_jwt;
error_page 401 = @do_oidc_flow;
#auth_jwt_key_file $oidc_jwt_keyfile; # Enable when using filename
auth_jwt_key_request /_jwks_uri; # Enable when using URL
# Successfully authenticated users are proxied to the backend,
# with 'sub' claim passed as HTTP header
proxy_set_header username $jwt_claim_sub;
proxy_pass https://backend_app_server; # The backend site/app
proxy_set_header Host app-proxy.example.com;
proxy_cookie_domain app-proxy.example.com $host;
}
}
This is a complete example of the updated frontend.conf
file.
Click here to expand...
# This is the backend application we are protecting with OpenID Connect
upstream backend_app_server {
zone backend_app_server 64k;
# Private Azure IP
server 10.1.2.3:443;
# DNS
#resolver 8.8.8.8;
#server app-proxy.example.com:443;
}
# Custom log format to include the 'sub' claim in the REMOTE_USER field
log_format main_jwt '$remote_addr - $jwt_claim_sub [$time_local] "$request" $status '
'$body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
# The frontend server - reverse proxy with OpenID Connect authentication
#
server {
include conf.d/openid_connect.server_conf; # Authorization code flow and Relying Party processing
error_log /var/log/nginx/error.log debug; # Reduce severity level as required
#####################
# SSL Configuration #
#####################
server_name app-proxy.example.com;
listen 443 ssl;
ssl_certificate ssl/surepassid.com_2022-05-14.crt;
ssl_certificate_key ssl/surepassid.com_2022-05-14.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
location = /oidc_logout {
# https://identityserver4.readthedocs.io/en/latest/endpoints/endsession.html
proxy_ssl_server_name on; # For SNI to the IdP
proxy_pass $oidc_endsession_endpoint?id_token_hint=$arg_token&post_logout_redirect_uri=https%3a%2f%2fapp-proxy.example.com%3a433%2f_logout;
}
location / {
# This site is protected with OpenID Connect
auth_jwt "" token=$session_jwt;
error_page 401 = @do_oidc_flow;
#auth_jwt_key_file $oidc_jwt_keyfile; # Enable when using filename
auth_jwt_key_request /_jwks_uri; # Enable when using URL
# Successfully authenticated users are proxied to the backend,
# with 'sub' claim passed as HTTP header
proxy_set_header username $jwt_claim_sub;
proxy_pass https://backend_app_server; # The backend site/app
proxy_set_header Host app-proxy.example.com;
proxy_cookie_domain app-proxy.example.com $host;
}
}
# vim: syntax=nginx