Use musicSession cookie for auth

This commit is contained in:
lucast committed 2026-10-02 00:20:38 +02:00
1 parent e2c47e6d0f
commit e89463591c
8 files changed
+80 -104

No files matched your search

+14 -10
View File
@@ -6,7 +6,7 @@ export function useApiFetch<DataT = any, ErrorT = any>(
options?: UseFetchOptions<DataT, ErrorT>,
authorize: boolean = true,
): ReturnType<typeof useFetch<DataT, ErrorT>> {
const { sessionToken, refreshSessionToken } = useAuth()
const { refreshSession } = useAuth()
const defaults: UseFetchOptions<DataT, ErrorT> = {
// The migrated API lives in this Nuxt app under server/api.
@@ -16,19 +16,23 @@ export function useApiFetch<DataT = any, ErrorT = any>(
retryDelay: 0,
retryStatusCodes: [401],
headers:
authorize && sessionToken.value
? { Authorization: `Bearer ${sessionToken.value}` }
: {},
headers: {},
onResponseError: async ({ request, response, options }) => {
if (response.status == 401 && authorize) {
const newToken = await refreshSessionToken()
const refreshed = await refreshSession()
if (!newToken) return
if (!refreshed.ok) return
const headers = new Headers(options.headers as HeadersInit)
headers.set("Authorization", `Bearer ${newToken}`)
options.headers = headers
if (import.meta.server && refreshed.sessionCookie) {
const headers = new Headers(options.headers as HeadersInit)
const cookies = (headers.get("cookie") ?? "")
.split(";")
.map((cookie) => cookie.trim())
.filter((cookie) => cookie && !cookie.startsWith("musicSession="))
cookies.push(refreshed.sessionCookie)
headers.set("cookie", cookies.join("; "))
options.headers = headers
}
}
},
}
+31 -28
View File
@@ -1,17 +1,11 @@
import { appendResponseHeader } from "h3"
type SessionResponse = {
sessionToken: string
expireAt: string
}
type SessionRefresh = { ok: boolean; sessionCookie?: string }
const refreshPromises = new WeakMap<object, Promise<SessionRefresh>>()
export const useAuth = () => {
const sessionToken = useCookie<string | null>("sessionToken", {
sameSite: "lax",
maxAge: 60 * 60,
})
let refreshPromise: Promise<string | null> | null = null
const nuxtApp = useNuxtApp()
const authenticated = useState("auth:authenticated", () => false)
const signin = async (email: string, password: string, remember = false) => {
try {
@@ -20,7 +14,7 @@ export const useAuth = () => {
body: { email, password, remember: Boolean(remember) },
})
if (!(await refreshSessionToken())) throw new Error("Unable to create session")
if (!(await refreshSession()).ok) throw new Error("Unable to create session")
await navigateTo("/")
} catch (error: any) {
throw new Error(error?.data?.message || error?.statusMessage || "Failed to sign in")
@@ -34,7 +28,7 @@ export const useAuth = () => {
body: { name, email, password },
})
if (!(await refreshSessionToken())) throw new Error("Unable to create session")
if (!(await refreshSession()).ok) throw new Error("Unable to create session")
await navigateTo("/")
} catch (error: any) {
throw new Error(error?.data?.message || error?.statusMessage || "Failed to sign up")
@@ -45,55 +39,64 @@ export const useAuth = () => {
try {
await $fetch("/api/auth/signout", { method: "POST" })
} finally {
sessionToken.value = null
authenticated.value = false
}
}
const refreshSessionToken = async (): Promise<string | null> => {
if (refreshPromise) return refreshPromise
const refreshSession = async (): Promise<SessionRefresh> => {
const inFlight = refreshPromises.get(nuxtApp)
if (inFlight) return inFlight
refreshPromise = (async () => {
const response = await $fetch.raw<SessionResponse>(
const refreshPromise = (async () => {
const response = await $fetch.raw<{ expireAt: string }>(
"/api/auth/session",
{
method: "POST",
headers: import.meta.server
? useRequestHeaders(["cookie", "authorization"])
? useRequestHeaders(["cookie"])
: undefined,
},
)
let sessionCookie: string | undefined
const setCookies = import.meta.server ? response.headers.getSetCookie() : []
for (const cookie of setCookies) {
if (!cookie.startsWith("musicSession=")) continue
sessionCookie = cookie.split(";", 1)[0]
}
if (import.meta.server) {
const event = useRequestEvent()
if (event) {
for (const cookie of response.headers.getSetCookie()) {
for (const cookie of setCookies) {
appendResponseHeader(event, "set-cookie", cookie)
}
}
}
return response._data!
return { ok: true, sessionCookie }
})()
.then((response) => {
sessionToken.value = response.sessionToken
return response.sessionToken
.then((result) => {
authenticated.value = true
return result
})
.catch(() => {
sessionToken.value = null
return null
authenticated.value = false
return { ok: false }
})
.finally(() => {
refreshPromise = null
refreshPromises.delete(nuxtApp)
})
refreshPromises.set(nuxtApp, refreshPromise)
return refreshPromise
}
return {
sessionToken,
authenticated,
signin,
signup,
signout,
refreshSessionToken,
refreshSession,
}
}