> ## Documentation Index
> Fetch the complete documentation index at: https://docs.jtbdos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Switch to Better Auth

> How to change the authentication provider to Better Auth.

export const Authors = ({data}) => {
  const baseUrl = typeof window !== 'undefined' && window.location.origin.includes('localhost') ? '' : 'https://raw.githubusercontent.com/haydenbleasel/JTBDOS/refs/heads/main/docs';
  return <div style={{
    marginBottom: '3rem',
    display: 'flex',
    flexDirection: 'column',
    gap: '0.5rem'
  }}>
      <span style={{
    color: 'rgb(107, 114, 128)',
    fontSize: '0.875rem'
  }}>Co-authored by</span>
      <div style={{
    display: 'flex',
    flexWrap: 'wrap',
    alignItems: 'center',
    gap: '0.5rem'
  }}>
        {data.map(author => <div key={author.name} style={{
    padding: '0.75rem',
    paddingRight: '1rem',
    display: 'inline-flex',
    alignItems: 'center',
    gap: '0.75rem',
    fontWeight: 'normal',
    position: 'relative',
    ringWidth: '2px',
    ringColor: 'transparent',
    borderRadius: '0.75rem',
    backgroundColor: 'white',
    border: '1px solid rgba(0,0,0,0.1)',
    overflow: 'hidden'
  }}>
            <div style={{
    position: 'relative'
  }}>
              <div style={{
    overflow: 'hidden',
    border: '1px solid #e5e7eb',
    borderRadius: '9999px',
    width: '2rem',
    height: '2rem'
  }}>
                <img style={{
    margin: 0,
    width: '100%',
    height: '100%',
    objectFit: 'cover'
  }} src={`${baseUrl}/images/authors/${author.company.id}/${author.user.id}.jpg`} alt="" width={32} height={32} />
              </div>
              <div style={{
    position: 'absolute',
    border: '1px solid white',
    overflow: 'hidden',
    borderRadius: '9999px',
    objectFit: 'cover',
    width: '1rem',
    height: '1rem',
    right: '-0.25rem',
    bottom: '-0.25rem'
  }}>
                <img style={{
    margin: 0,
    width: '100%',
    height: '100%',
    objectFit: 'cover'
  }} src={`${baseUrl}/images/authors/${author.company.id}/logo.jpg`} alt="" width={16} height={16} />
              </div>
            </div>
            <div style={{
    display: 'flex',
    flexDirection: 'column'
  }}>
              <span style={{
    fontWeight: 600,
    lineHeight: 1.25,
    fontSize: '13px',
    letterSpacing: '-0.01em'
  }}>
                {author.user.name}
              </span>
              <span style={{
    color: 'rgb(107, 114, 128)',
    lineHeight: 1.25,
    fontSize: '11px'
  }}>
                {author.company.name}
              </span>
            </div>
          </div>)}
      </div>
    </div>;
};

<Authors
  data={[{
user: {
name: 'Hayden Bleasel',
id: 'haydenbleasel',
},
company: {
name: 'JTBDOS',
id: 'JTBDOS',
},
}, {
user: {
name: 'Bereket Engida',
id: 'imbereket',
},
company: {
name: 'Better Auth',
id: 'better-auth',
},
}]}
/>

Better Auth is a comprehensive, open-source authentication framework for TypeScript. It is designed to be framework agnostic, but integrates well with Next.js and provides a lot of features out of the box.

## 1. Swap out the `auth` package dependencies

Uninstall the existing Clerk dependencies from the `auth` package...

```sh Terminal
pnpm remove @clerk/nextjs @clerk/themes @clerk/types --filter @repo/auth
```

...and install the Better Auth dependencies:

```sh Terminal
pnpm add better-auth @repo/database next --filter @repo/auth
```

## 2. Update your environment variables

Generate a secret with the following command to add it to the `.env.local` file in each Next.js application (`app`, `web` and `api`):

```sh Terminal
npx @better-auth/cli secret
```

This will add a `BETTER_AUTH_SECRET` environment variable to the `.env.local` file.

## 3. Setup the server and client auth

Update the `auth` package files with the following code:

<CodeGroup>
  ```ts packages/auth/server.ts
  import { betterAuth } from 'better-auth';
  import { nextCookies } from "better-auth/next-js";
  import { prismaAdapter } from "better-auth/adapters/prisma";
  import { database } from "@repo/database"

  export const auth = betterAuth({
    database: prismaAdapter(database, {
      provider: 'postgresql',
    }),
    plugins: [
      nextCookies()
      // organization() // if you want to use organization plugin
    ],
    //...add more options here
  });
  ```

  ```ts packages/auth/client.ts
  import { createAuthClient } from 'better-auth/react';

  export const { signIn, signOut, signUp, useSession } = createAuthClient();
  ```
