Docs

Basic Usage

Better Auth provides built-in authentication support for:

  • Email and password
  • Social provider (Google, GitHub, Apple, and more)

You can extend authentication options using plugins, such as: Username-based login, Passkeys, Email magic links, and more.

Email & Password

To enable email and password authentication:

auth.ts
import { betterAuth } from "better-auth"
 
export const auth = betterAuth({
    //...rest of the options
    emailAndPassword: {    
        enabled: true
    } 
})

Sign Up

Before a user can sign in, they need to sign up. To sign up a user using email and password, you need to call the client method signUp.email with the user's information.

You can pass the following properties to the signUp.email method:

  • email: the user's email address
  • password: the user's password
  • name: the user's display name
  • image: the user's image url (optional)
  • callbackURL: a callbackURL if email verification is enabled.

Example: Using React

SignUp.tsx
"use client"
import { authClient } from "@/lib/auth-client"; //import the auth client
import { useState } from 'react';
 
export default function SignUp() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [name, setName] = useState('');
  const [image, setImage] = useState<File | null>(null);
 
  const signUp = async () => {
    const { data, error } = await authClient.signUp.email({ 
        email, 
        password, 
        name, 
        image: image ? convertImageToBase64(image) : undefined, 
     }, { 
        onRequest: (ctx) => { 
         //show loading
        }, 
        onSuccess: (ctx) => { 
          //redirect to the dashboard
        }, 
        onError: (ctx) => { 
          alert(ctx.error.message); 
        }, 
      }); 
  };
 
  return (
    <div>
      <input type="name" value={name} onChange={(e) => setName(e.target.value)} />
      <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
      <input type="file" onChange={(e) => setImage(e.target.files?.[0])} />
      <button onClick={signUp}>Sign Up</button>
    </div>
  );
}

By default, the user is automatically signed in after signing up. This behaviour can be changed by configuring your auth-config

import { betterAuth } from "better-auth"
 
export const auth = betterAuth({
    //...rest of the options
    emailAndPassword: {
    	enabled: true,
    	autoSignIn: false //defaults to true
  },
})

Sign In

To sign a user in, you can use the signIn.email function provided by the client. The signIn function takes an object with the following properties:

  • email: the user's email address
  • password: the user's password

Example: Using Svelte

signin.svelte
<script lang="ts">
import { authClient } from "$lib/auth-client"; //import the auth client
import { writable } from "svelte/store";
 
const email = writable("");
const password = writable("");
 
const handleSignIn = async () => {
    await authClient.signIn.email({ 
        email: $email, 
        password: $password, 
    }, { 
        onRequest: () => { 
            //show loading
        }, 
        onSuccess: () => { 
            //redirect to dashboard
        }, 
        onError: (ctx) => { 
            alert(ctx.error.message) 
        } 
    }) 
}
</script>
 
<div>
    <input type="email" bind:value={$email} />
    <input type="password" bind:value={$password} />
    <button on:click={handleSignIn}>
      Sign In
    </button>
</div>

Social Sign-On

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.

auth.ts
import { betterAuth } from "better-auth"
import { github } from "better-auth/social-providers"
 
export const auth = betterAuth({
    //...rest of the options
    socialProviders: { 
        github: { 
            clientId: process.env.GITHUB_CLIENT_ID!, 
            clientSecret: process.env.GITHUB_CLIENT_SECRET!, 
        } 
    }, 
})

Signin with social providers

To sign in using a social provider you need to call signIn.social. It takes an object with the following properties:

  • provider: the social provider name (e.g. github, google, apple, etc.)
  • callbackURL: the URL to redirect to after the user signs in.
  • errorCallbackURL: the URL to redirect to if an error occurs during the sign in process.
  • disableRedirect: a boolean to disable the automatic redirect to the provider. This is useful when you want to show for example a popup.

and more options to do idToken authentication.

Example: Using Vue

signin.vue
<script>
import { authClient } from "@/auth-client"; //import the auth client
 
export default {
  name: "SignIn",
  methods: {
    async handleSignIn() {
        await authClient.signIn.social({ 
            provider: "github", 
            callbackURL: "/dashboard", //redirect to dashboard after sign in
        }); 
    }
  }
};
</script>
 
<template>
  <div>
    <h2>Sign In</h2>
    <button @click="handleSignIn">Sign In with GitHub</button>
  </div>
</template>

Signout

To signout a user, you can use the signOut function provided by the client.

user-card.tsx
await authClient.signOut();

you can pass fetchOptions to redirect onSuccess

user-card.tsx
await authClient.signOut({
  fetchOptions: {
    onSuccess: () => {
      router.push("/login"); // redirect to login page
    },
  },
});

Session Management

Once a user is signed in, you'll want to access the user session. Better Auth allows you easily to access the session data from the server and client side.

Client Side

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.

It has the following properties:

  • data: the actual session data which includes session and user object.
  • isPending: a boolean that indicates whether the session is being loaded.
  • error: an error object that contains any errors that occurred while loading the session.
user.tsx
import { authClient } from "@/lib/auth-client" // import the auth client
 
export function User(){
 
    const { 
        data: session, 
        isPending, //loading state
        error //error object
    } = authClient.useSession() 
 
    return (
        //...
    )
}

For more details check session-management documentation.

Server Side

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

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.
})

Using Plugins

One of the unique features of Better Auth is a plugins ecosystem. It allows you to add complex auth realted functionilty with small lines of code.

Below is an example of how to add two factor authentication using two factor plugin.

Server Configuration

To 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:

auth.ts
import { betterAuth } from "better-auth"
import { twoFactor } from "better-auth/plugins"
 
export const auth = betterAuth({
    //...rest of the options
    plugins: [ 
        twoFactor() 
    ] 
})

now two factor related routes and method will be available on the server.

Migrate Database

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:

terminal
npx @better-auth/cli generate

using the migrate command:

terminal
npx @better-auth/cli migrate

If you prefer adding the schema manually, you can check the schema required on the two factor plugin documentation.

Client Configuration

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:

client.ts
import { createAuthClient } from "better-auth/client";
import { twoFactorClient } from "better-auth/client/plugins"; 
 
const authClient = createAuthClient({
    plugins: [ 
        twoFactorClient({ 
            twoFactorPage: "/two-factor" // the page to redirect if a user need to verify 2nd factor
        }) 
    ] 
})

now two factor related methods will be available on the client.

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
    })
}

On this page