Skip to content

Commit 08d42c1

Browse files
committed
fix: session mgmt, post logout
1 parent 93466c5 commit 08d42c1

File tree

5 files changed

+59
-44
lines changed

5 files changed

+59
-44
lines changed

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ services:
99
dockerfile: ./docker/docker-files/nginxplus-ubuntu18.04/Dockerfile
1010
image: nginxplus_oidc_auth0_ubuntu18.04
1111
ports:
12-
- 443:443
12+
- 12000:12000
1313
volumes:
1414
- type: bind
1515
source: ./

oidc.js

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
*/
66

77
// Constants for common error message. These will be cleaned up.
8-
var ERR_CFG_VARS = 'OIDC missing configuration variables: ';
9-
var ERR_AC_TOKEN = 'OIDC Access Token validation error: ';
10-
var ERR_ID_TOKEN = 'OIDC ID Token validation error: ';
11-
var ERR_IDP_AUTH = 'OIDC unexpected response from IdP in code exchange';
12-
var ERR_TOKEN_RES = 'OIDC AuthZ code sent but token response is not JSON. ';
13-
var ERR_X_CLIENT_ID_COOKIE = 'X-Client-Id should be in cookie';
14-
var ERR_X_CLIENT_ID_NOT_FOUND = 'X-Client-Id not found in the IdP app';
15-
var WRN_SESSION = 'OIDC session is invalid';
16-
var INF_REFRESH_TOKEN = 'OIDC refresh success, updating tokens for ';
17-
var INF_REPLACE_TOKEN = 'OIDC replacing previous refresh token (';
8+
var ERR_CFG_VARS = 'OIDC missing configuration variables';
9+
var ERR_AC_TOKEN = 'OIDC Access Token validation error';
10+
var ERR_ID_TOKEN = 'OIDC ID Token validation error';
11+
var ERR_IDP_AUTH = 'OIDC unexpected response from IdP in code exchange';
12+
var ERR_TOKEN_RES = 'OIDC AuthZ code sent but token response is not JSON';
13+
var ERR_CLIENT_ID = 'Check if cookie is removed, and client_id is there';
14+
var ERR_IDP_APP_NAME = 'IdP app is not set in $oidc_app_name';
15+
var WRN_SESSION = 'OIDC session is invalid';
16+
var INF_SESSION = 'OIDC session is valid';
17+
var INF_REFRESH_TOKEN = 'OIDC refresh success, updating tokens for ';
18+
var INF_REPLACE_TOKEN = 'OIDC replacing previous refresh token';
1819

