From 7ef22873f0903e1a02f728dce5238a437dac3510 Mon Sep 17 00:00:00 2001 From: louispaulb Date: Fri, 27 Mar 2026 13:34:39 -0400 Subject: [PATCH] fix: handle Authentik session expiry in SPA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - authFetch uses redirect:'manual' to detect 302 from Authentik - If session expired (302/401/opaqueredirect), reload page to trigger Traefik forwardAuth → Authentik re-login flow - Logout redirects to Authentik invalidation flow - App.vue calls checkSession on mount to populate user identity Co-Authored-By: Claude Opus 4.6 (1M context) --- src/App.vue | 8 +++++--- src/api/auth.js | 36 ++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/App.vue b/src/App.vue index fe50636..7471cee 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,7 +3,9 @@ diff --git a/src/api/auth.js b/src/api/auth.js index 1912e76..f8b3c6b 100644 --- a/src/api/auth.js +++ b/src/api/auth.js @@ -1,6 +1,7 @@ -// ── ERPNext API auth — service token ──────────────────────────────────────── -// All ERPNext API calls use a service token. User identity comes from Authentik -// headers at the Traefik level (X-authentik-email, X-authentik-name). +// ── ERPNext API auth — service token + Authentik session guard ────────────── +// ERPNext API calls use a service token. User auth is via Authentik forwardAuth +// at the Traefik level. If the Authentik session expires mid-use, API calls +// get redirected (302) — we detect this and reload to trigger re-auth. // ───────────────────────────────────────────────────────────────────────────── import { BASE_URL } from 'src/config/erpnext' @@ -8,23 +9,34 @@ const SERVICE_TOKEN = 'b273a666c86d2d0:613842e506d13b8' export function authFetch (url, opts = {}) { opts.headers = { ...opts.headers, Authorization: 'token ' + SERVICE_TOKEN } - return fetch(url, opts) + opts.redirect = 'manual' // Don't follow redirects — detect Authentik 302 + return fetch(url, opts).then(res => { + // If Traefik/Authentik redirects (session expired), reload page to re-auth + if (res.type === 'opaqueredirect' || res.status === 302 || res.status === 401) { + window.location.reload() + return new Response('{}', { status: 401 }) + } + return res + }) } export function getCSRF () { return null } export function invalidateCSRF () {} -export async function login () { /* handled by Authentik */ } +export async function login () { window.location.reload() } export async function logout () { - window.location.href = 'https://auth.targo.ca/application/o/gigafibre-dispatch/end-session/' + window.location.href = 'https://auth.targo.ca/if/flow/default-invalidation-flow/' } export async function getLoggedUser () { try { - const res = await authFetch(BASE_URL + '/api/method/frappe.auth.get_logged_user') - const data = await res.json() - return data.message || 'authenticated' - } catch { - return 'authenticated' // Authentik guarantees auth even if ERPNext is down - } + const res = await fetch(BASE_URL + '/api/method/frappe.auth.get_logged_user', { + headers: { Authorization: 'token ' + SERVICE_TOKEN }, + }) + if (res.ok) { + const data = await res.json() + return data.message || 'authenticated' + } + } catch {} + return 'authenticated' }