Skip to content

Commit

Permalink
fix: refactor all pkce code into a single method (#860)
Browse files Browse the repository at this point in the history
## What kind of change does this PR introduce?

Moves all PKCE code generation logic into a single method. This removes
duplicate code and facilitates changes around PKCE methods

Co-authored-by: joel <[email protected]>
  • Loading branch information
J0 and joel authored Mar 11, 2024
1 parent e8a1fc9 commit 860bffc
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 37 deletions.
61 changes: 24 additions & 37 deletions src/GoTrueClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ import {
uuid,
retryable,
sleep,
generatePKCEVerifier,
generatePKCEChallenge,
supportsLocalStorage,
parseParametersFromURL,
getCodeChallengeAndMethod,
} from './lib/helpers'
import { localStorageAdapter, memoryLocalStorageAdapter } from './lib/local-storage'
import { polyfillGlobalThis } from './lib/polyfills'
Expand Down Expand Up @@ -416,10 +415,10 @@ export default class GoTrueClient {
let codeChallenge: string | null = null
let codeChallengeMethod: string | null = null
if (this.flowType === 'pkce') {
const codeVerifier = generatePKCEVerifier()
await setItemAsync(this.storage, `${this.storageKey}-code-verifier`, codeVerifier)
codeChallenge = await generatePKCEChallenge(codeVerifier)
codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'
[codeChallenge, codeChallengeMethod] = await getCodeChallengeAndMethod(
this.storage,
this.storageKey
)
}
res = await _request(this.fetch, 'POST', `${this.url}/signup`, {
headers: this.headers,
Expand Down Expand Up @@ -680,10 +679,10 @@ export default class GoTrueClient {
let codeChallenge: string | null = null
let codeChallengeMethod: string | null = null
if (this.flowType === 'pkce') {
const codeVerifier = generatePKCEVerifier()
await setItemAsync(this.storage, `${this.storageKey}-code-verifier`, codeVerifier)
codeChallenge = await generatePKCEChallenge(codeVerifier)
codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'
[codeChallenge, codeChallengeMethod] = await getCodeChallengeAndMethod(
this.storage,
this.storageKey
)
}
const { error } = await _request(this.fetch, 'POST', `${this.url}/otp`, {
headers: this.headers,
Expand Down Expand Up @@ -798,10 +797,10 @@ export default class GoTrueClient {
let codeChallenge: string | null = null
let codeChallengeMethod: string | null = null
if (this.flowType === 'pkce') {
const codeVerifier = generatePKCEVerifier()
await setItemAsync(this.storage, `${this.storageKey}-code-verifier`, codeVerifier)
codeChallenge = await generatePKCEChallenge(codeVerifier)
codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'
[codeChallenge, codeChallengeMethod] = await getCodeChallengeAndMethod(
this.storage,
this.storageKey
)
}

return await _request(this.fetch, 'POST', `${this.url}/sso`, {
Expand Down Expand Up @@ -1244,10 +1243,10 @@ export default class GoTrueClient {
let codeChallenge: string | null = null
let codeChallengeMethod: string | null = null
if (this.flowType === 'pkce' && attributes.email != null) {
const codeVerifier = generatePKCEVerifier()
await setItemAsync(this.storage, `${this.storageKey}-code-verifier`, codeVerifier)
codeChallenge = await generatePKCEChallenge(codeVerifier)
codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'
[codeChallenge, codeChallengeMethod] = await getCodeChallengeAndMethod(
this.storage,
this.storageKey
)
}

const { data, error: userError } = await _request(this.fetch, 'PUT', `${this.url}/user`, {
Expand Down Expand Up @@ -1672,15 +1671,13 @@ export default class GoTrueClient {
> {
let codeChallenge: string | null = null
let codeChallengeMethod: string | null = null

if (this.flowType === 'pkce') {
const codeVerifier = generatePKCEVerifier()
await setItemAsync(
[codeChallenge, codeChallengeMethod] = await getCodeChallengeAndMethod(
this.storage,
`${this.storageKey}-code-verifier`,
`${codeVerifier}/PASSWORD_RECOVERY`
this.storageKey,
true // isPasswordRecovery
)
codeChallenge = await generatePKCEChallenge(codeVerifier)
codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'
}
try {
return await _request(this.fetch, 'POST', `${this.url}/recover`, {
Expand Down Expand Up @@ -2307,19 +2304,9 @@ export default class GoTrueClient {
urlParams.push(`scopes=${encodeURIComponent(options.scopes)}`)
}
if (this.flowType === 'pkce') {
const codeVerifier = generatePKCEVerifier()
await setItemAsync(this.storage, `${this.storageKey}-code-verifier`, codeVerifier)
const codeChallenge = await generatePKCEChallenge(codeVerifier)
const codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'

this._debug(
'PKCE',
'code verifier',
`${codeVerifier.substring(0, 5)}...`,
'code challenge',
codeChallenge,
'method',
codeChallengeMethod
const [codeChallenge, codeChallengeMethod] = await getCodeChallengeAndMethod(
this.storage,
this.storageKey
)

const flowParams = new URLSearchParams({
Expand Down
16 changes: 16 additions & 0 deletions src/lib/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,19 @@ export async function generatePKCEChallenge(verifier: string) {
const hashed = await sha256(verifier)
return base64urlencode(hashed)
}

export async function getCodeChallengeAndMethod(
storage: SupportedStorage,
storageKey: string,
isPasswordRecovery = false
) {
const codeVerifier = generatePKCEVerifier()
let storedCodeVerifier = codeVerifier
if (isPasswordRecovery) {
storedCodeVerifier += '/PASSWORD_RECOVERY'
}
await setItemAsync(storage, `${storageKey}-code-verifier`, storedCodeVerifier)
const codeChallenge = await generatePKCEChallenge(codeVerifier)
const codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'
return [codeChallenge, codeChallengeMethod]
}

0 comments on commit 860bffc

Please sign in to comment.