diff --git a/clients/web/src/test/core/auth/oauth-storage.test.ts b/clients/web/src/test/core/auth/oauth-storage.test.ts index 5caf2c90..91821244 100644 --- a/clients/web/src/test/core/auth/oauth-storage.test.ts +++ b/clients/web/src/test/core/auth/oauth-storage.test.ts @@ -172,6 +172,28 @@ describe("OAuthStorageBase — async hydration", () => { expect(await storage.getCodeVerifier(SERVER)).toBe("keep-me"); }); + it("clearClientInformation before hydration is deferred and clears only client info", async () => { + const { storage, release } = makeAsyncBackedStorage({ + [SERVER]: { + clientInformation: { client_id: "abc" }, + clientRegistrationKind: "dynamic", + tokens: { access_token: "t", token_type: "Bearer" }, + }, + }); + storage.clearClientInformation(SERVER); + release(); + await storage.ready(); + await Promise.resolve(); + // Client info cleared, but the sibling token from the persisted blob (and + // every other server's blob, in the whole-blob adapter) survives — proving + // the pre-hydration clear did not clobber on-disk state. + expect(await storage.getClientInformation(SERVER)).toBeUndefined(); + expect(await storage.getTokens(SERVER)).toEqual({ + access_token: "t", + token_type: "Bearer", + }); + }); + it("clear() after hydration does not schedule a deferred re-apply", async () => { const { storage, release } = makeAsyncBackedStorage({ [SERVER]: { tokens: { access_token: "t", token_type: "Bearer" } }, diff --git a/core/auth/oauth-storage.ts b/core/auth/oauth-storage.ts index 29707b1c..040e5a32 100644 --- a/core/auth/oauth-storage.ts +++ b/core/auth/oauth-storage.ts @@ -172,16 +172,16 @@ export class OAuthStorageBase implements OAuthStorage { } clearClientInformation(serverUrl: string, isPreregistered?: boolean): void { - const updates: Partial = {}; - - if (isPreregistered) { - updates.preregisteredClientInformation = undefined; - } else { - updates.clientInformation = undefined; - updates.clientRegistrationKind = undefined; - } - - this.store.getState().setServerState(serverUrl, updates); + this.clearAfterHydration(() => { + const updates: Partial = {}; + if (isPreregistered) { + updates.preregisteredClientInformation = undefined; + } else { + updates.clientInformation = undefined; + updates.clientRegistrationKind = undefined; + } + this.store.getState().setServerState(serverUrl, updates); + }); } async getTokens(serverUrl: string): Promise {