1920
// Flag to check if there is still valid session cookie. It is used by auth()
2021
// and validateIdToken().
@@ -133,11 +134,25 @@ function validateIdToken(r) {
133134
//
134135
// - https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowTokenValidation
135136
// - https://openid.net/specs/openid-connect-core-1_0.html#ImplicitTokenValidation
137+
//
136138
// - This function is called by the location of `_access_token_validation` which
137139
// is called by either OIDC code exchange or refersh token request.
140+
//
138141
// - The 'aud' claim isn't contained in general ID token from Amazon Cognito,
139142
// although we can add it. Hence, the claim isn't part of this validation.
140143
//
144+
// - This function is for the case when you want to validate the token within
145+
// NGINX layer to following the spec. of OpenID Connect Core 1.0.
146+
//
147+
// - But, this token is mostly validated by using one of following options.
148+
//
149+
// + Option 1. validate a token (assumtion: JWT format) by using
150+
// a NGINX auth_jwt directive to validate it via IdP URI.
151+
// auth_jwt "" token=$access_token;
152+
// auth_jwt_key_request /_jwks_uri;
153+
//
154+
// + Option 2. validate a token by using IdP token introspection endpoint.
155+
//
141156
function validateAccessToken(r) {
142157
var missingClaims = []
143158
if (!isValidRequiredClaims(r, ERR_AC_TOKEN, missingClaims)) {
@@ -208,7 +223,6 @@ function generateCustomEndpoint(r, uri, isEnableCustomPath, paths) {
208223
var res = '';
209224
var key = '';
210225
var isKey = false;
211-
r.log('### paths: ' + paths)
212226
var items = JSON.parse(paths);
213227
for (var i = 0; i < uri.length; i++) {
214228
switch (uri[i]) {
@@ -271,7 +285,7 @@ function startIdPAuthZ(r) {
271285
}
272286
}
273287
if (missingConfig.length) {
274-
r.error(ERR_CFG_VARS + '$oidc_' + missingConfig.join(' $oidc_'));
288+
r.error(ERR_CFG_VARS + ': $oidc_' + missingConfig.join(' $oidc_'));
275289
r.return(500, r.variables.internal_error_message);
276290
return;
277291
}
@@ -335,7 +349,7 @@ function handleSuccessfulRefreshResponse(r, res) {
335349
// Update new refresh token to key/value store if we got a new one.
336350
r.log(INF_REFRESH_TOKEN + r.variables.cookie_session_id);
337351
if (r.variables.refresh_token != tokenset.refresh_token) {
338-
r.log(INF_REPLACE_TOKEN + r.variables.refresh_token +
352+
r.log(INF_REPLACE_TOKEN + ' (' + r.variables.refresh_token +
339353
') with new value: ' + tokenset.refresh_token);
340354
r.variables.refresh_token = tokenset.refresh_token;
341355
}
@@ -473,7 +487,7 @@ function handleSuccessfulTokenResponse(r, res) {
473487
'; ' + r.variables.oidc_cookie_flags;
474488
r.return(302, r.variables.redirect_base + r.variables.cookie_auth_redir);
475489
} catch (e) {
476-
r.error(ERR_TOKEN_RES + res.responseBody);
490+
r.error(ERR_TOKEN_RES + ' ' + res.responseBody);
477491
r.return(502);
478492
}
479493
}
@@ -512,7 +526,8 @@ function getAuthZArgs(r) {
512526
'&client_id=' + r.variables.oidc_client +
513527
'&redirect_uri=' + redirectURI +
514528
// uncomment when to need claims of access token in Auth0.
515-
// '&audience=' + 'https://{{domain}}}/api/v2/' +
529+
// '&audience=' + 'https://{{domain}}}/api/v2/' +
530+
'&audience=' + 'https://dev-s4i2bm4p.us.auth0.com/api/v2/' +
516531
'&nonce=' + nonceHash;
517532
var cookieFlags = r.variables.oidc_cookie_flags;
518533
r.headersOut['Set-Cookie'] = [
@@ -704,7 +719,7 @@ function isValidRequiredClaims(r, msgPrefix, missingClaims) {
704719
}
705720
}
706721
if (missingClaims.length) {
707-
r.error(msgPrefix + 'missing claim(s) ' + missingClaims.join(' '));
722+
r.error(msgPrefix + ': missing claim(s) ' + missingClaims.join(' '));
708723
return false;
709724
}
710725
} catch (e) {
@@ -733,6 +748,8 @@ function isValidTokenSet(r, tokenset) {
733748
// The validateIdToken() logs error so that r.error() isn't used.
734749
return isErr;
735750
}
751+
// The access token is mostly validated by IdP using auth_jwt directive.
752+
// This can be used when you want to validate the token set in NGINX.
736753
if (r.variables.access_token_validation_enable == 1 &&
737754
!isValidToken(r, '/_access_token_validation', tokenset.access_token)) {
738755
// The validateAccessToken() logs error so that r.error() isn't used.
@@ -804,12 +821,12 @@ function isValidSession(r) {
804821
// the session cookie could play from any client (browsers or command line).
805822
//
806823
function validateSession(r) {
807-
if (r.variables.session_validation_enable == 1 && !isValidSession(r)) {
824+
if (!isValidSession(r)) {
808825
r.warn(WRN_SESSION)
809826
r.return(401, '{"message": "' + WRN_SESSION + '"}\n')
810827
return false;
811828
}
812-
r.return(200, '{"message": "' + WRN_SESSION + '"}\n')
829+
r.return(200, '{"message": "' + INF_SESSION + '"}\n')
813830
return true;
814831
}
815832

@@ -820,14 +837,13 @@ function validateSession(r) {
820837
function isValidXClientId(r) {
821838
if (r.variables.client_id_validation_enable == 1) {
822839
if (!r.variables.cookie_client_id) {
823-
r.warn(ERR_X_CLIENT_ID_COOKIE)
824-
r.return(400, '{"message": "' + ERR_X_CLIENT_ID_COOKIE + '"}\n')
840+
r.warn(ERR_CLIENT_ID)
841+
r.return(400, '{"message": "' + ERR_CLIENT_ID + '"}\n')
825842
return false
826843
}
827844
if (r.variables.oidc_app_name == '') {
828-
var errMsg = ERR_X_CLIENT_ID_NOT_FOUND + ': ' + r.variables.cookie_client_id;
829-
r.warn(errMsg)
830-
r.return(404, '{"message": "' + errMsg + '"}\n')
845+
r.warn(ERR_IDP_APP_NAME)
846+
r.return(404, '{"message": "' + ERR_IDP_APP_NAME + '"}\n')
831847
return false
832848
}
833849
}

oidc_frontend_backend.conf

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ server {
3232
error_log /var/log/nginx/error.log debug; # Reduce severity level as required
3333
access_log /var/log/nginx/access.log main;
3434

35-
listen 443 ssl;
35+
listen 12000 ssl;
3636
server_name nginx.auth0.test;
3737

3838
ssl_certificate /etc/ssl/nginx/nginx-repo.crt;
@@ -59,9 +59,12 @@ server {
5959
location /v1/api/example {
6060
auth_request /_session_validation;
6161
auth_request_set $session_status $upstream_status;
62-
error_page 401 @session_error;
62+
if ($session_validation_enable) {
63+
error_page 401 = @session_error;
64+
}
6365

64-
auth_jwt "" token=$id_token;
66+
auth_jwt "" token=$access_token;
67+
#auth_jwt_key_file $oidc_jwt_keyfile; # Enable when using filename
6568
auth_jwt_key_request /_jwks_uri; # Enable when using URL
6669

6770
proxy_set_header Authorization "Bearer $access_token";

oidc_nginx_http.conf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,14 @@ map $http_x_forwarded_proto $proto {
3939
}
4040

4141
map $x_client_id $post_logout_return_uri {
42+
# The following examples can be replaced with a custom logout page, or
43+
# complete URL to be redirected after successful logout from the IdP.
44+
45+
# Example 1: Redirect to the original page.
4246
default $redirect_base;
47+
48+
# Example 2: Redirect to a custom logout page
49+
# default https://www.google.com;
4350
}
4451

4552
map $x_client_id $return_token_to_client_on_login {

oidc_nginx_server.conf

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,9 @@
108108
# This location is called by frontend to retrieve user info via the IDP.
109109
auth_request /_session_validation;
110110
auth_request_set $session_status $upstream_status;
111-
error_page 401 = @session_error;
112-
113-
auth_jwt "" token=$id_token;
114-
auth_jwt_key_request /_jwks_uri; # Enable when using URL
111+
if ($session_validation_enable) {
112+
error_page 401 = @session_error;
113+
}
115114

116115
proxy_ssl_server_name on; # For SNI to the IdP
117116
proxy_set_header Authorization "Bearer $access_token";
@@ -149,18 +148,8 @@
149148
add_header Set-Cookie "auth_nonce=; $oidc_cookie_flags";
150149
add_header Set-Cookie "client_id=; $oidc_cookie_flags";
151150

152-
# The following examples can be replaced with a custom logout page, or
153-
# complete URL.
154-
155-
# Example 1: Redirect to the original page via $post_logout_return_uri.
151+
# Redirect to either the original page or custom logout page.
156152
js_content oidc.redirectPostLogout;
157-
158-
# Example 2: Built-in, simple logout page
159-
# default_type text/plain;
160-
# return 200 "Logged out\n";
161-
162-
# Example 3: Custom logout page
163-
# proxy_pass http://my_frontend_site/logout;
164153
}
165154

166155
location @oidc_error {
@@ -171,7 +160,7 @@
171160
}
172161

173162
location @session_error {
174-
status_zone "OIDC session error";
163+
status_zone "OIDC error: session";
175164
default_type application/json;
176165

177166
# Clean cookies
@@ -180,7 +169,7 @@
180169
add_header Set-Cookie "auth_nonce=; $oidc_cookie_flags";
181170
add_header Set-Cookie "client_id=; $oidc_cookie_flags";
182171

183-
set $session_status '{ "session" : "invalid" }';
172+
set $session_status '{ "message" : "invalid session" }';
184173
return 401 $session_status;
185174
}
186175

0 commit comments

Comments
 (0)