mirror of https://github.com/usememos/memos.git
fix(auth): recover session via refresh cookie when localStorage is empty (#5748)
This commit is contained in:
parent
be00abe852
commit
551ee1d81f
|
|
@ -61,11 +61,10 @@ export const getAccessToken = (): string | null => {
|
|||
accessToken = storedToken;
|
||||
tokenExpiresAt = expiresAt;
|
||||
}
|
||||
// Do NOT remove expired tokens here. Callers such as InstanceContext.initialize()
|
||||
// run concurrently with AuthContext.initialize() via Promise.all. If we eagerly
|
||||
// delete the expired token from localStorage, hasStoredToken() (called synchronously
|
||||
// inside AuthContext.initialize()) finds nothing and skips the refresh attempt,
|
||||
// logging the user out even when the refresh-token cookie is still valid.
|
||||
// Do NOT remove expired tokens here. getRequestToken() in connect.ts calls
|
||||
// hasStoredToken() to decide whether to attempt a refresh — if we eagerly delete
|
||||
// the expired token, it returns null immediately, skipping the refresh and sending
|
||||
// the request without credentials.
|
||||
// clearAccessToken() handles proper cleanup after a confirmed auth failure or logout.
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { createContext, type ReactNode, useCallback, useContext, useMemo, useState } from "react";
|
||||
import { clearAccessToken, hasStoredToken } from "@/auth-state";
|
||||
import { authServiceClient, shortcutServiceClient, userServiceClient } from "@/connect";
|
||||
import { clearAccessToken, getAccessToken } from "@/auth-state";
|
||||
import { authServiceClient, refreshAccessToken, shortcutServiceClient, userServiceClient } from "@/connect";
|
||||
import { userKeys } from "@/hooks/useUserQueries";
|
||||
import type { Shortcut } from "@/types/proto/api/v1/shortcut_service_pb";
|
||||
import type { User, UserSetting_GeneralSetting, UserSetting_WebhooksSetting } from "@/types/proto/api/v1/user_service_pb";
|
||||
|
|
@ -53,9 +53,21 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|||
const initialize = useCallback(async () => {
|
||||
setState((prev) => ({ ...prev, isLoading: true }));
|
||||
|
||||
// If there is no stored token at all, the user is not authenticated.
|
||||
// Skip the network call — there is nothing to refresh and no session to restore.
|
||||
if (!hasStoredToken()) {
|
||||
// Try to get or refresh the access token.
|
||||
// This handles PWA isolated storage scenarios (e.g., iOS Safari) where localStorage
|
||||
// may be empty but a valid HTTP-only refresh token cookie still exists.
|
||||
// getAccessToken() returns a cached token or loads from localStorage if valid.
|
||||
if (!getAccessToken()) {
|
||||
try {
|
||||
await refreshAccessToken();
|
||||
} catch {
|
||||
// Refresh failed - no valid session
|
||||
}
|
||||
}
|
||||
|
||||
// If we still don't have a token after refresh attempt, skip getCurrentUser call
|
||||
// to avoid unnecessary network request for unauthenticated users.
|
||||
if (!getAccessToken()) {
|
||||
setState({
|
||||
currentUser: undefined,
|
||||
userGeneralSetting: undefined,
|
||||
|
|
|
|||
Loading…
Reference in New Issue