diff --git a/frontend/src/components/RestrictedAuth.vue b/frontend/src/components/RestrictedAuth.vue index 76d16a7..21bdc16 100644 --- a/frontend/src/components/RestrictedAuth.vue +++ b/frontend/src/components/RestrictedAuth.vue @@ -44,7 +44,7 @@ import { computed, onMounted, reactive, ref } from 'vue' import passkey from '@/utils/passkey' import { getSettings } from '@/utils/settings' -import { apiJson, getUserFriendlyErrorMessage } from '@/utils/api' +import { fetchJson, getUserFriendlyErrorMessage } from '@/utils/api' const props = defineProps({ mode: { @@ -121,7 +121,7 @@ async function fetchSettings() { async function fetchUserInfo() { try { - userInfo.value = await apiJson('/auth/api/user-info', { method: 'POST' }) + userInfo.value = await fetchJson('/auth/api/user-info', { method: 'POST' }) // Determine view based on authentication status if (isAuthenticated.value && props.mode !== 'reauth') { currentView.value = 'forbidden' @@ -168,7 +168,7 @@ async function logoutUser() { if (loading.value) return loading.value = true try { - await apiJson('/auth/api/logout', { method: 'POST' }) + await fetchJson('/auth/api/logout', { method: 'POST' }) userInfo.value = null // Switch to login view after logout currentView.value = 'login' @@ -191,7 +191,7 @@ async function setSessionCookie(result) { console.error('setSessionCookie called with missing session_token:', result) throw new Error('Authentication response missing session_token') } - return await apiJson('/auth/api/set-session', { + return await fetchJson('/auth/api/set-session', { method: 'POST', headers: { Authorization: `Bearer ${result.session_token}` } }) } diff --git a/frontend/src/utils/api.js b/frontend/src/utils/api.js index 77db61f..80cee99 100644 --- a/frontend/src/utils/api.js +++ b/frontend/src/utils/api.js @@ -280,6 +280,36 @@ export async function apiJson(url, options = {}) { return data } +/** + * Simple JSON fetch without auto-auth iframe handling. + * Use this in contexts where showing an auth iframe would be inappropriate + * (e.g., inside the auth iframe itself). + * + * @param {string|URL} url - The URL to fetch + * @param {RequestInit} [options] - Fetch options + * @returns {Promise} - Parsed JSON response + * @throws {ApiError} - If response is not ok + */ +export async function fetchJson(url, options = {}) { + const fetchOptions = { + credentials: 'include', + ...options, + headers: { + 'Accept': 'application/json', + ...options.headers, + }, + } + + const response = await fetch(url, fetchOptions) + const data = await response.json() + + if (!response.ok) { + throw new ApiError(url, response, data) + } + + return data +} + /** * Convert an error to a user-friendly message. * @param {Error} error - The error to convert