docs/content/docs/basic-usage.mdx
Better Auth provides built-in authentication support for:
But also can easily be extended using plugins, such as: username, magic link, passkey, email-otp, and more.
To enable email and password authentication:
import { betterAuth } from "better-auth"
export const auth = betterAuth({
emailAndPassword: { // [!code highlight]
enabled: true // [!code highlight]
} // [!code highlight]
})
To sign up a user you need to call the client method signUp.email with the user's information.
import { authClient } from "@/lib/auth-client"; //import the auth client // [!code highlight]
const { data, error } = await authClient.signUp.email({
email, // user email address
password, // user password -> min 8 characters by default
name, // user display name
image, // User image URL (optional)
callbackURL: "/dashboard" // A URL to redirect to after the user verifies their email (optional)
}, {
onRequest: (ctx) => {
//show loading
},
onSuccess: (ctx) => {
//redirect to the dashboard or sign in page
},
onError: (ctx) => {
// display the error message
alert(ctx.error.message);
},
});
By default, the users are automatically signed in after they successfully sign up. To disable this behavior you can set autoSignIn to false.
import { betterAuth } from "better-auth"
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
autoSignIn: false //defaults to true // [!code highlight]
},
})
To sign a user in, you can use the signIn.email function provided by the client.
const { data, error } = await authClient.signIn.email({
/**
* The user email
*/
email,
/**
* The user password
*/
password,
/**
* A URL to redirect to after the user verifies their email (optional)
*/
callbackURL: "/dashboard",
/**
* remember the user session after the browser is closed.
* @default true
*/
rememberMe: false
}, {
//callbacks
})
To authenticate a user on the server, you can use the auth.api methods.
import { auth } from "./auth"; // path to your Better Auth server instance
const response = await auth.api.signInEmail({
body: {
email,
password
},
asResponse: true // returns a response object instead of data
});
Better Auth supports multiple social providers, including Google, GitHub, Apple, Discord, and more. To use a social provider, you need to configure the ones you need in the socialProviders option on your auth object.
import { betterAuth } from "better-auth";
export const auth = betterAuth({
socialProviders: { // [!code highlight]
github: { // [!code highlight]
clientId: process.env.GITHUB_CLIENT_ID!, // [!code highlight]
clientSecret: process.env.GITHUB_CLIENT_SECRET!, // [!code highlight]
} // [!code highlight]
}, // [!code highlight]
})
To sign in using a social provider you need to call signIn.social. It takes an object with the following properties:
import { authClient } from "@/lib/auth-client"; //import the auth client // [!code highlight]
await authClient.signIn.social({
/**
* The social provider ID
* @example "github", "google", "apple"
*/
provider: "github",
/**
* A URL to redirect after the user authenticates with the provider
* @default "/"
*/
callbackURL: "/dashboard",
/**
* A URL to redirect if an error occurs during the sign in process
*/
errorCallbackURL: "/error",
/**
* A URL to redirect if the user is newly registered
*/
newUserCallbackURL: "/welcome",
/**
* disable the automatic redirect to the provider.
* @default false
*/
disableRedirect: true,
});
You can also authenticate using idToken or accessToken from the social provider instead of redirecting the user to the provider's site. See social providers documentation for more details.
To signout a user, you can use the signOut function provided by the client.
await authClient.signOut();
you can pass fetchOptions to redirect onSuccess
await authClient.signOut({
fetchOptions: {
onSuccess: () => {
router.push("/login"); // redirect to login page
},
},
});
Once a user is signed in, you'll want to access the user session. Better Auth allows you to easily access the session data from both the server and client sides.
Better Auth provides a useSession hook to easily access session data on the client side. This hook is implemented using nanostore and has support for each supported framework and vanilla client, ensuring that any changes to the session (such as signing out) are immediately reflected in your UI.
<Tabs items={["React", "Vue","Svelte", "Solid", "Vanilla"]} defaultValue="react"> <Tab value="React"> ```tsx title="user.tsx" import { authClient } from "@/lib/auth-client" // import the auth client // [!code highlight]
export function User(){
const { // [!code highlight]
data: session, // [!code highlight]
isPending, //loading state // [!code highlight]
error, //error object // [!code highlight]
refetch //refetch the session
} = authClient.useSession() // [!code highlight]
return (
//...
)
}
```
const session = authClient.useSession() // [!code highlight]
</script>
<template>
<div>
<div>
<pre>{{ session.data }}</pre>
<button v-if="session.data" @click="authClient.signOut()">
Sign out
</button>
</div>
</div>
</template>
```
const session = authClient.useSession(); // [!code highlight]
</script>
<p>
{$session.data?.user.email}
</p>
```
authClient.useSession.subscribe((value)=>{
//do something with the session //
})
```
export default function Home() {
const session = authClient.useSession() // [!code highlight]
return (
<pre>{JSON.stringify(session(), null, 2)}</pre>
);
}
```
If you prefer not to use the hook, you can use the getSession method provided by the client.
import { authClient } from "@/lib/auth-client" // import the auth client // [!code highlight]
const { data: session, error } = await authClient.getSession()
You can also use it with client-side data-fetching libraries like TanStack Query.
The server provides a session object that you can use to access the session data. It requires request headers object to be passed to the getSession method.
Example: Using some popular frameworks
<Tabs items={["Next.js", "Nuxt", "Svelte", "Astro", "Hono", "TanStack"]}> <Tab value="Next.js"> ```ts title="server.ts" import { auth } from "./auth"; // path to your Better Auth server instance import { headers } from "next/headers";
const session = await auth.api.getSession({
headers: await headers() // you need to pass the headers object.
})
```
export async function loader({ request }: LoaderFunctionArgs) {
const session = await auth.api.getSession({
headers: request.headers
})
return json({ session })
}
```
const session = await auth.api.getSession({
headers: Astro.request.headers,
});
---
<!-- Your Astro Template -->
```
export async function load({ request }) {
const session = await auth.api.getSession({
headers: request.headers
})
return {
props: {
session
}
}
}
```
const app = new Hono();
app.get("/path", async (c) => {
const session = await auth.api.getSession({
headers: c.req.raw.headers
})
});
```
export default defineEventHandler((event) => {
const session = await auth.api.getSession({
headers: event.headers,
})
});
```
export const APIRoute = createAPIFileRoute("/api/$")({
GET: async ({ request }) => {
const session = await auth.api.getSession({
headers: request.headers
})
},
});
```
One of the unique features of Better Auth is a plugins ecosystem. It allows you to add complex auth related functionality with small lines of code.
Below is an example of how to add two factor authentication using two factor plugin.
<Steps> <Step> ### Server ConfigurationTo add a plugin, you need to import the plugin and pass it to the `plugins` option of the auth instance. For example, to add two factor authentication, you can use the following code:
```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { twoFactor } from "better-auth/plugins" // [!code highlight]
export const auth = betterAuth({
//...rest of the options
plugins: [ // [!code highlight]
twoFactor() // [!code highlight]
] // [!code highlight]
})
```
now two factor related routes and method will be available on the server.
After adding the plugin, you'll need to add the required tables to your database. You can do this by running the `migrate` command, or by using the `generate` command to create the schema and handle the migration manually.
generating the schema:
```bash title="terminal"
npx auth generate
```
using the `migrate` command:
```bash title="terminal"
npx auth migrate
```
<Callout>
If you prefer adding the schema manually, you can check the schema required on the [two factor plugin](/docs/plugins/2fa#schema) documentation.
</Callout>
Once we're done with the server, we need to add the plugin to the client. To do this, you need to import the plugin and pass it to the `plugins` option of the auth client. For example, to add two factor authentication, you can use the following code:
```ts title="auth-client.ts"
import { createAuthClient } from "better-auth/client";
import { twoFactorClient } from "better-auth/client/plugins"; // [!code highlight]
const authClient = createAuthClient({
plugins: [ // [!code highlight]
twoFactorClient({ // [!code highlight]
twoFactorPage: "/two-factor" // the page to redirect if a user needs to verify 2nd factor // [!code highlight]
}) // [!code highlight]
] // [!code highlight]
})
```
now two factor related methods will be available on the client.
```ts title="profile.ts"
import { authClient } from "./auth-client"
const enableTwoFactor = async() => {
const data = await authClient.twoFactor.enable({
password // the user password is required
}) // this will enable two factor
}
const disableTwoFactor = async() => {
const data = await authClient.twoFactor.disable({
password // the user password is required
}) // this will disable two factor
}
const signInWith2Factor = async() => {
const data = await authClient.signIn.email({
//...
})
//if the user has two factor enabled, it will redirect to the two factor page
}
const verifyTOTP = async() => {
const data = await authClient.twoFactor.verifyTOTP({
code: "123456", // the code entered by the user
/**
* If the device is trusted, the user won't
* need to pass 2FA again on the same device
*/
trustDevice: true
})
}
```