Skip to content

Commit

Permalink
More idiomatic supabase auth following https://supabase.com/docs/guid…
Browse files Browse the repository at this point in the history
…es/auth/server-side/sveltekit

Differences:
 - only run the auth layout under /account and /login, want fast unauthed marketing pages with no JS
 - Be even more explicit in maing getSession safe by not calling it on the server at all
  • Loading branch information
scosman committed Aug 31, 2024
1 parent 574345d commit a1a7ba5
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 28 deletions.
2 changes: 2 additions & 0 deletions src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ declare global {
user: User | null
amr: AMREntry[] | null
}>
session: Session | null
user: User | null
}
interface PageData {
session: Session | null
Expand Down
22 changes: 21 additions & 1 deletion src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import {
import { createServerClient } from "@supabase/ssr"
import { createClient } from "@supabase/supabase-js"
import type { Handle } from "@sveltejs/kit"
import { sequence } from "@sveltejs/kit/hooks"
import { redirect } from "@sveltejs/kit"

export const handle: Handle = async ({ event, resolve }) => {
export const supabase: Handle = async ({ event, resolve }) => {
event.locals.supabase = createServerClient(
PUBLIC_SUPABASE_URL,
PUBLIC_SUPABASE_ANON_KEY,
Expand Down Expand Up @@ -82,3 +84,21 @@ export const handle: Handle = async ({ event, resolve }) => {
},
})
}

const authGuard: Handle = async ({ event, resolve }) => {
const { session, user } = await event.locals.safeGetSession()
event.locals.session = session
event.locals.user = user

if (!event.locals.session && event.url.pathname.startsWith("/account")) {
redirect(303, "/login")
}

if (event.locals.session && event.url.pathname === "/login") {
redirect(303, "/account")
}

return resolve(event)
}

export const handle: Handle = sequence(supabase, authGuard)
19 changes: 5 additions & 14 deletions src/routes/(admin)/account/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import { redirect } from "@sveltejs/kit"
import type { LayoutServerLoad } from "./$types"

export const load: LayoutServerLoad = async ({
locals: { supabase, safeGetSession },
locals: { session },
cookies,
}) => {
const { session, user } = await safeGetSession()

if (!session || !user?.id) {
redirect(303, "/login")
// Session here is from authGuard hook
return {
session,
cookies: cookies.getAll(),
}

const { data: profile } = await supabase
.from("profiles")
.select(`*`)
.eq("id", user.id)
.single()

return { session, user, profile, cookies: cookies.getAll() }
}
26 changes: 16 additions & 10 deletions src/routes/(admin)/account/+layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@ export const load = async ({ fetch, data, depends, url }) => {
},
})

/**
* Not always safe on server, but calling getUser next to verify JWT token
*/
const {
data: { session },
} = await supabase.auth.getSession()
// on server populated on server by LayoutData, using authGuard hook
let session = data.session
if (isBrowser()) {
// Only call getSession in browser where it's safe.
const getSessionResponse = await supabase.auth.getSession()
session = getSessionResponse.data.session
}
if (!session) {
redirect(303, "/login")
}

// https://github.com/supabase/auth-js/issues/888#issuecomment-2189298518
if ("suppressGetSessionWarning" in supabase.auth) {
Expand All @@ -53,14 +57,16 @@ export const load = async ({ fetch, data, depends, url }) => {
} = await supabase.auth.getUser()
if (userError || !user) {
// JWT validation has failed
console.log("User error", userError)
redirect(303, "/login")
}

const { data: aal } = await supabase.auth.mfa.getAuthenticatorAssuranceLevel()
const { data: profile } = await supabase
.from("profiles")
.select(`*`)
.eq("id", user.id)
.single()

const profile: Database["public"]["Tables"]["profiles"]["Row"] | null =
data.profile
const { data: aal } = await supabase.auth.mfa.getAuthenticatorAssuranceLevel()

const createProfilePath = "/account/create_profile"
const signOutPath = "/account/sign_out"
Expand Down
4 changes: 1 addition & 3 deletions src/routes/(marketing)/login/+layout.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ export const load: LayoutServerLoad = async ({
locals: { safeGetSession },
cookies,
}) => {
const { session } = await safeGetSession()

// if the user is already logged in return them to the account page
const { session } = await safeGetSession()
if (session) {
redirect(303, "/account")
}

return {
session: session,
url: url.origin,
cookies: cookies.getAll(),
}
Expand Down

0 comments on commit a1a7ba5

Please sign in to comment.