fix: safari cookie issue
This commit is contained in:
@@ -44,6 +44,13 @@ export const api = createTRPCProxyClient<AppRouter>({
|
|||||||
headers: () => {
|
headers: () => {
|
||||||
const csrfToken = getCSRFToken();
|
const csrfToken = getCSRFToken();
|
||||||
return csrfToken ? { "x-csrf-token": csrfToken } : {};
|
return csrfToken ? { "x-csrf-token": csrfToken } : {};
|
||||||
|
},
|
||||||
|
// CRITICAL FOR SAFARI: Ensure cookies are sent and received
|
||||||
|
fetch(url, options) {
|
||||||
|
return fetch(url, {
|
||||||
|
...options,
|
||||||
|
credentials: "include" // Safari requires this for cookie handling
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class TokenRefreshManager {
|
|||||||
private onlineHandler: (() => void) | null = null;
|
private onlineHandler: (() => void) | null = null;
|
||||||
private focusHandler: (() => void) | null = null;
|
private focusHandler: (() => void) | null = null;
|
||||||
private lastRefreshTime: number | null = null;
|
private lastRefreshTime: number | null = null;
|
||||||
|
private lastCheckTime: number = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start monitoring and auto-refresh
|
* Start monitoring and auto-refresh
|
||||||
@@ -73,7 +74,18 @@ class TokenRefreshManager {
|
|||||||
window.addEventListener("online", this.onlineHandler);
|
window.addEventListener("online", this.onlineHandler);
|
||||||
|
|
||||||
// Re-check on window focus (device was asleep or user switched apps)
|
// Re-check on window focus (device was asleep or user switched apps)
|
||||||
|
// Debounce to prevent Safari from firing this too frequently
|
||||||
this.focusHandler = () => {
|
this.focusHandler = () => {
|
||||||
|
const now = Date.now();
|
||||||
|
const timeSinceLastCheck = now - this.lastCheckTime;
|
||||||
|
|
||||||
|
// Debounce: only check if last check was >1s ago (prevents Safari spam)
|
||||||
|
if (timeSinceLastCheck < 1000) {
|
||||||
|
console.log("[Token Refresh] Window focused but debouncing (Safari)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastCheckTime = now;
|
||||||
console.log("[Token Refresh] Window focused, checking token status");
|
console.log("[Token Refresh] Window focused, checking token status");
|
||||||
this.checkAndRefreshIfNeeded();
|
this.checkAndRefreshIfNeeded();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1660,17 +1660,33 @@ export const authRouter = createTRPCRouter({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4: Refresh CSRF token
|
// Step 4: Force response headers to be sent immediately
|
||||||
|
// This is critical for Safari to receive the new session cookies
|
||||||
|
// Safari is very strict about cookie updates from fetch responses
|
||||||
|
try {
|
||||||
|
const headers = event.node?.res?.getHeaders?.() || {};
|
||||||
|
console.log(
|
||||||
|
"[Token Refresh] Response headers set:",
|
||||||
|
Object.keys(headers)
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// Headers already sent or not available - that's OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: Refresh CSRF token
|
||||||
setCSRFToken(event);
|
setCSRFToken(event);
|
||||||
|
|
||||||
// Step 5: Opportunistic cleanup (serverless-friendly)
|
// Step 6: Opportunistic cleanup (serverless-friendly)
|
||||||
import("~/server/token-cleanup")
|
import("~/server/token-cleanup")
|
||||||
.then((module) => module.opportunisticCleanup())
|
.then((module) => module.opportunisticCleanup())
|
||||||
.catch((err) => console.error("Opportunistic cleanup failed:", err));
|
.catch((err) => console.error("Opportunistic cleanup failed:", err));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "Token refreshed successfully"
|
message: "Token refreshed successfully",
|
||||||
|
// Return new session ID for Safari fallback
|
||||||
|
// If Safari doesn't apply cookies, client can use this to restore
|
||||||
|
sessionId: newSession.sessionId
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Token refresh error:", error);
|
console.error("Token refresh error:", error);
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ export async function createAuthSession(
|
|||||||
// Explicitly seal/flush the session to ensure cookie is written
|
// Explicitly seal/flush the session to ensure cookie is written
|
||||||
// This is important in serverless environments where response might stream early
|
// This is important in serverless environments where response might stream early
|
||||||
const { sealSession } = await import("vinxi/http");
|
const { sealSession } = await import("vinxi/http");
|
||||||
sealSession(event, configWithMaxAge);
|
await sealSession(event, configWithMaxAge);
|
||||||
|
|
||||||
console.log("[Session Create] Session sealed");
|
console.log("[Session Create] Session sealed");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user