From d109db2155ad6bdd1b4fd3b6721856105ba89f26 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Tue, 9 Dec 2025 19:23:11 -0500 Subject: [PATCH] [FA-misc] Fixes refresh token usage hopefully --- fictionarchive-web-astro/package-lock.json | 14 +++++++ fictionarchive-web-astro/package.json | 1 + .../src/lib/auth/authStore.ts | 11 ++++++ .../src/lib/auth/oidcConfig.ts | 4 +- .../src/lib/graphql/client.ts | 37 ++++++++++++++----- 5 files changed, 55 insertions(+), 12 deletions(-) diff --git a/fictionarchive-web-astro/package-lock.json b/fictionarchive-web-astro/package-lock.json index a103b37..620b683 100644 --- a/fictionarchive-web-astro/package-lock.json +++ b/fictionarchive-web-astro/package-lock.json @@ -12,6 +12,7 @@ "@astrojs/svelte": "^7.2.2", "@tailwindcss/vite": "^4.1.17", "@urql/core": "^6.0.1", + "@urql/exchange-auth": "^3.0.0", "@urql/svelte": "^5.0.0", "astro": "^5.16.2", "class-variance-authority": "^0.7.1", @@ -4304,6 +4305,19 @@ "wonka": "^6.3.2" } }, + "node_modules/@urql/exchange-auth": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@urql/exchange-auth/-/exchange-auth-3.0.0.tgz", + "integrity": "sha512-tj09xiOR2f1J2h8TE9uZWjRZipCdmDoTewEytOacDQ+0Teo+yIZxm3ppHxolQtiA51OHrGYiNTkMte8HtfvaBw==", + "license": "MIT", + "dependencies": { + "@urql/core": "^6.0.0", + "wonka": "^6.3.2" + }, + "peerDependencies": { + "@urql/core": "^6.0.0" + } + }, "node_modules/@urql/svelte": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-5.0.0.tgz", diff --git a/fictionarchive-web-astro/package.json b/fictionarchive-web-astro/package.json index 0a35c55..8a64bce 100644 --- a/fictionarchive-web-astro/package.json +++ b/fictionarchive-web-astro/package.json @@ -16,6 +16,7 @@ "@astrojs/svelte": "^7.2.2", "@tailwindcss/vite": "^4.1.17", "@urql/core": "^6.0.1", + "@urql/exchange-auth": "^3.0.0", "@urql/svelte": "^5.0.0", "astro": "^5.16.2", "class-variance-authority": "^0.7.1", diff --git a/fictionarchive-web-astro/src/lib/auth/authStore.ts b/fictionarchive-web-astro/src/lib/auth/authStore.ts index 238b0b5..862dedb 100644 --- a/fictionarchive-web-astro/src/lib/auth/authStore.ts +++ b/fictionarchive-web-astro/src/lib/auth/authStore.ts @@ -117,3 +117,14 @@ export async function logout() { user.set(null); } } + +export async function refreshToken(): Promise { + if (!userManager) return null; + try { + const newUser = await userManager.signinSilent(); + return newUser; + } catch (e) { + console.error('Token refresh failed:', e); + return null; + } +} diff --git a/fictionarchive-web-astro/src/lib/auth/oidcConfig.ts b/fictionarchive-web-astro/src/lib/auth/oidcConfig.ts index 17ae4cc..16faa3d 100644 --- a/fictionarchive-web-astro/src/lib/auth/oidcConfig.ts +++ b/fictionarchive-web-astro/src/lib/auth/oidcConfig.ts @@ -4,7 +4,7 @@ const authority = import.meta.env.PUBLIC_OIDC_AUTHORITY; const clientId = import.meta.env.PUBLIC_OIDC_CLIENT_ID; const redirectUri = import.meta.env.PUBLIC_OIDC_REDIRECT_URI; const postLogoutRedirectUri = import.meta.env.PUBLIC_OIDC_POST_LOGOUT_REDIRECT_URI ?? redirectUri; -const scope = import.meta.env.PUBLIC_OIDC_SCOPE ?? 'openid profile email'; +const scope = import.meta.env.PUBLIC_OIDC_SCOPE ?? 'openid profile email offline_access'; export const isOidcConfigured = Boolean(authority) && Boolean(clientId) && Boolean(redirectUri); @@ -20,7 +20,7 @@ function buildSettings(): UserManagerSettings | null { response_type: 'code', scope, loadUserInfo: true, - automaticSilentRenew: true, + automaticSilentRenew: false, // We handle refresh reactively via authExchange userStore: typeof window !== 'undefined' ? new WebStorageStateStore({ store: window.localStorage }) diff --git a/fictionarchive-web-astro/src/lib/graphql/client.ts b/fictionarchive-web-astro/src/lib/graphql/client.ts index 3ba35b5..abfed7c 100644 --- a/fictionarchive-web-astro/src/lib/graphql/client.ts +++ b/fictionarchive-web-astro/src/lib/graphql/client.ts @@ -1,19 +1,36 @@ import { Client, cacheExchange, fetchExchange } from '@urql/core'; +import { authExchange } from '@urql/exchange-auth'; import { get } from 'svelte/store'; -import { user } from '../auth/authStore'; +import { user, refreshToken } from '../auth/authStore'; export function createClient() { return new Client({ url: import.meta.env.PUBLIC_GRAPHQL_URI, - exchanges: [cacheExchange, fetchExchange], - fetchOptions: () => { - const currentUser = get(user); - return { - headers: currentUser?.access_token - ? { Authorization: `Bearer ${currentUser.access_token}` } - : {}, - }; - }, + exchanges: [ + cacheExchange, + authExchange(async (utils) => ({ + addAuthToOperation(operation) { + const currentUser = get(user); + if (!currentUser?.access_token) return operation; + return utils.appendHeaders(operation, { + Authorization: `Bearer ${currentUser.access_token}`, + }); + }, + didAuthError(error) { + return error.graphQLErrors?.some( + (e) => e.extensions?.code === 'AUTH_NOT_AUTHENTICATED' + ); + }, + async refreshAuth() { + const newUser = await refreshToken(); + if (!newUser) { + // Refresh failed, redirect to login + window.location.href = '/'; + } + }, + })), + fetchExchange, + ], }); } -- 2.49.1