mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-09 20:27:44 +00:00
feat: move password hashing to scrypt
This commit is contained in:
@@ -3,7 +3,7 @@ import {} from "better-auth/client";
|
||||
import Section from "@/components/landing/section";
|
||||
import Hero from "@/components/landing/hero";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { FeaturesSectionDemo } from "@/components/blocks/features-section-demo-3";
|
||||
import { FeaturesSectionDemo } from "@/components/blocks/features";
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { useId } from "react";
|
||||
|
||||
export function FeaturesSectionDemo() {
|
||||
export function Features() {
|
||||
return (
|
||||
<div className="py-2">
|
||||
<div className="mt-2 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-10 md:gap-2 max-w-7xl mx-auto">
|
||||
@@ -30,6 +30,11 @@ const grid = [
|
||||
description:
|
||||
"Supports your favorite frontend, backend and meta frameworks, including React, Vue, Svelte, Solid, Next.js, Nuxt.js, Hono, and more.",
|
||||
},
|
||||
{
|
||||
title: "Automatic Database Management",
|
||||
description:
|
||||
"better auth will automatically manage required tables for authentication, just configure the database and better auth will do the rest.",
|
||||
},
|
||||
{
|
||||
title: "Email & Password Authentication",
|
||||
description:
|
||||
@@ -40,11 +45,6 @@ const grid = [
|
||||
description:
|
||||
"Allow users to sign in with their accounts, including Github, Google, Discord, Twitter, and more.",
|
||||
},
|
||||
{
|
||||
title: "Two Factor",
|
||||
description:
|
||||
"Add an extra layer of security with two-factor authentication, including TOTP and SMS.",
|
||||
},
|
||||
{
|
||||
title: "Organization & Access Control",
|
||||
description:
|
||||
@@ -109,9 +109,10 @@ export default function Hero() {
|
||||
The most comprehensive authentication library for typescript.
|
||||
</p>
|
||||
<div className="mt-8 flex gap-4 font-sans md:justify-center lg:justify-start flex-col md:flex-row">
|
||||
<button className="px-4 md:px-8 py-0.5 border-2 border-black dark:border-white uppercase bg-white text-black transition duration-200 text-sm shadow-[1px_1px_rgba(0,0,0),2px_2px_rgba(0,0,0),3px_3px_rgba(0,0,0),4px_4px_rgba(0,0,0),5px_5px_0px_0px_rgba(0,0,0)] dark:shadow-[1px_1px_rgba(255,255,255),2px_2px_rgba(255,255,255),3px_3px_rgba(255,255,255),4px_4px_rgba(255,255,255),5px_5px_0px_0px_rgba(255,255,255)] ">
|
||||
<Link href="/docs" className="px-4 md:px-8 py-0.5 border-2 border-black dark:border-stone-100 uppercase bg-white text-black transition duration-200 text-sm shadow-[1px_1px_rgba(0,0,0),2px_2px_rgba(0,0,0),3px_3px_rgba(0,0,0),4px_4px_rgba(0,0,0),5px_5px_0px_0px_rgba(0,0,0)] dark:shadow-[1px_1px_rgba(255,255,255),2px_2px_rgba(255,255,255),3px_3px_rgba(255,255,255),4px_4px_rgba(255,255,255),5px_5px_0px_0px_rgba(255,255,255)] dark:hover:shadow-sm hover:shadow-sm">
|
||||
Get Started
|
||||
</button>
|
||||
|
||||
</Link>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
|
||||
@@ -76,20 +76,10 @@ export const contents: Content[] = [
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Basic Usage",
|
||||
href: "/docs/basic-usage",
|
||||
title: "Core Concepts",
|
||||
href: "/docs/core-concepts",
|
||||
icon: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1.2em"
|
||||
height="1.2em"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M21 2H3c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2M10 19.4l-1.6.6C6.9 18.6 6 16.6 6 14.5s.9-4.1 2.4-5.5l1.6.6c-1.3 1.1-2 3-2 4.9s.7 3.7 2 4.9m5.6.6l-1.6-.6c1.3-1.2 2-3 2-4.9s-.7-3.7-2-4.9l1.6-.6c1.5 1.4 2.4 3.4 2.4 5.5s-.9 4.1-2.4 5.5M21 7H3V4h18z"
|
||||
></path>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1.3em" height="1.3em" viewBox="0 0 24 24"><path fill="currentColor" d="M5 21L3 9h18l-2 12zm5-6h4q.425 0 .713-.288T15 14t-.288-.712T14 13h-4q-.425 0-.712.288T9 14t.288.713T10 15M6 8q-.425 0-.712-.288T5 7t.288-.712T6 6h12q.425 0 .713.288T19 7t-.288.713T18 8zm2-3q-.425 0-.712-.288T7 4t.288-.712T8 3h8q.425 0 .713.288T17 4t-.288.713T16 5z"></path></svg>
|
||||
),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -35,7 +35,7 @@ To signup a user, you can use the `signUp.email` function provided by the client
|
||||
// @filename: client.ts
|
||||
import { createAuthClient } from "better-auth/client"
|
||||
|
||||
const client = createAuthClient()
|
||||
export const client = createAuthClient()
|
||||
|
||||
// ---cut---
|
||||
// @filename: signup.ts
|
||||
|
||||
59
docs/content/docs/core-concepts.mdx
Normal file
59
docs/content/docs/core-concepts.mdx
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: Core Concepts
|
||||
description: core concepts of better-auth
|
||||
---
|
||||
|
||||
## Auth Server
|
||||
|
||||
```ts
|
||||
import { betterAuth } from "better-auth"
|
||||
|
||||
export const auth = betterAuth({
|
||||
//...
|
||||
})
|
||||
const api = auth.api
|
||||
const handler = auth.handler
|
||||
```
|
||||
|
||||
The auth instance you create with betterAuth comes with two key properties:
|
||||
|
||||
**handler**: A web standard handler that you mount on your server to handle API requests. (see installation [here](/docs/installation#mount-handler))
|
||||
|
||||
**api**: A collection of methods you can call directly on the server to interact with the auth server, such as `getSession` to retrieve the current session.
|
||||
|
||||
**Example: Getting the current session on the server**
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Consider this as a random route endpoint that we want to protect
|
||||
*/
|
||||
export const POST = (request: Request)=> {
|
||||
const session = await auth.api.getSession({
|
||||
headers: request.headers // get session requires the headers to be passed
|
||||
})
|
||||
}
|
||||
```
|
||||
## Client
|
||||
|
||||
The client side of the library lets you interact with the auth server and includes built-in state management for specific methods, such as useSession.
|
||||
|
||||
You can import the client and use it to call these methods directly or export each method individually from the client.
|
||||
|
||||
If you add new plugins, they may also introduce their own methods. For instance, using the twoFactor plugin will add methods like twoFactor.enable. Check out the example below to see how to use the client:
|
||||
|
||||
```tsx
|
||||
const client = createAuthClient()
|
||||
|
||||
export const { signIn, signUp, signOut, useSession } = client
|
||||
|
||||
export function SignUp(){
|
||||
async function handleSubmit(data){
|
||||
await signUp.email({
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
password: data.password,
|
||||
})
|
||||
}
|
||||
//...your component
|
||||
}
|
||||
```
|
||||
@@ -18,16 +18,9 @@ description: Installation
|
||||
|
||||
Create a `.env` file in the root of your project and add the following environment variables:
|
||||
|
||||
**Set Base URL**
|
||||
|
||||
Base URL of your auth handler (this is assuming you are using `/api/auth` as the base path)
|
||||
```txt title=".env"
|
||||
BETTER_AUTH_URL=http://localhost:3000/api/auth
|
||||
```
|
||||
|
||||
**Set Secret**
|
||||
|
||||
Random value used by the library for encryption and generating hashes. You can generate one using the button below or you can use something like openssl.
|
||||
Random value used by the library for encryption and generating hashes. **You can generate one using the button below** or you can use something like openssl.
|
||||
```txt title=".env"
|
||||
BETTER_AUTH_SECRET=
|
||||
```
|
||||
@@ -41,6 +34,23 @@ description: Installation
|
||||
|
||||
any of these directories can also be nested under `src/` directory.
|
||||
|
||||
<Callout type="warn">
|
||||
Make sure to export the auth instance from the file. With the virable name `auth`.
|
||||
</Callout>
|
||||
|
||||
```ts title="auth.ts"
|
||||
import { betterAuth } from "better-auth"
|
||||
|
||||
export const auth = betterAuth({
|
||||
//...
|
||||
})
|
||||
```
|
||||
</Step>
|
||||
<Step>
|
||||
### Database
|
||||
|
||||
Better Auth requires a database to store user data. It currently only supports `sqlite`, `postgresql` and `mysql`.
|
||||
|
||||
```ts twoslash title="auth.ts"
|
||||
import { betterAuth } from "better-auth"
|
||||
|
||||
@@ -52,19 +62,19 @@ description: Installation
|
||||
})
|
||||
```
|
||||
<Callout type="info">
|
||||
Better Auth currently supports only SQLite, MySQL, and PostgreSQL. It uses Kysely under the hood, so you can also pass any Kysely dialect directly to the database object.
|
||||
Better auth uses <Link href="https://kysely.dev/">Kysley</Link> under the hood. You can pass a Kysley dialect directly to the auth instance.
|
||||
</Callout>
|
||||
</Step>
|
||||
<Step>
|
||||
### Database
|
||||
|
||||
**Push Schema**
|
||||
|
||||
Better Auth includes a CLI tool to migrate the required schema to your database. Run the following command to perform the migration:
|
||||
```bash
|
||||
npx better-auth migrate
|
||||
```
|
||||
</Step>
|
||||
<Step>
|
||||
### Providers
|
||||
Enable email/password authentication and social sign-on providers.
|
||||
### Authentication Methods
|
||||
Configure the authentication methods you want to use. Better auth comes with built-in support for email/password, and social sign-on providers.
|
||||
|
||||
```ts
|
||||
import { betterAuth } from "better-auth"
|
||||
@@ -75,21 +85,27 @@ description: Installation
|
||||
provider: "sqlite",
|
||||
url: "./db.sqlite",
|
||||
},
|
||||
socialProvider: [
|
||||
github({
|
||||
clientId: process.env.GITHUB_CLIENT_ID as string,
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
|
||||
}),
|
||||
],
|
||||
emailAndPassword: {
|
||||
enabled: true
|
||||
}
|
||||
socialProvider: [ // [!code highlight]
|
||||
github({ // [!code highlight]
|
||||
clientId: process.env.GITHUB_CLIENT_ID as string, // [!code highlight]
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET as string, // [!code highlight]
|
||||
}), // [!code highlight]
|
||||
], // [!code highlight]
|
||||
emailAndPassword: { // [!code highlight]
|
||||
enabled: true // [!code highlight]
|
||||
}// [!code highlight]
|
||||
});
|
||||
```
|
||||
|
||||
<Callout type="info">
|
||||
You can use even more authentication methods like passkey, username, magic link and more through plugins.
|
||||
</Callout>
|
||||
</Step>
|
||||
<Step>
|
||||
### Mount Handler
|
||||
Once you’ve got your instance set up, mount the handler on the right server route to handle authentication requests. Just create a route handler or drop a file into your framework’s catch-all directory, making sure the base path is set to /api/auth (unless you’ve changed it to something else).
|
||||
To handle api requests, you need to set up a route handler on your server.
|
||||
|
||||
Create a new file or route in your framework's designated catch-all route handler. This route should handle requests for the path `/api/auth/*` (unless you've configured a different base path).
|
||||
|
||||
<Tabs items={["next-js", "svelte-kit", "nuxt", "solid-start", "hono"]} defaultValue="react">
|
||||
<Tab value="next-js">
|
||||
@@ -159,44 +175,55 @@ description: Installation
|
||||
</Step>
|
||||
<Step>
|
||||
### Create Client
|
||||
Better Auth Client supports various frameworks like React, Vue, Svelte, and Solid, and it even plays nice with vanilla JavaScript. To get started, just import the createAuthClient function from the appropriate package and drop it into any file where you want to use the client.
|
||||
|
||||
The client side of the library lets you interact with the auth server and includes state management for methods like useSession. Adding plugins may introduce additional methods, like `twoFactor.enable` from the twoFactor plugin.
|
||||
|
||||
To get started, just import and call the `createAuthClient` function from the **appropriate package**.
|
||||
|
||||
<Callout type="warn">
|
||||
Make sure you import the client from the correct path.
|
||||
</Callout>
|
||||
<Tabs items={["vanilla","react", "vue", "svelte", "solid"]} defaultValue="react">
|
||||
<Tab value="vanilla" title="lib/auth-client.ts">
|
||||
```ts
|
||||
<Tab value="vanilla">
|
||||
```ts title="lib/auth-client.ts" twoslash
|
||||
import { createAuthClient } from "better-auth/client"
|
||||
const client = createAuthClient()
|
||||
export const client = createAuthClient()
|
||||
```
|
||||
</Tab>
|
||||
<Tab value="react" title="lib/auth-client.ts">
|
||||
```ts
|
||||
```ts title="lib/auth-client.ts" twoslash
|
||||
import { createAuthClient } from "better-auth/react"
|
||||
const client = createAuthClient()
|
||||
export const client = createAuthClient()
|
||||
```
|
||||
</Tab>
|
||||
<Tab value="vue" title="lib/auth-client.ts">
|
||||
```ts
|
||||
```ts title="lib/auth-client.ts" twoslash
|
||||
import { createAuthClient } from "better-auth/vue"
|
||||
const client = createAuthClient()
|
||||
export const client = createAuthClient()
|
||||
```
|
||||
</Tab>
|
||||
<Tab value="svelte" title="lib/auth-client.ts">
|
||||
```ts
|
||||
```ts title="lib/auth-client.ts" twoslash
|
||||
import { createAuthClient } from "better-auth/svelte"
|
||||
const client = createAuthClient()
|
||||
export const client = createAuthClient()
|
||||
```
|
||||
</Tab>
|
||||
<Tab value="solid" title="lib/auth-client.ts">
|
||||
```ts
|
||||
```ts title="lib/auth-client.ts" twoslash
|
||||
import { createAuthClient } from "better-auth/solid"
|
||||
const client = createAuthClient()
|
||||
export const client = createAuthClient()
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
<Callout type="info">
|
||||
You can also export the client methods individually.
|
||||
```ts twoslash
|
||||
import { createAuthClient } from "better-auth/client"
|
||||
// ---cut---
|
||||
export const { signIn, signUp, useSession } = createAuthClient()
|
||||
//...rest of the methods you want to export
|
||||
```
|
||||
</Callout>
|
||||
</Step>
|
||||
<Step>
|
||||
### That's it!
|
||||
|
||||
@@ -7,7 +7,7 @@ Better Auth is a type-safe, framework-agnostic authentication library for TypeSc
|
||||
|
||||
## Why Better Auth?
|
||||
|
||||
*Hi there, I’m <Link href="https://x.com/imbereket" target="_blank">Beka</Link>, the creator of Better Auth. I’ve often found that working with TypeScript auth libraries means dealing with a ton of additional code for anything beyond basic authentication, which is just a huge time sink. I thought we could do better than pushing third-party providers for something that can be provided as a library, so I built Better Auth.*
|
||||
*Authentication libraries in typescript often doesn't deliver the quality and features that are required for modern applications. Third-party services are convenient, but they come with their own set of problems. And of course, they aren't free. Better Auth aims to provide a better alternative.*
|
||||
|
||||
## Features
|
||||
|
||||
@@ -15,4 +15,4 @@ Better auth is aims to be the most comprehensive auth library. It provides a wid
|
||||
|
||||
<Features/>
|
||||
|
||||
and much more...
|
||||
and much more and even more to come...
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
||||
import { GenerateSecret } from "./components/generate-secret";
|
||||
import { Popup, PopupContent, PopupTrigger } from "fumadocs-ui/twoslash/popup";
|
||||
import { TypeTable } from "fumadocs-ui/components/type-table";
|
||||
import { FeaturesSectionDemo } from "./components/blocks/features-section-demo-3";
|
||||
import { Features } from "./components/blocks/features";
|
||||
export function useMDXComponents(components: MDXComponents): MDXComponents {
|
||||
return {
|
||||
...defaultComponents,
|
||||
@@ -27,6 +27,6 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
|
||||
PopupTrigger,
|
||||
PopupContent,
|
||||
TypeTable,
|
||||
Features: FeaturesSectionDemo,
|
||||
Features,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { TimeSpan } from "oslo";
|
||||
import { createJWT } from "oslo/jwt";
|
||||
import { validateJWT } from "oslo/jwt";
|
||||
import { Argon2id } from "oslo/password";
|
||||
import { z } from "zod";
|
||||
import { createAuthEndpoint } from "../call";
|
||||
import { hashPassword } from "../../crypto/password";
|
||||
|
||||
export const forgetPassword = createAuthEndpoint(
|
||||
"/forget-password",
|
||||
@@ -115,8 +115,7 @@ export const resetPassword = createAuthEndpoint(
|
||||
},
|
||||
});
|
||||
}
|
||||
const argon2id = new Argon2id();
|
||||
const hashedPassword = await argon2id.hash(newPassword);
|
||||
const hashedPassword = await hashPassword(newPassword);
|
||||
const updatedUser = await ctx.context.internalAdapter.updatePassword(
|
||||
user.user.id,
|
||||
hashedPassword,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { APIError } from "better-call";
|
||||
import { generateCodeVerifier } from "oslo/oauth2";
|
||||
import { Argon2id } from "oslo/password";
|
||||
import { z } from "zod";
|
||||
import { oAuthProviderList } from "../../social-providers";
|
||||
import { generateState } from "../../utils/state";
|
||||
import { createAuthEndpoint } from "../call";
|
||||
import { getSessionFromCtx } from "./session";
|
||||
import { setSessionCookie } from "../../utils/cookies";
|
||||
import { hashPassword, verifyPassword } from "../../crypto/password";
|
||||
|
||||
export const signInOAuth = createAuthEndpoint(
|
||||
"/sign-in/social",
|
||||
@@ -132,10 +132,9 @@ export const signInEmail = createAuthEndpoint(
|
||||
message: "Invalid email",
|
||||
});
|
||||
}
|
||||
const argon2id = new Argon2id();
|
||||
const user = await ctx.context.internalAdapter.findUserByEmail(email);
|
||||
if (!user) {
|
||||
await argon2id.hash(password);
|
||||
await hashPassword(password);
|
||||
ctx.context.logger.error("User not found", { email });
|
||||
throw new APIError("UNAUTHORIZED", {
|
||||
message: "Invalid email or password",
|
||||
@@ -157,7 +156,7 @@ export const signInEmail = createAuthEndpoint(
|
||||
message: "Unexpected error",
|
||||
});
|
||||
}
|
||||
const validPassword = await argon2id.verify(currentPassword, password);
|
||||
const validPassword = await verifyPassword(currentPassword, password);
|
||||
if (!validPassword) {
|
||||
ctx.context.logger.error("Invalid password");
|
||||
throw new APIError("UNAUTHORIZED", {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { alphabet, generateRandomString } from "oslo/crypto";
|
||||
import { Argon2id } from "oslo/password";
|
||||
import { z } from "zod";
|
||||
import { createAuthEndpoint } from "../call";
|
||||
import { createEmailVerificationToken } from "./verify-email";
|
||||
import { hashPassword } from "../../crypto/password";
|
||||
|
||||
export const signUpEmail = createAuthEndpoint(
|
||||
"/sign-up/email",
|
||||
@@ -35,12 +35,11 @@ export const signUpEmail = createAuthEndpoint(
|
||||
body: { message: "Password is too short" },
|
||||
});
|
||||
}
|
||||
const argon2id = new Argon2id();
|
||||
const dbUser = await ctx.context.internalAdapter.findUserByEmail(email);
|
||||
/**
|
||||
* hash first to avoid timing attacks
|
||||
*/
|
||||
const hash = await argon2id.hash(password);
|
||||
const hash = await hashPassword(password);
|
||||
if (dbUser?.user) {
|
||||
return ctx.json(null, {
|
||||
status: 400,
|
||||
|
||||
4
packages/better-auth/src/crypto/password.ts
Normal file
4
packages/better-auth/src/crypto/password.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Scrypt } from "oslo/password";
|
||||
|
||||
const password = new Scrypt();
|
||||
export const { hash: hashPassword, verify: verifyPassword } = password;
|
||||
@@ -1,10 +1,10 @@
|
||||
import { z } from "zod";
|
||||
import { createAuthEndpoint } from "../../api/call";
|
||||
import type { BetterAuthPlugin } from "../../types/plugins";
|
||||
import { Argon2id } from "oslo/password";
|
||||
import { APIError } from "better-call";
|
||||
import type { Account, User } from "../../adapters/schema";
|
||||
import { signUpEmail } from "../../api/routes/sign-up";
|
||||
import { hashPassword, verifyPassword } from "../../crypto/password";
|
||||
|
||||
export const username = () => {
|
||||
return {
|
||||
@@ -31,9 +31,8 @@ export const username = () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
const argon2id = new Argon2id();
|
||||
if (!user) {
|
||||
await argon2id.hash(ctx.body.password);
|
||||
await hashPassword(ctx.body.password);
|
||||
ctx.context.logger.error("User not found", { username });
|
||||
throw new APIError("UNAUTHORIZED", {
|
||||
message: "Invalid email or password",
|
||||
@@ -64,7 +63,7 @@ export const username = () => {
|
||||
message: "Unexpected error",
|
||||
});
|
||||
}
|
||||
const validPassword = await argon2id.verify(
|
||||
const validPassword = await verifyPassword(
|
||||
currentPassword,
|
||||
ctx.body.password,
|
||||
);
|
||||
|
||||
52
rough-doc.md
Normal file
52
rough-doc.md
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
Basic Concepts
|
||||
|
||||
|
||||
## Auth Server
|
||||
|
||||
the auth instance you create with `betterAuth` has 2 important properties:
|
||||
|
||||
- `auth.handler`
|
||||
- `auth.api`
|
||||
|
||||
the `auth.handler` is a web standard handler that you mount on your server that handler api requests.
|
||||
|
||||
`auth.api` is a list of methods that you can call directly on the server, to interact with the auth server. Like `getSession` to get the current session. Plugins may add additional methods to the api.
|
||||
|
||||
**Example: Getting the current session on the server**
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Consider this as a random route endpoint that we want to protect
|
||||
*/
|
||||
export const POST = (request: Request)=> {
|
||||
const session = await auth.api.getSession({
|
||||
headers: request.headers // get session requires the headers to be passed
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Client
|
||||
|
||||
The client side of the library lets you interact with the auth server and includes built-in state management for specific methods, such as useSession.
|
||||
|
||||
You can import the client and use it to call these methods directly or export each method individually from the client.
|
||||
|
||||
If you add new plugins, they may also introduce their own methods. For instance, using the twoFactor plugin will add methods like twoFactor.enable. Check out the example below to see how to use the client:
|
||||
|
||||
```tsx
|
||||
const client = createAuthClient()
|
||||
|
||||
export const { signIn, signUp, signOut, useSession } = client
|
||||
|
||||
export function SignUp(){
|
||||
async function handleSubmit(data){
|
||||
await signUp.email({
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
password: data.password,
|
||||
})
|
||||
}
|
||||
//...your component
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user