diff --git a/.changeset/nine-pets-rhyme.md b/.changeset/nine-pets-rhyme.md new file mode 100644 index 00000000000..9c7d6fa174e --- /dev/null +++ b/.changeset/nine-pets-rhyme.md @@ -0,0 +1,5 @@ +--- +"@clerk/clerk-js": patch +--- + +Re-init window.Clerk options when `ClerkProvider` props change in `@clerk/clerk-react` diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 7c610a15d50..5cde53679bd 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -294,10 +294,7 @@ export class Clerk implements ClerkInterface { ); } - this.#options = { - ...defaultOptions, - ...options, - }; + this.#options = this.#initOptions(options); assertNoLegacyProp(this.#options); @@ -314,11 +311,6 @@ export class Clerk implements ClerkInterface { }); } - this.#options.allowedRedirectOrigins = createAllowedRedirectOrigins( - this.#options.allowedRedirectOrigins, - this.frontendApi, - ); - if (this.#options.standardBrowser) { this.#loaded = await this.#loadInStandardBrowser(); } else { @@ -1602,9 +1594,14 @@ export class Clerk implements ClerkInterface { this.#fapiClient.onAfterResponse(callback); }; - __unstable__updateProps = (props: any) => { - // The expect-error directive below is safe since `updateAppearanceProp` is only used - // in the v4 build. This will be removed when v4 becomes the main stable version + __unstable__updateProps = (_props: any) => { + // We need to re-init the options here in order to keep the options passed to ClerkProvider + // in sync with the state of clerk-js. If we don't init the options here again, the following scenario is possible: + // 1. User renders + // 2. clerk-js initializes propA with a default value + // 3. The customer update propB independently of propA and window.Clerk.updateProps is called + // 4. If we don't merge the new props with the current options, propA will be reset to undefined + const props = { ..._props, options: this.#initOptions({ ...this.#options, ..._props.options }) }; return this.#componentControls?.ensureMounted().then(controls => controls.updateProps(props)); }; @@ -1976,6 +1973,14 @@ export class Clerk implements ClerkInterface { return true; }; + #initOptions = (options?: ClerkOptions): ClerkOptions => { + return { + ...defaultOptions, + ...options, + allowedRedirectOrigins: createAllowedRedirectOrigins(options?.allowedRedirectOrigins, this.frontendApi), + }; + }; + /** * The handshake payload is transported in the URL in development. In cases where FAPI is returning the handshake payload, but Clerk is being used in a client-only application, * we remove the handshake associated parameters as they are not necessary.