Skip to content

Commit 252dae0

Browse files
committed
attempt to fix cleanup db
1 parent 3543feb commit 252dae0

File tree

3 files changed

+62
-27
lines changed

3 files changed

+62
-27
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "integrate-sdk",
3-
"version": "0.8.26",
3+
"version": "0.8.27",
44
"description": "Type-safe 3rd party integration SDK for the Integrate MCP server",
55
"type": "module",
66
"main": "./dist/index.js",

src/oauth/manager.ts

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -687,14 +687,10 @@ export class OAuthManager {
687687
* and sessionStorage is isolated per tab. localStorage is shared across tabs.
688688
* Keyed by state parameter for security and retrieval.
689689
*
690-
* Skipped when using server-side database storage (skipLocalStorage is enabled)
690+
* Note: Pending auths are always stored in localStorage regardless of skipLocalStorage,
691+
* as they are temporary OAuth state needed for the flow, not permanent token storage.
691692
*/
692693
private savePendingAuthToStorage(state: string, pendingAuth: PendingAuth): void {
693-
// Skip localStorage if using server-side database storage
694-
if (this.skipLocalStorage) {
695-
return;
696-
}
697-
698694
if (typeof window !== 'undefined' && window.localStorage) {
699695
try {
700696
const key = `integrate_oauth_pending_${state}`;
@@ -709,14 +705,10 @@ export class OAuthManager {
709705
* Load pending auth from localStorage (after redirect)
710706
* Returns undefined if not found or invalid
711707
*
712-
* Skipped when using server-side database storage (skipLocalStorage is enabled)
708+
* Note: Pending auths are always loaded from localStorage regardless of skipLocalStorage,
709+
* as they are temporary OAuth state needed for the flow, not permanent token storage.
713710
*/
714711
private loadPendingAuthFromStorage(state: string): PendingAuth | undefined {
715-
// Skip localStorage if using server-side database storage
716-
if (this.skipLocalStorage) {
717-
return undefined;
718-
}
719-
720712
if (typeof window !== 'undefined' && window.localStorage) {
721713
try {
722714
const key = `integrate_oauth_pending_${state}`;
@@ -734,14 +726,10 @@ export class OAuthManager {
734726
/**
735727
* Remove pending auth from localStorage
736728
*
737-
* Skipped when using server-side database storage (skipLocalStorage is enabled)
729+
* Note: Pending auths are always removed from localStorage regardless of skipLocalStorage,
730+
* as they are temporary OAuth state that should be cleaned up after the flow completes.
738731
*/
739732
private removePendingAuthFromStorage(state: string): void {
740-
// Skip localStorage if using server-side database storage
741-
if (this.skipLocalStorage) {
742-
return;
743-
}
744-
745733
if (typeof window !== 'undefined' && window.localStorage) {
746734
try {
747735
const key = `integrate_oauth_pending_${state}`;
@@ -756,14 +744,10 @@ export class OAuthManager {
756744
* Clean up expired pending auth entries from localStorage
757745
* Removes any entries older than 5 minutes
758746
*
759-
* Skipped when using server-side database storage (skipLocalStorage is enabled)
747+
* Note: Pending auths are always cleaned up from localStorage regardless of skipLocalStorage,
748+
* as they are temporary OAuth state that should be removed when expired.
760749
*/
761750
private cleanupExpiredPendingAuths(): void {
762-
// Skip localStorage if using server-side database storage
763-
if (this.skipLocalStorage) {
764-
return;
765-
}
766-
767751
if (typeof window !== 'undefined' && window.localStorage) {
768752
try {
769753
const prefix = 'integrate_oauth_pending_';

tests/oauth/automatic-skip-localstorage.test.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ describe("Automatic skipLocalStorage Detection", () => {
311311
describe("Combined scenarios", () => {
312312
test("client-side: tokens persist in localStorage across page reloads", async () => {
313313
const manager1 = new OAuthManager("/api/integrate/oauth");
314-
314+
315315
const tokenData: ProviderTokenData = {
316316
accessToken: "persistent-token",
317317
tokenType: "Bearer",
@@ -414,7 +414,7 @@ describe("Automatic skipLocalStorage Detection", () => {
414414

415415
// Should call removeProviderToken callback
416416
expect(removeTokenMock).toHaveBeenCalledWith("github", undefined);
417-
417+
418418
// Should be removed from database
419419
expect(dbTokens["github"]).toBeUndefined();
420420

@@ -492,6 +492,57 @@ describe("Automatic skipLocalStorage Detection", () => {
492492
const allTokens = manager.getAllProviderTokens();
493493
expect(allTokens.get("github")).toEqual(newToken);
494494
});
495+
496+
test("pending auths are always cleaned up even with database callbacks", async () => {
497+
const setTokenMock = mock(async (provider: string, tokenData: ProviderTokenData) => {
498+
// Simulate database save
499+
});
500+
501+
const manager = new OAuthManager(
502+
"/api/integrate/oauth",
503+
undefined,
504+
undefined,
505+
{
506+
setProviderToken: setTokenMock,
507+
}
508+
);
509+
510+
// Simulate OAuth flow: create pending auth
511+
const state = "test-state-123";
512+
const pendingAuth = {
513+
provider: "github",
514+
state,
515+
codeVerifier: "verifier",
516+
codeChallenge: "challenge",
517+
redirectUri: "http://localhost/callback",
518+
returnUrl: undefined,
519+
initiatedAt: Date.now(),
520+
};
521+
522+
// Save pending auth to memory and localStorage (simulating initiateFlow)
523+
(manager as any).pendingAuths.set(state, pendingAuth);
524+
const pendingKey = `integrate_oauth_pending_${state}`;
525+
mockLocalStorage.set(pendingKey, JSON.stringify(pendingAuth));
526+
expect(mockLocalStorage.has(pendingKey)).toBe(true);
527+
528+
// Simulate callback completion with token (backend redirect flow)
529+
const tokenData: ProviderTokenData = {
530+
accessToken: "db-token",
531+
tokenType: "Bearer",
532+
expiresIn: 3600,
533+
};
534+
535+
await manager.handleCallbackWithToken("code", state, { ...tokenData, provider: "github" });
536+
537+
// Pending auth should be removed from localStorage even though we're using database for tokens
538+
expect(mockLocalStorage.has(pendingKey)).toBe(false);
539+
540+
// Token should NOT be in localStorage (goes to database instead)
541+
expect(mockLocalStorage.has("integrate_token_github")).toBe(false);
542+
543+
// But token should be saved via callback
544+
expect(setTokenMock).toHaveBeenCalledWith("github", tokenData, undefined);
545+
});
495546
});
496547
});
497548

0 commit comments

Comments
 (0)