diff --git a/src/core/plugins/auth/actions.js b/src/core/plugins/auth/actions.js index 6c124608..da77ee22 100644 --- a/src/core/plugins/auth/actions.js +++ b/src/core/plugins/auth/actions.js @@ -152,7 +152,7 @@ export const authorizeAccessCodeWithFormParams = ( { auth, redirectUrl } ) => ( } export const authorizeAccessCodeWithBasicAuthentication = ( { auth, redirectUrl } ) => ( { authActions } ) => { - let { schema, name, clientId, clientSecret } = auth + let { schema, name, clientId, clientSecret, codeVerifier } = auth let headers = { Authorization: "Basic " + btoa(clientId + ":" + clientSecret) } @@ -160,7 +160,8 @@ export const authorizeAccessCodeWithBasicAuthentication = ( { auth, redirectUrl grant_type: "authorization_code", code: auth.code, client_id: clientId, - redirect_uri: redirectUrl + redirect_uri: redirectUrl, + code_verifier: codeVerifier } return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers}) @@ -277,4 +278,4 @@ export const persistAuthorizationIfNeeded = () => ( { authSelectors, getConfigs const authorized = authSelectors.authorized() localStorage.setItem("authorized", JSON.stringify(authorized.toJS())) } -} \ No newline at end of file +} diff --git a/test/unit/core/oauth2-authorize.js b/test/unit/core/oauth2-authorize.js index 5fea1d46..aabb07b3 100644 --- a/test/unit/core/oauth2-authorize.js +++ b/test/unit/core/oauth2-authorize.js @@ -112,6 +112,40 @@ describe("oauth2", () => { createCodeChallengeSpy.mockReset() }) + + it("should send code_challenge when using accessCode flow with usePkceWithAuthorizationCodeGrant enabled", () => { + const windowOpenSpy = jest.spyOn(win, "open") + mockSchema.flow = "accessCode" + + const expectedCodeVerifier = "mock_code_verifier" + const expectedCodeChallenge = "mock_code_challenge" + + const generateCodeVerifierSpy = jest.spyOn(utils, "generateCodeVerifier").mockImplementation(() => expectedCodeVerifier) + const createCodeChallengeSpy = jest.spyOn(utils, "createCodeChallenge").mockImplementation(() => expectedCodeChallenge) + + authConfig.authConfigs.useBasicAuthenticationWithAccessCodeGrant = true + authConfig.authConfigs.usePkceWithAuthorizationCodeGrant = true + + oauth2Authorize(authConfig) + expect(win.open.mock.calls.length).toEqual(1) + + const actualUrl = new URLSearchParams(win.open.mock.calls[0][0]) + expect(actualUrl.get("code_challenge")).toBe(expectedCodeChallenge) + expect(actualUrl.get("code_challenge_method")).toBe("S256") + + expect(createCodeChallengeSpy.mock.calls.length).toEqual(1) + expect(createCodeChallengeSpy.mock.calls[0][0]).toBe(expectedCodeVerifier) + + // The code_verifier should be stored to be able to send in + // on the TokenUrl call + expect(authConfig.auth.codeVerifier).toBe(expectedCodeVerifier) + + // Restore spies + windowOpenSpy.mockReset() + generateCodeVerifierSpy.mockReset() + createCodeChallengeSpy.mockReset() + }) + it("should send code_challenge when using authorization_code flow with usePkceWithAuthorizationCodeGrant enabled", () => { const windowOpenSpy = jest.spyOn(win, "open") mockSchema.flow = "authorization_code" diff --git a/test/unit/core/plugins/auth/actions.js b/test/unit/core/plugins/auth/actions.js index 84e0a53d..8b08587c 100644 --- a/test/unit/core/plugins/auth/actions.js +++ b/test/unit/core/plugins/auth/actions.js @@ -7,6 +7,7 @@ import { logoutWithPersistOption, persistAuthorizationIfNeeded } from "corePlugins/auth/actions" +import { authorizeAccessCodeWithBasicAuthentication } from "../../../../../src/core/plugins/auth/actions" describe("auth plugin - actions", () => { @@ -178,26 +179,31 @@ describe("auth plugin - actions", () => { describe("tokenRequest", function () { it("should send the code verifier when set", () => { - const data = { - auth: { - schema: { - get: () => "http://tokenUrl" + const testCodeVerifierForAuthorizationCodeFlows = (flowAction) => { + const data = { + auth: { + schema: { + get: () => "http://tokenUrl", + }, + codeVerifier: "mock_code_verifier", }, - codeVerifier: "mock_code_verifier" - }, - redirectUrl: "http://google.com" + redirectUrl: "http://google.com", + } + + const authActions = { + authorizeRequest: jest.fn(), + } + + flowAction(data)({ authActions }) + + expect(authActions.authorizeRequest.mock.calls.length).toEqual(1) + const actualArgument = authActions.authorizeRequest.mock.calls[0][0] + expect(actualArgument.body).toContain("code_verifier=" + data.auth.codeVerifier) + expect(actualArgument.body).toContain("grant_type=authorization_code") } - const authActions = { - authorizeRequest: jest.fn() - } - - authorizeAccessCodeWithFormParams(data)({ authActions }) - - expect(authActions.authorizeRequest.mock.calls.length).toEqual(1) - const actualArgument = authActions.authorizeRequest.mock.calls[0][0] - expect(actualArgument.body).toContain("code_verifier=" + data.auth.codeVerifier) - expect(actualArgument.body).toContain("grant_type=authorization_code") + testCodeVerifierForAuthorizationCodeFlows(authorizeAccessCodeWithFormParams) + testCodeVerifierForAuthorizationCodeFlows(authorizeAccessCodeWithBasicAuthentication) }) }) @@ -278,7 +284,7 @@ describe("auth plugin - actions", () => { localStorage.clear() }) it("should skip if `persistAuthorization` is turned off", () => { - // Given + // Given const system = { getConfigs: () => ({ persistAuthorization: false