From 99bad051d162571735315aa13390654c03f525d5 Mon Sep 17 00:00:00 2001 From: Shawn Kim Date: Thu, 22 Dec 2022 22:21:28 -0800 Subject: [PATCH] feat: enhance custom query params for authz endpoint --- openid_connect.js | 26 ++++++++++++++++---------- openid_connect_configuration.conf | 30 ++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/openid_connect.js b/openid_connect.js index e4f2084..5cb9508 100644 --- a/openid_connect.js +++ b/openid_connect.js @@ -5,6 +5,9 @@ */ var newSession = false; // Used by oidcAuth() and validateIdToken() +const EXTRA_PARAMS = 1; +const REPLACE_PARAMS = 2; + export default {auth, codeExchange, validateIdToken, logout}; function retryOriginalRequest(r) { @@ -48,7 +51,7 @@ function auth(r, afterSyncCheck) { return; } // Redirect the client to the IdP login page with the cookies we need for state - r.return(302, r.variables.oidc_authz_endpoint + getAuthZArgs(r)); + r.return(302, r.variables.oidc_authz_endpoint + getQueryParamsAuthZ(r)); return; } @@ -260,18 +263,15 @@ function logout(r) { r.return(302, r.variables.oidc_logout_redirect); } -function getAuthZArgs(r) { +function getQueryParamsAuthZ(r) { // Choose a nonce for this flow for the client, and hash it for the IdP var noncePlain = r.variables.request_id; var c = require('crypto'); var h = c.createHmac('sha256', r.variables.oidc_hmac_key).update(noncePlain); var nonceHash = h.digest('base64url'); - var authZArgs = "?response_type=code&scope=" + r.variables.oidc_scopes + "&client_id=" + r.variables.oidc_client + "&redirect_uri="+ r.variables.redirect_base + r.variables.redir_location + "&nonce=" + nonceHash; - - if (r.variables.oidc_authz_extra_args) { - authZArgs += "&" + r.variables.oidc_authz_extra_args; - } + var queryParams = "?response_type=code&scope=" + r.variables.oidc_scopes + "&client_id=" + r.variables.oidc_client + "&redirect_uri="+ r.variables.redirect_base + r.variables.redir_location + "&nonce=" + nonceHash; + r.variables.nonce_hash = nonceHash; r.headersOut['Set-Cookie'] = [ "auth_redir=" + r.variables.request_uri + "; " + r.variables.oidc_cookie_flags, "auth_nonce=" + noncePlain + "; " + r.variables.oidc_cookie_flags @@ -282,12 +282,18 @@ function getAuthZArgs(r) { r.variables.pkce_id = c.createHash('sha256').update(String(Math.random())).digest('base64url'); var pkce_code_challenge = c.createHash('sha256').update(pkce_code_verifier).digest('base64url'); r.variables.pkce_code_verifier = pkce_code_verifier; + r.variables.pkce_code_challenge = pkce_code_challenge; - authZArgs += "&code_challenge_method=S256&code_challenge=" + pkce_code_challenge + "&state=" + r.variables.pkce_id; + queryParams += "&code_challenge_method=S256&code_challenge=" + pkce_code_challenge + "&state=" + r.variables.pkce_id; } else { - authZArgs += "&state=0"; + queryParams += "&state=0"; + } + if (r.variables.oidc_authz_query_params_option == REPLACE_PARAMS) { + queryParams = '?' + r.variables.oidc_authz_query_params; + } else if (r.variables.oidc_authz_query_params_option == EXTRA_PARAMS) { + queryParams += '&' + r.variables.oidc_authz_query_params; } - return authZArgs; + return queryParams; } function idpClientAuth(r) { diff --git a/openid_connect_configuration.conf b/openid_connect_configuration.conf index e8a9759..1739e6e 100644 --- a/openid_connect_configuration.conf +++ b/openid_connect_configuration.conf @@ -8,16 +8,22 @@ map $host $oidc_authz_endpoint { #www.example.com "https://my-idp/oauth2/v1/authorize"; } -map $host $oidc_authz_extra_args { - # Extra arguments to include in the request to the IdP's authorization - # endpoint. - # Some IdPs provide extended capabilities controlled by extra arguments, - # for example Keycloak can select an IdP to delegate to via the - # "kc_idp_hint" argument. - # Arguments must be expressed as query string parameters and URL-encoded +map $host $oidc_authz_query_params_option { + # The option of custom query params in the request of $oidc_authz_endpoint. + # 0: built-in params (e.g. response_type, client_id, redirect_uri, nonce) + # 1: extra args($oidc_authz_query_params) are extended after built-in params + # 2: replace built-in params with custom params($oidc_authz_query_params) + default 0; +} + +map $host $oidc_authz_query_params { + # Each IdP may use different query params of the $oidc_authz_endpoint. For + # example, Keycloak can select an IdP to delegate to via the "kc_idp_hint" + # argument. It must be expressed as query string parameters and URL-encoded # if required. default ""; - #www.example.com "kc_idp_hint=another_provider" + #extra.args.example "kc_idp_hint=another_provider"; + #replace.args.example "response_type=code&scope=$oidc_scopes&client_id=$oidc_client&redirect_uri=$redirect_base$redir_location&nonce=$nonce_hash&state=0&audience=https://auth0.com/api/v2/"; } map $host $oidc_token_endpoint { @@ -89,13 +95,17 @@ 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_zone zone=oidc_pkce_verifier:128K timeout=90s; # Temporary storage for PKCE code verifier. +keyval_zone zone=oidc_pkce_challenge:128K timeout=90s; # Temporary storage for PKCE code challenge. +keyval_zone zone=oidc_nonce:128K timeout=90s; # Temporary storage for nonce. 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; +keyval $request_id $nonce_hash zone=oidc_nonce; +keyval $pkce_id $pkce_code_verifier zone=oidc_pkce_verifier; +keyval $pkce_id $pkce_code_challenge zone=oidc_pkce_challenge; auth_jwt_claim_set $jwt_audience aud; # In case aud is an array js_import oidc from conf.d/openid_connect.js;