</CodeGroup>

Read more in the Better Auth [installation guide](https://www.better-auth.com/docs/installation).

## 4. Update the auth components

Update both the `sign-in.tsx` and `sign-up.tsx` components in the `auth` package to use the `signIn` and `signUp` functions from the `client` file.

<CodeGroup>
  ```tsx packages/auth/components/sign-in.tsx
  "use client";

  import { signIn } from '../client';
  import { useState } from 'react';

  export const SignIn = () => {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");

    return (
      <form
        onSubmit={async (e) => {
          e.preventDefault();
          await signIn.email({
            email,
            password,
            name
          })
        }}
      >
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
        <button type="submit">Sign in</button>
      </form>
    );
  }
  ```

  ```tsx packages/auth/components/sign-up.tsx
  "use client";

  import { signUp } from '../client';
  import { useState } from 'react';

  export const SignUp = () => {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [name, setName] = useState("");

    return (
      <form
        onSubmit={async (e) => {
          e.preventDefault();
          await signUp.email({
            email,
            password,
            name
          })
        }}
      >
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
        <button type="submit">Sign up</button>
      </form>
    );
  }
  ```
</CodeGroup>

You can use different sign-in methods like social providers, phone, username etc. Read more about Better Auth [basic usage](https://better-auth.com/docs/basic-usage).

## 5. Generate Prisma Models

From the root folder, generate Prisma models for Better Auth by running the following command:

```sh Terminal
npx @better-auth/cli generate --output ./packages/database/prisma/schema.prisma --config ./packages/auth/server.ts
```

<Warning>
  You may have to comment out the `server-only` directive in `packages/database/index.ts` temporarily. Ensure you have environment variables set.
</Warning>

<Note>
  Best practice is to have a `better-auth.ts` file, but we're just specifying the existing `server.ts` left over from Clerk here.
</Note>

## 6. Update the Provider file

Better Auth has no concept of a Provider as a higher-order component, so you can either remove it entirely or just replace it with a stub, like so:

```tsx packages/auth/provider.tsx
import type { ReactNode } from 'react';

type AuthProviderProps = {
  children: ReactNode;
};

export const AuthProvider = ({ children }: AuthProviderProps) => children;
```

## 7. Change Middleware

Change the middleware in the `auth` package to the following:

```tsx packages/auth/middleware.ts
import type { NextRequest } from "next/server";
import { NextResponse } from 'next/server';

const isProtectedRoute = (request: NextRequest) => {
  return request.url.startsWith("/dashboard"); // change this to your protected route
}

export const authMiddleware = async (request: NextRequest) => {
  const url = new URL('/api/auth/get-session', request.nextUrl.origin);
  const response = await fetch(url, {
    headers: {
      cookie: request.headers.get('cookie') || '',
    },
  });

  const session = await response.json();
  
  if (isProtectedRoute(request) && !session) {
    return NextResponse.redirect(new URL("/sign-in", request.url));
  }
  
  return NextResponse.next();
}
```

## 8. Update your apps

From here, you'll need to replace any remaining Clerk implementations in your apps with Better Auth.

Here is some inspiration:

```tsx
const user = await currentUser();
const { redirectToSignIn } = await auth();

// to

const session = await auth.api.getSession({
  headers: await headers(), // from next/headers
});
if (!session?.user) {
  return redirect('/sign-in'); // from next/navigation
}
// do something with session.user
```

```tsx
const { orgId } = await auth();

// to

const h = await headers(); // from next/headers
const session = await auth.api.getSession({
  headers: h,
});
const orgId = session?.session.activeOrganizationId;
const fullOrganization = await auth.api.getFullOrganization({
  headers: h,
  query: { organizationId: orgId },
});
```

```tsx webhooks/stripe/route.ts
import { clerkClient } from '@repo/auth/server';

const clerk = await clerkClient();
const users = await clerk.users.getUserList();
const user = users.data.find(
  (user) => user.privateMetadata.stripeCustomerId === customerId
);

// to

import { database } from '@repo/database';

const user = await database.user.findFirst({
  where: {
    privateMetadata: {
      contains: { stripeCustomerId: customerId },
    },
  },
});
```

For using organization, check [organization plugin](https://better-auth.com/docs/plugins/organization) and more from the [Better Auth documentation](https://better-auth.com/docs).
