Skip to content

Commit 69e28e7

Browse files
committed
OIDC logout endpoint support
address comments for logout query params add end session endpoint in the IdP configuration
1 parent 6ad8ec6 commit 69e28e7

5 files changed

+56
-15
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ If a [refresh token](https://openid.net/specs/openid-connect-core-1_0.html#Refre
3636

3737
### Logout
3838

39-
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.
39+
Requests made to the `/logout` location invalidate both the ID token and refresh token by erasing them from the key-value store. Next, the User Agent is redirected to the `$oidc_end_session_endpoint` in order to terminate the user session on the IdP's side. After the session is successfully terminated on the IdP side, the User Agent will be redirected to the `$oidc_logout_landing_page`. Note that the `$oidc_logout_landing_page` endpoint must not require authentication, otherwise the user authentication process may be initiated from the beginning.
4040

4141
### Multiple IdPs
4242

@@ -96,6 +96,7 @@ When NGINX Plus is deployed behind another proxy, the original protocol and port
9696
* Obtain the URL for `jwks_uri` or download the JWK file to your NGINX Plus instance
9797
* Obtain the URL for the **authorization endpoint**
9898
* Obtain the URL for the **token endpoint**
99+
* Obtain the URL for the **end session endpoint**
99100

100101
## Configuring NGINX Plus
101102

@@ -105,7 +106,7 @@ Manual configuration involves reviewing the following files so that they match y
105106

106107
* **openid_connect_configuration.conf** - this contains the primary configuration for one or more IdPs in `map{}` blocks
107108
* Modify all of the `map…$oidc_` blocks to match your IdP configuration
108-
* Modify the URI defined in `map…$oidc_logout_redirect` to specify an unprotected resource to be displayed after requesting the `/logout` location
109+
* Modify the URI defined in `map…$oidc_logout_landing_page` to redirect browser after successful logout
109110
* Set a unique value for `$oidc_hmac_key` to ensure nonce values are unpredictable
110111
* If NGINX Plus is deployed behind another proxy or load balancer, modify the `map…$redirect_base` and `map…$proto` blocks to define how to obtain the original protocol and port number.
111112

configure.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ fi
120120
# Build an intermediate configuration file
121121
# File format is: <NGINX variable name><space><IdP value>
122122
#
123-
jq -r '. | "$oidc_authz_endpoint \(.authorization_endpoint)\n$oidc_token_endpoint \(.token_endpoint)\n$oidc_jwks_uri \(.jwks_uri)"' < /tmp/${COMMAND}_$$_json > /tmp/${COMMAND}_$$_conf
123+
jq -r '. | "$oidc_authz_endpoint \(.authorization_endpoint)\n$oidc_token_endpoint \(.token_endpoint)\n$oidc_jwks_uri \(.jwks_uri)\n$oidc_end_session_endpoint \(.end_session_endpoint)"' < /tmp/${COMMAND}_$$_json > /tmp/${COMMAND}_$$_conf
124124

125125
# Create a random value for HMAC key, adding to the intermediate configuration file
126126
echo "\$oidc_hmac_key `openssl rand -base64 18`" >> /tmp/${COMMAND}_$$_conf
@@ -178,7 +178,7 @@ fi
178178

179179
# Loop through each configuration variable
180180
echo "$COMMAND: NOTICE: Configuring $CONFDIR/openid_connect_configuration.conf"
181-
for OIDC_VAR in \$oidc_authz_endpoint \$oidc_token_endpoint \$oidc_jwt_keyfile \$oidc_hmac_key $CLIENT_ID_VAR $CLIENT_SECRET_VAR $PKCE_ENABLE_VAR; do
181+
for OIDC_VAR in \$oidc_authz_endpoint \$oidc_token_endpoint \$oidc_jwt_keyfile \$oidc_end_session_endpoint \$oidc_hmac_key $CLIENT_ID_VAR $CLIENT_SECRET_VAR $PKCE_ENABLE_VAR; do
182182
# Pull the configuration value from the intermediate file
183183
VALUE=`grep "^$OIDC_VAR " /tmp/${COMMAND}_$$_conf | cut -f2 -d' '`
184184
echo -n "$COMMAND: NOTICE: - $OIDC_VAR ..."

openid_connect.js

+19-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
var newSession = false; // Used by oidcAuth() and validateIdToken()
77

8-
export default {auth, codeExchange, validateIdToken, logout};
8+
export default {auth, codeExchange, validateIdToken, logout, redirectPostLogout};
99

1010
function retryOriginalRequest(r) {
1111
delete r.headersOut["WWW-Authenticate"]; // Remove evidence of original failed auth_jwt
@@ -253,11 +253,26 @@ function validateIdToken(r) {
253253
}
254254
}
255255

256+
// Default RP-Initiated or Custom Logout w/ OP as per:
257+
// https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout
258+
// https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RedirectionAfterLogout
259+
// An RP requests that the OP log out the end-user by redirecting the end-user's
260+
// User Agent to the OP's Logout endpoint.
256261
function logout(r) {
257262
r.log("OIDC logout for " + r.variables.cookie_auth_token);
258-
r.variables.session_jwt = "-";
259-
r.variables.refresh_token = "-";
260-
r.return(302, r.variables.oidc_logout_redirect);
263+
var queryParams = '';
264+
if (r.variables.oidc_logout_query_params) {
265+
queryParams = '?' + r.variables.oidc_logout_query_params;
266+
}
267+
r.variables.session_jwt = '-';
268+
r.variables.access_token = '-';
269+
r.variables.refresh_token = '-';
270+
r.return(302, r.variables.oidc_end_session_endpoint + queryParams);
271+
}
272+
273+
// Redirect URI after logged-out from the OP.
274+
function redirectPostLogout(r) {
275+
r.return(302, r.variables.oidc_logout_landing_page);
261276
}
262277

263278
function getAuthZArgs(r) {

openid_connect.server_conf

+16-3
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,27 @@
6767
}
6868

6969
location = /logout {
70+
# RP-Initiated Logout to interact with $oidc_end_session_endpoint as per:
71+
# https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout
7072
status_zone "OIDC logout";
71-
add_header Set-Cookie "auth_token=; $oidc_cookie_flags"; # Send empty cookie
72-
add_header Set-Cookie "auth_redir=; $oidc_cookie_flags"; # Erase original cookie
7373
js_content oidc.logout;
7474
}
7575

7676
location = /_logout {
77-
# This location is the default value of $oidc_logout_redirect (in case it wasn't configured)
77+
# This location is a RP's callback URI which is called by the IdP after
78+
# successful logout from the IdP by calling $oidc_logout_endpoint.
79+
80+
# Clean cookies
81+
add_header Set-Cookie "auth_token=; $oidc_cookie_flags"; # Send empty cookie
82+
add_header Set-Cookie "auth_redir=; $oidc_cookie_flags"; # Erase original cookie
83+
add_header Set-Cookie "auth_nonce=; $oidc_cookie_flags";
84+
85+
js_content oidc.redirectPostLogout;
86+
}
87+
88+
location = /logout_page {
89+
# This location is a default value of $oidc_logout_landing_page as a
90+
# Built-in, simple logout page in case it wasn't configured.
7891
default_type text/plain;
7992
return 200 "Logged out\n";
8093
}

openid_connect_configuration.conf

+16-4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ map $host $oidc_jwt_keyfile {
2828
default "http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/certs";
2929
}
3030

31+
map $host $oidc_end_session_endpoint {
32+
default "http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/logout";
33+
}
34+
35+
map $host $oidc_logout_query_params {
36+
# Each IdP may use different query params of the $oidc_end_session_endpoint.
37+
# For example, Amazon Cognito requires 'logout_uri', and Auth0 requires
38+
# 'returnTo' instead of 'post_logout_redirect_uri' in the query params.
39+
default "post_logout_redirect_uri=$redirect_base/_logout&id_token_hint=$session_jwt";;
40+
#www.example.com "client_id=$oidc_client&logout_uri=$redirect_base/_logout";
41+
}
42+
3143
map $host $oidc_client {
3244
default "my-client-id";
3345
}
@@ -44,10 +56,10 @@ map $host $oidc_scopes {
4456
default "openid+profile+email+offline_access";
4557
}
4658

47-
map $host $oidc_logout_redirect {
48-
# Where to send browser after requesting /logout location. This can be
49-
# replaced with a custom logout page, or complete URL.
50-
default "/_logout"; # Built-in, simple logout page
59+
map $host $oidc_logout_landing_page {
60+
# Where to redirect browser after successful logout from the IdP.
61+
default "$redirect_base/logout_page"; # Built-in, simple logout page
62+
#www.example.com $redirect_base;
5163
}
5264

5365
map $host $oidc_hmac_key {

0 commit comments

Comments
 (0)