UNPKG

@auth/sveltekit

Version:

Authentication for SvelteKit.

149 lines (124 loc) 4.47 kB
import { redirect } from "@sveltejs/kit" import type { RequestEvent } from "@sveltejs/kit" import { parse } from "set-cookie-parser" import { env } from "$env/dynamic/private" import { Auth, createActionURL, raw } from "@auth/core" import type { ProviderType } from "@auth/core/providers" import type { SvelteKitAuthConfig } from "./types" import { setEnvDefaults } from "./env" type SignInParams = Parameters<App.Locals["signIn"]> export async function signIn( provider: SignInParams[0], options: SignInParams[1] = {}, authorizationParams: SignInParams[2], config: SvelteKitAuthConfig, event: RequestEvent ) { const { request, url: { protocol }, } = event const headers = new Headers(request.headers) const { redirect: shouldRedirect = true, redirectTo, ...rest } = options instanceof FormData ? Object.fromEntries(options) : options const callbackUrl = redirectTo?.toString() ?? headers.get("Referer") ?? "/" const signInURL = createActionURL("signin", protocol, headers, env, config) if (!provider) { signInURL.searchParams.append("callbackUrl", callbackUrl) if (shouldRedirect) redirect(302, signInURL.toString()) return signInURL.toString() } let url = `${signInURL}/${provider}?${new URLSearchParams(authorizationParams)}` let foundProvider: { id?: SignInParams[0]; type?: ProviderType } = {} for (const providerConfig of config.providers) { const { options, ...defaults } = typeof providerConfig === "function" ? providerConfig() : providerConfig const id = (options?.id as string | undefined) ?? defaults.id if (id === provider) { foundProvider = { id, type: (options?.type as ProviderType | undefined) ?? defaults.type, } break } } if (!foundProvider.id) { const url = `${signInURL}?${new URLSearchParams({ callbackUrl })}` if (shouldRedirect) redirect(302, url) return url } if (foundProvider.type === "credentials") { url = url.replace("signin", "callback") } headers.set("Content-Type", "application/x-www-form-urlencoded") const body = new URLSearchParams({ ...rest, callbackUrl }) const req = new Request(url, { method: "POST", headers, body }) const res = await Auth(req, { ...config, raw }) for (const c of res?.cookies ?? []) { event.cookies.set(c.name, c.value, { path: "/", ...c.options }) } if (shouldRedirect) { return redirect(302, res.redirect!) } // eslint-disable-next-line @typescript-eslint/no-explicit-any return res.redirect as any } type SignOutParams = Parameters<App.Locals["signOut"]> export async function signOut( options: SignOutParams[0], config: SvelteKitAuthConfig, event: RequestEvent ) { const { request, url: { protocol }, } = event const headers = new Headers(request.headers) headers.set("Content-Type", "application/x-www-form-urlencoded") const url = createActionURL("signout", protocol, headers, env, config) const callbackUrl = options?.redirectTo ?? headers.get("Referer") ?? "/" const body = new URLSearchParams({ callbackUrl }) const req = new Request(url, { method: "POST", headers, body }) const res = await Auth(req, { ...config, raw }) for (const c of res?.cookies ?? []) event.cookies.set(c.name, c.value, { path: "/", ...c.options }) if (options?.redirect ?? true) return redirect(302, res.redirect!) // eslint-disable-next-line @typescript-eslint/no-explicit-any return res as any } export async function auth( event: RequestEvent, config: SvelteKitAuthConfig ): ReturnType<App.Locals["auth"]> { setEnvDefaults(env, config) config.trustHost ??= true const { request: req, url: { protocol }, } = event const sessionUrl = createActionURL( "session", protocol, req.headers, env, config ) const request = new Request(sessionUrl, { headers: { cookie: req.headers.get("cookie") ?? "" }, }) const response = await Auth(request, config) const authCookies = parse(response.headers.getSetCookie()) for (const cookie of authCookies) { const { name, value, ...options } = cookie // @ts-expect-error - Review: SvelteKit and set-cookie-parser are mismatching event.cookies.set(name, value, { path: "/", ...options }) } const { status = 200 } = response const data = await response.json() if (!data || !Object.keys(data).length) return null if (status === 200) return data throw new Error(data.message) }