Skip to content

Commit

Permalink
fix(ui): add state parameter in the pkce flow (#17235)
Browse files Browse the repository at this point in the history
* Add state to pkce flow

Signed-off-by: Jungho Son <js3692@users.noreply.github.com>

* Call unset

Signed-off-by: Jungho Son <js3692@users.noreply.github.com>

---------

Signed-off-by: Jungho Son <js3692@users.noreply.github.com>
  • Loading branch information
js3692 committed Sep 22, 2024
1 parent 0573ed7 commit 555854c
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 7 deletions.
3 changes: 2 additions & 1 deletion ui/src/app/login/components/pkce-verify.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {useEffect, useState} from 'react';
import {RouteComponentProps} from 'react-router';
import {services} from '../../shared/services';
import {PKCECodeVerifier, PKCELoginError, getPKCERedirectURI, pkceCallback} from './utils';
import {PKCECodeVerifier, PKCEState, PKCELoginError, getPKCERedirectURI, pkceCallback} from './utils';

import './pkce-verify.scss';

Expand All @@ -18,6 +18,7 @@ export const PKCEVerification = (props: RouteComponentProps<any>) => {
.finally(() => {
setLoading(false);
PKCECodeVerifier.unset();
PKCEState.unset();
});
}, [props.location]);

Expand Down
20 changes: 14 additions & 6 deletions ui/src/app/login/components/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
authorizationCodeGrantRequest,
calculatePKCECodeChallenge,
discoveryRequest,
expectNoState,
generateRandomCodeVerifier,
generateRandomState,
isOAuth2Error,
parseWwwAuthenticateChallenges,
processAuthorizationCodeOpenIDResponse,
Expand All @@ -22,6 +22,12 @@ export const PKCECodeVerifier = {
unset: () => sessionStorage.removeItem(window.btoa('code_verifier'))
};

export const PKCEState = {
get: () => sessionStorage.getItem(window.btoa('pkce_session_id')),
set: (sessionId: string) => sessionStorage.setItem(window.btoa('pkce_session_id'), sessionId),
unset: () => sessionStorage.removeItem(window.btoa('pkce_session_id'))
};

export const getPKCERedirectURI = () => {
const currentOrigin = new URL(window.location.origin);

Expand Down Expand Up @@ -74,6 +80,8 @@ export const pkceLogin = async (oidcConfig: AuthSettings['oidcConfig'], redirect
throw new PKCELoginError('No Authorization Server endpoint found');
}

const state = generateRandomState();

const codeVerifier = generateRandomCodeVerifier();

const codeChallange = await calculatePKCECodeChallenge(codeVerifier);
Expand All @@ -86,8 +94,10 @@ export const pkceLogin = async (oidcConfig: AuthSettings['oidcConfig'], redirect
authorizationServerConsentScreen.searchParams.set('redirect_uri', redirectURI);
authorizationServerConsentScreen.searchParams.set('response_type', 'code');
authorizationServerConsentScreen.searchParams.set('scope', oidcConfig.scopes.join(' '));
authorizationServerConsentScreen.searchParams.set('state', state);

PKCECodeVerifier.set(codeVerifier);
PKCEState.set(state);

window.location.replace(authorizationServerConsentScreen.toString());
};
Expand All @@ -110,18 +120,16 @@ export const pkceCallback = async (queryParams: string, oidcConfig: AuthSettings
throw new PKCELoginError('No code in query parameters');
}

if (callbackQueryParams.get('state') === '') {
callbackQueryParams.delete('state');
}

const {authorizationServer} = await validateAndGetOIDCForPKCE(oidcConfig);

const client: Client = {
client_id: oidcConfig.clientID,
token_endpoint_auth_method: 'none'
};

const params = validateAuthResponse(authorizationServer, client, callbackQueryParams, expectNoState);
const expectedState = PKCEState.get();

const params = validateAuthResponse(authorizationServer, client, callbackQueryParams, expectedState);

if (isOAuth2Error(params)) {
throw new PKCELoginError('Error validating auth response');
Expand Down

0 comments on commit 555854c

Please sign in to comment.