mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
3 Commits
@auth/soli
...
feat/svelt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42632c8894 | ||
|
|
c286b6fea7 | ||
|
|
d0fbea8027 |
@@ -1,12 +1,11 @@
|
||||
<script lang="ts">
|
||||
export let provider: any
|
||||
export let callbackUrl: string
|
||||
</script>
|
||||
|
||||
<form action={provider.signinUrl} method="POST">
|
||||
{#if provider.callbackUrl}
|
||||
<input type="hidden" name="callbackUrl" value={provider.callbackUrl} />
|
||||
{/if}
|
||||
<button type="submit" class="button">
|
||||
<input type="hidden" name="callbackUrl" value={callbackUrl} />
|
||||
<button type="submit">
|
||||
<slot>Sign in with {provider.name}</slot>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -3,5 +3,7 @@ import type { LayoutServerLoad } from "./$types"
|
||||
export const load: LayoutServerLoad = async (event) => {
|
||||
return {
|
||||
session: await event.locals.getSession(),
|
||||
providers: await event.locals.getProviders(),
|
||||
callbackUrl: new URL(event.request.url).host,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<ul class="navItems">
|
||||
<li class="navItem"><a href="/">Home</a></li>
|
||||
<li class="navItem"><a href="/protected">Protected</a></li>
|
||||
<li class="navItem"><a href="/js-disabled">No JS</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
29
apps/dev/sveltekit/src/routes/js-disabled/+page.svelte
Normal file
29
apps/dev/sveltekit/src/routes/js-disabled/+page.svelte
Normal file
@@ -0,0 +1,29 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/stores"
|
||||
import SignInButton from "$lib/SignInButton.svelte"
|
||||
</script>
|
||||
|
||||
<h1>SvelteKit Auth Example</h1>
|
||||
<p>Disable JS in this page and SvelteKit Auth would still work.</p>
|
||||
{#if $page.data.session}
|
||||
{#if $page.data.session.user?.image}
|
||||
<span
|
||||
style="background-image: url('{$page.data.session.user.image}')"
|
||||
class="avatar"
|
||||
/>
|
||||
{/if}
|
||||
<span class="signedInText">
|
||||
<small>Signed in as</small><br />
|
||||
<strong
|
||||
>{$page.data.session.user?.email ?? $page.data.session.user?.name}</strong
|
||||
>
|
||||
</span>
|
||||
<form action="/auth/signout" method="POST">
|
||||
<button type="submit">Sign out</button>
|
||||
</form>
|
||||
{:else}
|
||||
<span class="notSignedInText">You are not signed in</span>
|
||||
{#each Object.values($page.data.providers) as provider}
|
||||
<SignInButton {provider} callbackUrl={$page.data.callbackUrl} />
|
||||
{/each}
|
||||
{/if}
|
||||
@@ -337,4 +337,12 @@ export interface AuthConfig {
|
||||
/** @todo */
|
||||
trustHost?: boolean
|
||||
skipCSRFCheck?: typeof skipCSRFCheck
|
||||
/**
|
||||
* 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/modules/providers).
|
||||
*
|
||||
* @default "/api/auth"
|
||||
*/
|
||||
prefix?: string
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ export async function init({
|
||||
// TODO: move this to web.ts
|
||||
const parsed = parseUrl(
|
||||
reqUrl.origin +
|
||||
reqUrl.pathname.replace(`/${action}`, "").replace(`/${providerId}`, "")
|
||||
reqUrl.pathname.replace(`/${action}`, "").replace(`/${providerId}`, ""),
|
||||
authOptions.prefix
|
||||
)
|
||||
const url = new URL(parsed.toString())
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@ interface InternalUrl {
|
||||
}
|
||||
|
||||
/** Returns an `URL` like object to make requests/redirects from server-side */
|
||||
export default function parseUrl(url?: string | URL): InternalUrl {
|
||||
export default function parseUrl(
|
||||
url?: string | URL,
|
||||
prefix?: string
|
||||
): InternalUrl {
|
||||
const defaultUrl = new URL("http://localhost:3000/api/auth")
|
||||
|
||||
if (url && !url.toString().startsWith("http")) {
|
||||
@@ -20,7 +23,9 @@ export default function parseUrl(url?: string | URL): InternalUrl {
|
||||
}
|
||||
|
||||
const _url = new URL(url ?? defaultUrl)
|
||||
const path = (_url.pathname === "/" ? defaultUrl.pathname : _url.pathname)
|
||||
const path = (
|
||||
_url.pathname === "/" ? prefix ?? defaultUrl.pathname : _url.pathname
|
||||
)
|
||||
// Remove trailing slash
|
||||
.replace(/\/$/, "")
|
||||
|
||||
|
||||
@@ -41,11 +41,6 @@ export async function signIn<
|
||||
|
||||
const _signInUrl = `${signInUrl}?${new URLSearchParams(authorizationParams)}`
|
||||
|
||||
// TODO: Handle custom base path
|
||||
// TODO: Remove this since Sveltekit offers the CSRF protection via origin check
|
||||
const csrfTokenResponse = await fetch("/auth/csrf")
|
||||
const { csrfToken } = await csrfTokenResponse.json()
|
||||
|
||||
const res = await fetch(_signInUrl, {
|
||||
method: "post",
|
||||
headers: {
|
||||
@@ -55,7 +50,6 @@ export async function signIn<
|
||||
// @ts-expect-error -- ignore
|
||||
body: new URLSearchParams({
|
||||
...options,
|
||||
csrfToken,
|
||||
callbackUrl,
|
||||
}),
|
||||
})
|
||||
@@ -84,8 +78,6 @@ export async function signOut(options?: SignOutParams) {
|
||||
const { callbackUrl = window.location.href } = options ?? {}
|
||||
// TODO: Custom base path
|
||||
// TODO: Remove this since Sveltekit offers the CSRF protection via origin check
|
||||
const csrfTokenResponse = await fetch("/auth/csrf")
|
||||
const { csrfToken } = await csrfTokenResponse.json()
|
||||
const res = await fetch(`/auth/signout`, {
|
||||
method: "post",
|
||||
headers: {
|
||||
@@ -93,7 +85,6 @@ export async function signOut(options?: SignOutParams) {
|
||||
"X-Auth-Return-Redirect": "1",
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
csrfToken,
|
||||
callbackUrl,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
* providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* or to use sveltekit platform environment variables for platforms like Cloudflare
|
||||
*
|
||||
*
|
||||
* ```ts title="src/hooks.server.ts"
|
||||
* import { SvelteKitAuth } from "@auth/sveltekit"
|
||||
* import GitHub from "@auth/core/providers/github"
|
||||
@@ -206,17 +206,37 @@ import type { Handle, RequestEvent } from "@sveltejs/kit"
|
||||
import { dev } from "$app/environment"
|
||||
import { env } from "$env/dynamic/private"
|
||||
|
||||
import { Auth } from "@auth/core"
|
||||
import { Auth, skipCSRFCheck } from "@auth/core"
|
||||
import type { AuthAction, AuthConfig, Session } from "@auth/core/types"
|
||||
import type { Provider } from "@auth/core/providers"
|
||||
|
||||
export async function getSession(
|
||||
req: Request,
|
||||
config: AuthConfig
|
||||
config: SvelteKitAuthConfig
|
||||
): ReturnType<App.Locals["getSession"]> {
|
||||
config.secret ??= env.AUTH_SECRET
|
||||
config.trustHost ??= true
|
||||
|
||||
const url = new URL("/api/auth/session", req.url)
|
||||
const url = new URL(`${config.prefix}/session`, req.url)
|
||||
const request = new Request(url, { headers: req.headers })
|
||||
const response = await Auth(request, config)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
export async function getProviders(
|
||||
req: Request,
|
||||
config: SvelteKitAuthConfig
|
||||
): ReturnType<App.Locals["getProviders"]> {
|
||||
config.secret ??= env.AUTH_SECRET
|
||||
config.trustHost ??= true
|
||||
|
||||
const url = new URL(`${config.prefix}/providers`, req.url)
|
||||
const request = new Request(url, { headers: req.headers })
|
||||
const response = await Auth(request, config)
|
||||
|
||||
@@ -240,6 +260,9 @@ export interface SvelteKitAuthConfig extends AuthConfig {
|
||||
prefix?: string
|
||||
}
|
||||
|
||||
/** Configure the {@link SvelteKitAuth} method. */
|
||||
export interface SvelteKitAuthConfig extends AuthConfig {}
|
||||
|
||||
const actions: AuthAction[] = [
|
||||
"providers",
|
||||
"session",
|
||||
@@ -251,24 +274,36 @@ const actions: AuthAction[] = [
|
||||
"error",
|
||||
]
|
||||
|
||||
type DynamicSvelteKitAuthConfig = (event: RequestEvent) => PromiseLike<SvelteKitAuthConfig>
|
||||
type DynamicSvelteKitAuthConfig = (
|
||||
event: RequestEvent
|
||||
) => PromiseLike<SvelteKitAuthConfig>
|
||||
|
||||
function AuthHandle(svelteKitAuthOptions: SvelteKitAuthConfig | DynamicSvelteKitAuthConfig): Handle {
|
||||
function AuthHandle(
|
||||
svelteKitAuthOptions: SvelteKitAuthConfig | DynamicSvelteKitAuthConfig
|
||||
): Handle {
|
||||
return async function ({ event, resolve }) {
|
||||
const authOptions =
|
||||
const _authOptions =
|
||||
typeof svelteKitAuthOptions === "object"
|
||||
? svelteKitAuthOptions
|
||||
: await svelteKitAuthOptions(event)
|
||||
const { prefix = "/auth" } = authOptions
|
||||
const { url, request } = event
|
||||
const authOptions = {
|
||||
..._authOptions,
|
||||
skipCSRFCheck,
|
||||
prefix: _authOptions.prefix ?? "/auth",
|
||||
} satisfies AuthConfig
|
||||
|
||||
event.locals.getSession ??= () => getSession(request, authOptions)
|
||||
event.locals.getProviders ??= () => getProviders(request, authOptions)
|
||||
|
||||
const action = url.pathname
|
||||
.slice(prefix.length + 1)
|
||||
.slice(authOptions.prefix.length + 1)
|
||||
.split("/")[0] as AuthAction
|
||||
|
||||
if (!actions.includes(action) || !url.pathname.startsWith(prefix + "/")) {
|
||||
if (
|
||||
!actions.includes(action) ||
|
||||
!url.pathname.startsWith(authOptions.prefix + "/")
|
||||
) {
|
||||
return resolve(event)
|
||||
}
|
||||
|
||||
@@ -280,7 +315,9 @@ function AuthHandle(svelteKitAuthOptions: SvelteKitAuthConfig | DynamicSvelteKit
|
||||
* The main entry point to `@auth/sveltekit`
|
||||
* @see https://sveltekit.authjs.dev
|
||||
*/
|
||||
export function SvelteKitAuth(options: SvelteKitAuthConfig | DynamicSvelteKitAuthConfig): Handle {
|
||||
export function SvelteKitAuth(
|
||||
options: SvelteKitAuthConfig | DynamicSvelteKitAuthConfig
|
||||
): Handle {
|
||||
if (typeof options === "object") {
|
||||
options.secret ??= env.AUTH_SECRET
|
||||
options.trustHost ??= !!(env.AUTH_TRUST_HOST ?? env.VERCEL ?? dev)
|
||||
@@ -293,9 +330,11 @@ declare global {
|
||||
namespace App {
|
||||
interface Locals {
|
||||
getSession(): Promise<Session | null>
|
||||
getProviders(): Promise<Provider[] | null>
|
||||
}
|
||||
interface PageData {
|
||||
session: Session | null
|
||||
providers: Provider[] | null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user