···49 // Give it time for cookies to be properly set
50 if (query.isError && !query.isLoading && pathname !== '/') {
51 // Add a small delay for Safari iOS cookie handling
52- const isSafariIOS =
53- /iPad|iPhone|iPod/.test(navigator.userAgent) &&
54- /Safari/.test(navigator.userAgent) &&
55- !/Chrome/.test(navigator.userAgent);
56-57 if (isSafariIOS) {
58 setTimeout(() => {
59 // Re-check auth status before logging out
···62 logout();
63 }
64 });
65- }, 2000); // Increase to 2 seconds for PWA context
66 } else {
67 logout();
68 }
···49 // Give it time for cookies to be properly set
50 if (query.isError && !query.isLoading && pathname !== '/') {
51 // Add a small delay for Safari iOS cookie handling
52+ const isSafariIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) &&
53+ /Safari/.test(navigator.userAgent) &&
54+ !/Chrome/.test(navigator.userAgent);
55+056 if (isSafariIOS) {
57 setTimeout(() => {
58 // Re-check auth status before logging out
···61 logout();
62 }
63 });
64+ }, 1000);
65 } else {
66 logout();
67 }
-4
src/webapp/lib/auth/dal.ts
···1import type { GetProfileResponse } from '@/api-client/ApiClient';
2import { cache } from 'react';
3-import { isPWA } from './pwa-cookie-handler';
45const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://127.0.0.1:4000';
6···21 const response = await fetch(`${appUrl}/api/auth/me`, {
22 method: 'GET',
23 credentials: 'include', // HttpOnly cookies sent automatically
24- headers: {
25- 'X-PWA-Context': isPWA() ? 'true' : 'false',
26- },
27 });
2829 if (!response.ok) {
···1import type { GetProfileResponse } from '@/api-client/ApiClient';
2import { cache } from 'react';
034const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://127.0.0.1:4000';
5···20 const response = await fetch(`${appUrl}/api/auth/me`, {
21 method: 'GET',
22 credentials: 'include', // HttpOnly cookies sent automatically
00023 });
2425 if (!response.ok) {
-33
src/webapp/lib/auth/pwa-cookie-handler.ts
···1-export const isPWA = () => {
2- if (typeof window === 'undefined') return false;
3-4- return (
5- window.matchMedia('(display-mode: standalone)').matches ||
6- (window.navigator as any).standalone === true
7- );
8-};
9-10-export const setCookieForPWA = (
11- name: string,
12- value: string,
13- days: number = 7,
14-) => {
15- if (isPWA()) {
16- const expires = new Date();
17- expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
18- document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/;secure;samesite=lax`;
19- }
20-};
21-22-export const getCookieForPWA = (name: string): string | null => {
23- if (isPWA()) {
24- const nameEQ = name + '=';
25- const ca = document.cookie.split(';');
26- for (let i = 0; i < ca.length; i++) {
27- let c = ca[i];
28- while (c.charAt(0) === ' ') c = c.substring(1, c.length);
29- if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
30- }
31- }
32- return null;
33-};