mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-10 04:19:32 +00:00
feat: sveltekit cookie helper plugin (#3049)
* fix(email-verification): improve email verification logic to check session and user email consistency (#3042) * docs(passkey): Fixed signIn passkey props (#3014) callbackURL doesn't exist. * feat: svelte kit cookie helper * lint * docs and clean up * clean up * lint * clean up * clean up * sync cookies * lint * pruning * pruning and lint * update * update * update --------- Co-authored-by: Bereket Engida <86073083+Bekacru@users.noreply.github.com> Co-authored-by: Maxwell <145994855+ping-maxwell@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
be3face70c
commit
4e38645b44
@@ -28,7 +28,6 @@ import { useAtom } from "jotai";
|
||||
import { optionsAtom } from "./store";
|
||||
import { useTheme } from "next-themes";
|
||||
import { ScrollArea } from "../ui/scroll-area";
|
||||
import styles from "./builder.module.css";
|
||||
const frameworks = [
|
||||
{
|
||||
title: "Next.js",
|
||||
|
||||
@@ -18,6 +18,27 @@ export async function handle({ event, resolve }) {
|
||||
}
|
||||
```
|
||||
|
||||
### Server Action Cookies
|
||||
|
||||
To ensure cookies are properly set when you call functions like `signInEmail` or `signUpEmail` in a server action, you should use the `sveltekitCookies` plugin. This plugin will automatically handle setting cookies for you in SvelteKit.
|
||||
|
||||
You need to add it as a plugin to your Better Auth instance.
|
||||
|
||||
<Callout>
|
||||
The `getRequestEvent` function is available in SvelteKit `2.2.0` and later. Make sure you are using a compatible version.
|
||||
</Callout>
|
||||
|
||||
```ts title="lib/auth.ts"
|
||||
import { BetterAuth } from "better-auth";
|
||||
import { sveltekitCookies } from "better-auth/svelte-kit";
|
||||
|
||||
export const auth = betterAuth({
|
||||
// ... your config
|
||||
plugins: [sveltekitCookies()]
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
## Create a client
|
||||
|
||||
Create a client instance. You can name the file anything you want. Here we are creating `client.ts` file inside the `lib/` directory.
|
||||
|
||||
@@ -117,7 +117,9 @@ Signin method accepts:
|
||||
|
||||
`autoFill`: Browser autofill, a.k.a. Conditional UI. [read more](https://simplewebauthn.dev/docs/packages/browser#browser-autofill-aka-conditional-ui)
|
||||
|
||||
`callbackURL`: The URL to redirect to after the user has signed in. (optional)
|
||||
`email`: The email of the user to sign in.
|
||||
|
||||
`fetchOptions`: Fetch options to pass to the fetch request.
|
||||
|
||||
```ts
|
||||
const data = await authClient.signIn.passkey();
|
||||
|
||||
@@ -4,7 +4,6 @@ import { APIError } from "better-call";
|
||||
import { getSessionFromCtx } from "./session";
|
||||
import { setSessionCookie } from "../../cookies";
|
||||
import type { GenericEndpointContext, User } from "../../types";
|
||||
import { BASE_ERROR_CODES } from "../../error/codes";
|
||||
import { jwtVerify, type JWTPayload, type JWTVerifyResult } from "jose";
|
||||
import { signJWT } from "../../crypto/jwt";
|
||||
import { originCheck } from "../middlewares";
|
||||
@@ -155,13 +154,32 @@ export const sendVerificationEmail = createAuthEndpoint(
|
||||
});
|
||||
}
|
||||
const { email } = ctx.body;
|
||||
const user = await ctx.context.internalAdapter.findUserByEmail(email);
|
||||
if (!user) {
|
||||
throw new APIError("BAD_REQUEST", {
|
||||
message: BASE_ERROR_CODES.USER_NOT_FOUND,
|
||||
const session = await getSessionFromCtx(ctx);
|
||||
if (!session) {
|
||||
const user = await ctx.context.internalAdapter.findUserByEmail(email);
|
||||
if (!user) {
|
||||
//we're returning true to avoid leaking information about the user
|
||||
return ctx.json({
|
||||
status: true,
|
||||
});
|
||||
}
|
||||
await sendVerificationEmailFn(ctx, user.user);
|
||||
return ctx.json({
|
||||
status: true,
|
||||
});
|
||||
}
|
||||
await sendVerificationEmailFn(ctx, user.user);
|
||||
if (session?.user.emailVerified) {
|
||||
throw new APIError("BAD_REQUEST", {
|
||||
message:
|
||||
"You can only send a verification email to an unverified email",
|
||||
});
|
||||
}
|
||||
if (session?.user.email !== email) {
|
||||
throw new APIError("BAD_REQUEST", {
|
||||
message: "You can only send a verification email to your own email",
|
||||
});
|
||||
}
|
||||
await sendVerificationEmailFn(ctx, session.user);
|
||||
return ctx.json({
|
||||
status: true,
|
||||
});
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import type { BetterAuthOptions } from "../types";
|
||||
import type { BetterAuthPlugin } from "../types";
|
||||
import { createAuthMiddleware } from "../api";
|
||||
import { parseSetCookieHeader } from "../cookies";
|
||||
|
||||
export const toSvelteKitHandler = (auth: {
|
||||
handler: (request: Request) => any;
|
||||
@@ -49,3 +52,43 @@ export function isAuthPath(url: string, options: BetterAuthOptions) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
export const sveltekitCookies = () => {
|
||||
return {
|
||||
id: "sveltekit-cookies",
|
||||
hooks: {
|
||||
after: [
|
||||
{
|
||||
matcher() {
|
||||
return true;
|
||||
},
|
||||
handler: createAuthMiddleware(async (ctx) => {
|
||||
const returned = ctx.context.responseHeaders;
|
||||
if ("_flag" in ctx && ctx._flag === "router") {
|
||||
return;
|
||||
}
|
||||
if (returned instanceof Headers) {
|
||||
const setCookies = returned?.get("set-cookie");
|
||||
if (!setCookies) return;
|
||||
// @ts-expect-error
|
||||
const { getRequestEvent } = await import("$app/server");
|
||||
const event = await getRequestEvent();
|
||||
if (!event) return;
|
||||
const parsed = parseSetCookieHeader(setCookies);
|
||||
for (const [name, { value, ...ops }] of parsed) {
|
||||
event.cookies.set(name, decodeURIComponent(value), {
|
||||
sameSite: ops.samesite,
|
||||
path: ops.path || "/",
|
||||
expires: ops.expires,
|
||||
secure: ops.secure,
|
||||
httpOnly: ops.httponly,
|
||||
domain: ops.domain,
|
||||
maxAge: ops["max-age"],
|
||||
});
|
||||
}
|
||||
}
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
} satisfies BetterAuthPlugin;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user