Files
better-auth/docs/content/docs/basic-usage.mdx
2024-12-02 17:04:23 +03:00

522 lines
16 KiB
Plaintext

---
title: Basic Usage
description: Getting started with Better Auth
---
Better Auth provides built-in authentication support for:
- **Email and password**
- **Social provider (Google, GitHub, Apple, and more)**
<Callout>
You can extend authentication options using plugins, such as: Username-based login, Passkeys, Email magic links, and more.
</Callout>
## Email & Password
To enable email and password authentication:
```ts title="auth.ts"
import { betterAuth } from "better-auth"
export const auth = betterAuth({
//...rest of the options
emailAndPassword: { // [!code highlight]
enabled: true // [!code highlight]
} // [!code highlight]
})
```
### 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**
```tsx title="SignUp.tsx"
"use client"
import { authClient } from "@/lib/auth-client"; //import the auth client // [!code highlight]
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({ // [!code highlight]
email, // [!code highlight]
password, // [!code highlight]
name, // [!code highlight]
image: image ? convertImageToBase64(image) : undefined, // [!code highlight]
}, { // [!code highlight]
onRequest: (ctx) => { // [!code highlight]
//show loading // [!code highlight]
}, // [!code highlight]
onSuccess: (ctx) => { // [!code highlight]
//redirect to the dashboard // [!code highlight]
}, // [!code highlight]
onError: (ctx) => { // [!code highlight]
alert(ctx.error.message); // [!code highlight]
}, // [!code highlight]
}); // [!code highlight]
};
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`
```js
import { betterAuth } from "better-auth"
export const auth = betterAuth({
//...rest of the options
emailAndPassword: {
enabled: true,
autoSignIn: false //defaults to true // [!code highlight]
},
})
```
### 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**
```svelte title="signin.svelte"
<script lang="ts">
import { authClient } from "$lib/auth-client"; //import the auth client // [!code highlight]
import { writable } from "svelte/store";
const email = writable("");
const password = writable("");
const handleSignIn = async () => {
await authClient.signIn.email({ // [!code highlight]
email: $email, // [!code highlight]
password: $password, // [!code highlight]
}, { // [!code highlight]
onRequest: () => { // [!code highlight]
//show loading // [!code highlight]
}, // [!code highlight]
onSuccess: () => { // [!code highlight]
//redirect to dashboard // [!code highlight]
}, // [!code highlight]
onError: (ctx) => { // [!code highlight]
alert(ctx.error.message) // [!code highlight]
} // [!code highlight]
}) // [!code highlight]
}
</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.
```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { github } from "better-auth/social-providers"
export const auth = betterAuth({
//...rest of the options
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]
})
```
### 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 authenticates with the provider.
- **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**
```vue title="signin.vue"
<script>
import { authClient } from "@/auth-client"; //import the auth client // [!code highlight]
export default {
name: "SignIn",
methods: {
async handleSignIn() {
await authClient.signIn.social({ // [!code highlight]
provider: "github", // [!code highlight]
callbackURL: "/dashboard", //redirect to dashboard after sign in // [!code highlight]
}); // [!code highlight]
}
}
};
</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.
```ts title="user-card.tsx"
await authClient.signOut();
```
you can pass `fetchOptions` to redirect onSuccess
```ts title="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.
<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]
} = authClient.useSession() // [!code highlight]
return (
//...
)
}
```
</Tab>
<Tab value="Vue">
```vue title="index.vue"
<script setup lang="ts">
import { authClient } from "~/lib/auth-client" // [!code highlight]
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>
```
</Tab>
<Tab value="Svelte">
```svelte title="user.svelte"
<script lang="ts">
import { authClient } from "$lib/auth-client"; // [!code highlight]
const session = authClient.useSession(); // [!code highlight]
</script>
<p>
{$session.data?.user.email}
</p>
```
</Tab>
<Tab value="Vanilla">
```ts title="user.svelte"
import { authClient } from "~/lib/auth-client"; //import the auth client
authClient.useSession.subscribe((value)=>{
//do something with the session //
})
```
</Tab>
<Tab value="Solid">
```tsx title="user.tsx"
import { authClient } from "~/lib/auth-client"; // [!code highlight]
export default function Home() {
const session = authClient.useSession() // [!code highlight]
return (
<pre>{JSON.stringify(session(), null, 2)}</pre>
);
}
```
</Tab>
</Tabs>
<Callout>
For more details check [session-management](/docs/concepts/session-management) documentation.
</Callout>
### 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**
<Tabs items={["NextJs", "Nuxt", "Svelte", "Astro", "Hono", "TanStack"]}>
<Tab value="NextJs">
```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.
})
```
</Tab>
<Tab value="Remix">
```ts title="route.ts"
import { auth } from "lib/auth"; // path to your Better Auth server instance
export async function loader({ request }: LoaderFunctionArgs) {
const session = await auth.api.getSession({
headers: request.headers
})
return json({ session })
}
```
</Tab>
<Tab value="Astro">
```astro title="index.astro"
---
import { auth } from "./auth";
const session = await auth.api.getSession({
headers: Astro.request.headers,
});
---
<!-- Your Astro Template -->
```
</Tab>
<Tab value="Svelte">
```ts title="+page.ts"
import { auth } from "./auth";
export async function load({ request }) {
const session = await auth.api.getSession({
headers: request.headers
})
return {
props: {
session
}
}
}
```
</Tab>
<Tab value="Hono">
```ts title="index.ts"
import { auth } from "./auth";
const app = new Hono();
app.get("/path", async (c) => {
const session = auth.api.getSession({
headers: c.req.raw.headers
})
});
```
</Tab>
<Tab value="Nuxt">
```ts title="server/session.ts"
import { auth } from "~/utils/auth";
export default defineEventHandler((event) => {
const session = await auth.api.getSession({
headers: event.headers,
})
});
```
</Tab>
<Tab value="TanStack">
```ts title="app/routes/api/index.ts"
import { auth } from "./auth";
import { createAPIFileRoute } from "@tanstack/start/api";
export const Route = createAPIFileRoute("/api/$")({
GET: async ({ request }) => {
const session = await auth.api.getSession({
headers: request.headers
})
},
});
```
</Tab>
</Tabs>
## Using Plugins
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 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:
```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.
</Step>
<Step>
### 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:
```bash title="terminal"
npx @better-auth/cli generate
```
using the `migrate` command:
```bash title="terminal"
npx @better-auth/cli 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>
</Step>
<Step>
### 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:
```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 need 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
})
}
```
</Step>
<Step>
Next step: See the <Link href="/docs/plugins/2fa">the two factor plugin documentation</Link>.
</Step>
</Steps>