Skip to content

Commit

Permalink
feat(sveltekit): Refresh session cookie expiry & introduce auth met…
Browse files Browse the repository at this point in the history
…hod (#9694)

* fix(kit): set cookies in getSession, introduce auth method

* Apply suggestions from code review

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Nico Domino <yo@ndo.dev>

* fix review comments

* Apply suggestions from code review

Co-authored-by: Balázs Orbán <info@balazsorban.com>

* Apply suggestions from code review

* fix build

---------

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Nico Domino <yo@ndo.dev>
  • Loading branch information
3 people committed Jan 20, 2024
1 parent a595ca7 commit cbf5ce8
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 200 deletions.
7 changes: 4 additions & 3 deletions apps/dev/sveltekit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
},
"devDependencies": {
"@sveltejs/adapter-auto": "next",
"@sveltejs/kit": "next",
"svelte": "3.55.0",
"@sveltejs/kit": "2.4.1",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"svelte": "^4",
"svelte-check": "2.10.2",
"typescript": "5.2.2",
"vite": "4.0.5"
"vite": "^5"
},
"dependencies": {
"@auth/sveltekit": "workspace:*"
Expand Down
2 changes: 1 addition & 1 deletion apps/dev/sveltekit/src/routes/+layout.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import type { LayoutServerLoad } from "./$types"

export const load: LayoutServerLoad = async (event) => {
return {
session: await event.locals.getSession(),
session: await event.locals.auth(),
}
}
2 changes: 1 addition & 1 deletion apps/dev/sveltekit/svelte.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import adapter from "@sveltejs/adapter-auto"
import { vitePreprocess } from "@sveltejs/kit/vite"
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"

/** @type {import('@sveltejs/kit').Config} */
const config = {
Expand Down
10 changes: 6 additions & 4 deletions packages/frameworks-sveltekit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,20 @@
"@sveltejs/kit": "^2.0.0",
"@sveltejs/package": "^1.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@types/set-cookie-parser": "^2.4.7",
"svelte": "^4.0.0",
"svelte-check": "^3.4.3",
"tslib": "^2.4.1",
"vite": "^5.0.0",
"vitest": "^1.0.0"
},
"dependencies": {
"@auth/core": "workspace:*"
"@auth/core": "workspace:*",
"set-cookie-parser": "^2.6.0"
},
"peerDependencies": {
"svelte": "^3.54.0 || ^4.0.0",
"@sveltejs/kit": "^1.0.0 || ^2.0.0"
"@sveltejs/kit": "^1.0.0 || ^2.0.0",
"svelte": "^3.54.0 || ^4.0.0 || ^5"
},
"type": "module",
"types": "./index.d.ts",
Expand Down Expand Up @@ -77,4 +79,4 @@
},
"./package.json": "./package.json"
}
}
}
72 changes: 45 additions & 27 deletions packages/frameworks-sveltekit/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
*
* When deploying your app outside Vercel, set the `AUTH_TRUST_HOST` variable to `true` for other hosting providers like Cloudflare Pages or Netlify.
*
* The callback URL used by the [providers](https://authjs.dev/getting-started/providers) must be set to the following, unless you override {@link SvelteKitAuthConfig.prefix}:
* The callback URL used by the [providers](https://authjs.dev/getting-started/providers) must be set to the following, unless you override {@link SvelteKitAuthConfig.basePath}:
* ```
* [origin]/auth/callback/[provider]
* ```
Expand Down Expand Up @@ -199,7 +199,7 @@

/// <reference types="@sveltejs/kit" />
import type { Handle, RequestEvent } from "@sveltejs/kit"

import { parse } from "set-cookie-parser"
import { dev, building } from "$app/environment"
import { base } from "$app/paths"
import { env } from "$env/dynamic/private"
Expand All @@ -215,18 +215,29 @@ export type {
User,
} from "@auth/core/types"

export async function getSession(
req: Request,
async function auth(
event: RequestEvent,
config: SvelteKitAuthConfig
): ReturnType<App.Locals["getSession"]> {
): ReturnType<App.Locals["auth"]> {
setEnvDefaults(env, config)
config.trustHost ??= true

const prefix = config.prefix ?? `${base}/auth`
const url = new URL(prefix + "/session", req.url)
const request = new Request(url, { headers: req.headers })
const { request: req } = event

const basePath = config.basePath ?? `${base}/auth`
const url = new URL(basePath + "/session", req.url)
const request = new Request(url, {
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()

Expand All @@ -236,16 +247,7 @@ export async function getSession(
}

/** Configure the {@link SvelteKitAuth} method. */
export interface SvelteKitAuthConfig extends Omit<AuthConfig, "raw"> {
/**
* Defines the base path for the auth routes.
* If you change the default value,
* you must also update the callback URL used by the [providers](https://authjs.dev/reference/core/providers).
*
* @default `${base}/auth` - `base` is the base path of your SvelteKit app, configured in `svelte.config.js`.
*/
prefix?: string
}
export interface SvelteKitAuthConfig extends Omit<AuthConfig, "raw"> {}

const actions: AuthAction[] = [
"providers",
Expand All @@ -270,28 +272,37 @@ export function SvelteKitAuth(
return async function ({ event, resolve }) {
const _config = typeof config === "object" ? config : await config(event)
setEnvDefaults(env, _config)
const { prefix = `${base}/auth` } = _config

const { url, request } = event

event.locals.getSession ??= () => getSession(request, _config)
event.locals.auth ??= () => auth(event, _config)
event.locals.getSession ??= event.locals.auth

const action = url.pathname
.slice(prefix.length + 1)
.split("/")[0] as AuthAction
.slice(
// @ts-expect-error - basePath is defined in setEnvDefaults
_config.basePath.length + 1
)
.split("/")[0]

if (!actions.includes(action) || !url.pathname.startsWith(prefix + "/")) {
return resolve(event)
if (isAction(action) && url.pathname.startsWith(_config.basePath + "/")) {
return Auth(request, _config)
}

return Auth(request, _config)
return resolve(event)
}
}

// TODO: Get this function from @auth/core/util
function isAction(action: string): action is AuthAction {
return actions.includes(action as AuthAction)
}

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace App {
interface Locals {
auth(): Promise<Session | null>
/** @deprecated Use `auth` instead. */
getSession(): Promise<Session | null>
}
interface PageData {
Expand All @@ -309,11 +320,18 @@ declare module "$env/dynamic/private" {
export function setEnvDefaults(envObject: any, config: SvelteKitAuthConfig) {
if (building) return

try {
const url = env.AUTH_URL
if (url) config.basePath = new URL(url).pathname
} catch {
} finally {
config.basePath ??= `${base}/auth`
}

config.redirectProxyUrl ??= env.AUTH_REDIRECT_PROXY_URL
config.secret ??= env.AUTH_SECRET
config.trustHost ??= !!(
env.AUTH_URL ??
env.NEXTAUTH_URL ??
env.AUTH_TRUST_HOST ??
env.VERCEL ??
env.NODE_ENV !== "production" ??
Expand Down
Loading

1 comment on commit cbf5ce8

@vercel
Copy link

@vercel vercel bot commented on cbf5ce8 Jan 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.