Skip to content

Commit

Permalink
fix(auth): support pkce when using basic auth header (#7038)
Browse files Browse the repository at this point in the history
* support pkce when using basic auth header

* test(auth): useBasicAuthenticationWithAccessCodeGrant + usePkceWithAuthorizationCodeGrant
  • Loading branch information
hcldan committed Mar 10, 2021
1 parent dc694ba commit f23a9d6
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 20 deletions.
7 changes: 4 additions & 3 deletions src/core/plugins/auth/actions.js
Expand Up @@ -152,15 +152,16 @@ 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)
}
let form = {
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})
Expand Down Expand Up @@ -277,4 +278,4 @@ export const persistAuthorizationIfNeeded = () => ( { authSelectors, getConfigs
const authorized = authSelectors.authorized()
localStorage.setItem("authorized", JSON.stringify(authorized.toJS()))
}
}
}
34 changes: 34 additions & 0 deletions test/unit/core/oauth2-authorize.js
Expand Up @@ -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"
Expand Down
40 changes: 23 additions & 17 deletions test/unit/core/plugins/auth/actions.js
Expand Up @@ -7,6 +7,7 @@ import {
logoutWithPersistOption,
persistAuthorizationIfNeeded
} from "corePlugins/auth/actions"
import { authorizeAccessCodeWithBasicAuthentication } from "../../../../../src/core/plugins/auth/actions"

describe("auth plugin - actions", () => {

Expand Down Expand Up @@ -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()
}
const authActions = {
authorizeRequest: jest.fn(),
}

authorizeAccessCodeWithFormParams(data)({ authActions })
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")
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)
})
})

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit f23a9d6

Please sign in to comment.