sync fix - fallback MSAL
This commit is contained in:
parent
a88b2ea93e
commit
a62ada936d
|
|
@ -47,6 +47,8 @@ UI in Settings → "Browser-Authentifizierung" section.
|
|||
|
||||
Use case: avoids MSAL silent refresh failures (Azure AD returning HTTP 400 on refresh token).
|
||||
|
||||
**401 auto-invalidation:** `authFetch` in `apiClient.ts` detects 401 responses when a browser key was used and calls `setBrowserApiKey(null)` — clears `localStorage` and the store. `isAuthenticated` becomes `false`, restoring the MSAL login UI. Prevents the stuck state where a revoked/expired key blocks both sync and manual login.
|
||||
|
||||
## Deploy
|
||||
|
||||
`deploy.ps1` uses normal `docker build` with layer caching. Only changed layers are pushed to ACR.
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1.1.59
|
||||
1.1.62
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
import { getAccessToken } from './authStore.js';
|
||||
import { getAccessToken, handleUnauthorized } from './authStore.js';
|
||||
|
||||
export async function authFetch(url: string, options: RequestInit = {}): Promise<Response> {
|
||||
const token = await getAccessToken();
|
||||
const headers = new Headers(options.headers);
|
||||
headers.set('Authorization', `Bearer ${token}`);
|
||||
return fetch(url, { ...options, headers });
|
||||
const response = await fetch(url, { ...options, headers });
|
||||
if (response.status === 401) handleUnauthorized();
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,14 @@ export function setBrowserApiKey(key: string | null): void {
|
|||
browserApiKey.set(key);
|
||||
}
|
||||
|
||||
// Call after a 401 response to clear a stale browser key and restore MSAL login UI.
|
||||
export function handleUnauthorized(): void {
|
||||
if (get(browserApiKey) !== null) {
|
||||
console.warn('[auth] 401 received — clearing browser API key to allow MSAL fallback');
|
||||
setBrowserApiKey(null);
|
||||
}
|
||||
}
|
||||
|
||||
const DEV_ACCOUNT = {
|
||||
homeAccountId: 'dev-user',
|
||||
environment: 'localhost',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { writable } from 'svelte/store';
|
||||
import { getAccessToken } from '$lib/auth/authStore';
|
||||
import { getAccessToken, handleUnauthorized } from '$lib/auth/authStore';
|
||||
|
||||
export type AiLockStatus = { locked: false } | { locked: true; lockedAt: string; expiresAt: string };
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ const API_BASE = import.meta.env.VITE_API_URL ?? '';
|
|||
|
||||
async function apiFetch(path: string, init: RequestInit = {}): Promise<Response> {
|
||||
const token = await getAccessToken();
|
||||
return fetch(`${API_BASE}${path}`, {
|
||||
const res = await fetch(`${API_BASE}${path}`, {
|
||||
...init,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
@ -17,6 +17,8 @@ async function apiFetch(path: string, init: RequestInit = {}): Promise<Response>
|
|||
...(init.headers ?? {}),
|
||||
},
|
||||
});
|
||||
if (res.status === 401) handleUnauthorized();
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function refreshLockStatus(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { writable } from 'svelte/store';
|
||||
import { db } from '$lib/db/schema';
|
||||
import { getAccessToken } from '$lib/auth/authStore';
|
||||
import { getAccessToken, handleUnauthorized } from '$lib/auth/authStore';
|
||||
import { aiLockStatus } from '$lib/stores/aiLock';
|
||||
import type { SyncPushRequest, SyncPullResponse } from '@ka-note/shared';
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ async function apiFetch(path: string, init: RequestInit): Promise<Response> {
|
|||
const payload = JSON.parse(atob(token.split('.')[1]));
|
||||
console.log('[sync] token aud:', payload.aud, '| scp:', payload.scp, '| exp:', new Date(payload.exp * 1000).toISOString());
|
||||
} catch { /* ignore */ }
|
||||
return fetch(`${API_BASE}${path}`, {
|
||||
const res = await fetch(`${API_BASE}${path}`, {
|
||||
...init,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
@ -62,6 +62,8 @@ async function apiFetch(path: string, init: RequestInit): Promise<Response> {
|
|||
...(init.headers ?? {}),
|
||||
},
|
||||
});
|
||||
if (res.status === 401) handleUnauthorized();
|
||||
return res;
|
||||
}
|
||||
|
||||
async function pullAndMerge(since: Date | null): Promise<string> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue