diff --git a/__tests__/Auth0Client/getTokenSilently.test.ts b/__tests__/Auth0Client/getTokenSilently.test.ts index 17b017f0a..2c46b1cbc 100644 --- a/__tests__/Auth0Client/getTokenSilently.test.ts +++ b/__tests__/Auth0Client/getTokenSilently.test.ts @@ -1685,7 +1685,7 @@ describe('Auth0Client', () => { redirect_uri: TEST_REDIRECT_URI, client_id: TEST_CLIENT_ID, grant_type: 'authorization_code', - custom_param: 'hello+world', + custom_param: 'hello world', another_custom_param: 'bar', code_verifier: TEST_CODE_VERIFIER }, diff --git a/__tests__/Auth0Client/helpers.ts b/__tests__/Auth0Client/helpers.ts index 794282c4b..6d94f0d82 100644 --- a/__tests__/Auth0Client/helpers.ts +++ b/__tests__/Auth0Client/helpers.ts @@ -42,7 +42,12 @@ export const assertPostFn = (mockFetch: jest.Mock) => { expect(url).toEqual(actualUrl); expect(body).toEqual( - json ? JSON.parse(call.body) : utils.parseQueryResult(call.body) + json + ? JSON.parse(call.body) + : Array.from(new URLSearchParams(call.body).entries()).reduce( + (acc, curr) => ({ ...acc, [curr[0]]: curr[1] }), + {} + ) ); if (headers) { diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 37a5dae4e..29f43b5d3 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -50,7 +50,7 @@ const setup = async ( utils.sha256.mockReturnValue(Promise.resolve(TEST_ARRAY_BUFFER)); utils.bufferToBase64UrlEncoded.mockReturnValue(TEST_BASE64_ENCODED_STRING); - utils.parseQueryResult.mockReturnValue({ + utils.parseAuthenticationResult.mockReturnValue({ state: TEST_ENCODED_STATE, code: TEST_CODE }); diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts index 1ef521977..5c8cef4e7 100644 --- a/__tests__/utils.test.ts +++ b/__tests__/utils.test.ts @@ -1,5 +1,5 @@ import { - parseQueryResult, + parseAuthenticationResult, createQueryParams, bufferToBase64UrlEncoded, createRandomString, @@ -23,29 +23,42 @@ afterEach(() => { }); describe('utils', () => { - describe('parseQueryResult', () => { + describe('parseAuthenticationResult', () => { it('parses the query string', () => { expect( - parseQueryResult('value=test&otherValue=another-test') + parseAuthenticationResult('code=test&state=another-test') ).toMatchObject({ - value: 'test', - otherValue: 'another-test' + code: 'test', + state: 'another-test' }); }); + + it('parses the query string when containing raw =', () => { + expect( + parseAuthenticationResult('code=test&state=another-test==') + ).toMatchObject({ + code: 'test', + state: 'another-test==' + }); + }); + + it('parses the query string when containing url encoded =', () => { + expect( + parseAuthenticationResult('code=test&state=another-test%3D%3D') + ).toMatchObject({ + code: 'test', + state: 'another-test==' + }); + }); + it('strips off hash values', () => { expect( - parseQueryResult('code=some-code&state=some-state#__') + parseAuthenticationResult('code=some-code&state=some-state#__') ).toMatchObject({ code: 'some-code', state: 'some-state' }); }); - it('converts `expires_in` to int', () => { - expect(parseQueryResult('value=test&expires_in=10')).toMatchObject({ - value: 'test', - expires_in: 10 - }); - }); }); describe('createQueryParams', () => { it('creates query string from object', () => { diff --git a/src/Auth0Client.ts b/src/Auth0Client.ts index 7389fc7a3..41d21ea35 100644 --- a/src/Auth0Client.ts +++ b/src/Auth0Client.ts @@ -3,7 +3,7 @@ import Lock from 'browser-tabs-lock'; import { createQueryParams, runPopup, - parseQueryResult, + parseAuthenticationResult, encode, createRandomString, runIframe, @@ -486,7 +486,7 @@ export class Auth0Client { throw new Error('There are no query params available for parsing.'); } - const { state, code, error, error_description } = parseQueryResult( + const { state, code, error, error_description } = parseAuthenticationResult( queryStringFragments.join('') ); diff --git a/src/utils.ts b/src/utils.ts index b1dbf5836..1c055f002 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -12,24 +12,21 @@ import { PopupCancelledError } from './errors'; -export const parseQueryResult = (queryString: string): AuthenticationResult => { +export const parseAuthenticationResult = ( + queryString: string +): AuthenticationResult => { if (queryString.indexOf('#') > -1) { - queryString = queryString.substr(0, queryString.indexOf('#')); + queryString = queryString.substring(0, queryString.indexOf('#')); } - const queryParams = queryString.split('&'); - const parsedQuery: Record = {}; + const searchParams = new URLSearchParams(queryString); - queryParams.forEach(qp => { - const [key, val] = qp.split('='); - parsedQuery[key] = decodeURIComponent(val); - }); - - if (parsedQuery.expires_in) { - parsedQuery.expires_in = parseInt(parsedQuery.expires_in); - } - - return parsedQuery as AuthenticationResult; + return { + state: searchParams.get('state')!, + code: searchParams.get('code') || undefined, + error: searchParams.get('error') || undefined, + error_description: searchParams.get('error_description') || undefined + }; }; export const runIframe = (