diff --git a/lib/sessionManager/stores/expoSecureStore.ts b/lib/sessionManager/stores/expoSecureStore.ts index b387ab5..958b0e2 100644 --- a/lib/sessionManager/stores/expoSecureStore.ts +++ b/lib/sessionManager/stores/expoSecureStore.ts @@ -4,6 +4,14 @@ import { splitString } from "../utils.js"; let expoSecureStore: typeof import("expo-secure-store") | undefined = undefined; +async function waitForExpoSecureStore() { + let tries = 0; + while (!expoSecureStore && tries < 20) { + await new Promise((resolve) => setTimeout(resolve, 100)); + tries++; + } +} + /** * Provides a expo local store based session manager implementation for the browser. * @class ExpoSecureStore @@ -42,6 +50,7 @@ export class ExpoSecureStore implements SessionManager { itemKey: V | StorageKeys, itemValue: unknown, ): Promise { + await waitForExpoSecureStore(); // clear items first await this.removeSessionItem(itemKey); @@ -66,6 +75,8 @@ export class ExpoSecureStore implements SessionManager { * @returns {unknown | null} */ async getSessionItem(itemKey: V | StorageKeys): Promise { + await waitForExpoSecureStore(); + const chunks = []; let index = 0; @@ -82,7 +93,7 @@ export class ExpoSecureStore implements SessionManager { ); } - return chunks.join(""); + return chunks.join("") || null; } /** @@ -91,6 +102,8 @@ export class ExpoSecureStore implements SessionManager { * @returns {void} */ async removeSessionItem(itemKey: V | StorageKeys): Promise { + await waitForExpoSecureStore(); + let index = 0; let chunk = await expoSecureStore!.getItemAsync( diff --git a/lib/types.ts b/lib/types.ts index cb177a2..8904ff0 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -105,6 +105,10 @@ export type LoginOptions = { * Whether to show the success screen at the end of the flow, this is most useful when the callback is not a webpage. */ hasSuccessPage?: boolean; + /** + * Single use code to prevent replay attacks + */ + nonce?: string; }; export enum IssuerRouteTypes { diff --git a/lib/utils/generateAuthUrl.ts b/lib/utils/generateAuthUrl.ts index 257f5b2..4308709 100644 --- a/lib/utils/generateAuthUrl.ts +++ b/lib/utils/generateAuthUrl.ts @@ -22,11 +22,15 @@ export const generateAuthUrl = ( ...mapLoginMethodParamsForUrl(options), }; - const generatedState = generateRandomString(32); - const generatedNonce = generateRandomString(16); + if (!options.state) { + options.state = generateRandomString(32); + } + searchParams["state"] = options.state; - searchParams["state"] = options.state || generatedState; - searchParams["nonce"] = generatedNonce; + if (!options.nonce) { + options.nonce = generateRandomString(16); + } + searchParams["nonce"] = options.nonce; if (options.codeChallenge) { searchParams["code_challenge"] = options.codeChallenge; @@ -38,5 +42,9 @@ export const generateAuthUrl = ( } authUrl.search = new URLSearchParams(searchParams).toString(); - return { url: authUrl, state: generatedState, nonce: generatedNonce }; + return { + url: authUrl, + state: searchParams["state"], + nonce: searchParams["nonce"], + }; }; diff --git a/lib/utils/generateRandomString.ts b/lib/utils/generateRandomString.ts index 1d61668..183a4eb 100644 --- a/lib/utils/generateRandomString.ts +++ b/lib/utils/generateRandomString.ts @@ -4,11 +4,28 @@ * @returns {string} required secret */ export const generateRandomString = (length: number = 28): string => { - const arr = new Uint8Array(length / 2); - crypto.getRandomValues(arr); - return Array.from(arr, dec2hex).join(""); + if (crypto) { + const arr = new Uint8Array(length / 2); + crypto.getRandomValues(arr); + return Array.from(arr, dec2hex).join(""); + } else { + return generateRandomStringNonCrypto(length); + } }; function dec2hex(dec: number) { return dec.toString(16).padStart(2, "0"); } + +function generateRandomStringNonCrypto(length: number = 28) { + const characters = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + let result = ""; + const charactersLength = characters.length; + + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + + return result; +}