DEV Community

Daanish2003
Daanish2003

Posted on

OAuth using Better_Auth, nextjs, prisma, shadcn and tailwindcss

In this blog post, we'll explore how to set up OAuth authentication in a modern web application using a powerful stack that ensures efficiency, scalability, and developer productivity. By the end, you'll have a working OAuth system integrated into a full-stack application.

Tech Stack:

  • Better_Auth v1: A lightweight and extensible authentication library for TypeScript.
  • Next.js: A React framework for building server-rendered web applications.
  • Prisma: A modern ORM for database management.
  • Shadcn: A utility-first component library.
  • TailwindCSS: A popular utility-first CSS framework.

Prerequisites:

Before we begin, make sure you have the following tools installed:

  • Node.js (LTS version)
  • npm, yarn, or pnpm (package managers)
  • A PostgreSQL database instance (local or hosted, such as Supabase or PlanetScale). I'll be using Docker for local development
  • Basic knowledge of TypeScript, Next.js, and Prisma.

Step 1: Setting up your Next.js project

Create a New Project Directory:

Begin by creating a folder for your project and navigating into it via the terminal. Use the following commands:

mkdir better_auth_nextjs_oauth
cd better_auth_nextjs_oauth
Enter fullscreen mode Exit fullscreen mode

Install Next.js in the Directory:

Initialize a new Next.js project within the folder using the command below. You can use your preferred package manager (e.g., npm, yarn, or pnpm). For this guide, we'll use pnpm.

pnpx create-next-app@latest .
Enter fullscreen mode Exit fullscreen mode

💡Tip: If you don't have pnpm installed, visit pnpm.io and follow the instructions for your operating system.

Configure the Project Options:

Follow the prompts displayed in the terminal to configure your project. You will be asked to make selections such as enabling TypeScript, which is recommended for better type safety and development experience.

Use the arrow keys to navigate through the options and choose according to your preferences.

Image description

Step 2: Installing Dependencies

Install the necessary packages for the tech stack by running the following commands:

pnpm add better-auth@latest
pnpm add -D prisma
pnpm add @prisma/client
pnpm install react-icons --save
pnpm add oslo
Enter fullscreen mode Exit fullscreen mode

To install shadcn-ui, a utility-first component library, run the following command:

pnpm dlx shadcn@latest init
Enter fullscreen mode Exit fullscreen mode

This will set up shadcn-ui in your project, allowing you to start using its components right away.

When prompted, choose from the available options to customize your shadcn-ui setup. Follow the instructions in the terminal to select the components and configurations that best suit your project needs.

![Image description]](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x3l4jss12ft95ieuoef2.png)
To add reusable components from shadcn-ui, you can use the following command:

pnpx shadcn@latest add button card
Enter fullscreen mode Exit fullscreen mode

Step 3: Setting Up the Database (Local or Cloud)

Option 1: Local Development with Docker:

💡Tip: If you're using a cloud-based database provider like Neon or PlanetScale, you can skip this step and proceed to configure your database connection directly through their provided URLs.

Create a docker-compose.yml File

To set up a PostgreSQL database using Docker, create a docker-compose.yml file in your project’s root directory. This file will define the configuration for your database container.

Here's an example configuration for the docker-compose.yml file:

# docker-compose.yml
version: '3.9'
services:
  db:
    container_name: BETTER_AUTH_NEXTJS_OAUTH
    image: postgres:17-alpine
    restart: always
    ports:
      - 5432:5432
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_DB=OAUTH
volumes:
  postgres-data:
Enter fullscreen mode Exit fullscreen mode

This configuration sets up a PostgreSQL container with a persistent volume and environment variables for your database credentials.

Set Up Environment Variables for the Database

Create a .env file in the root of your project and define the necessary environment variables for your database connection. Here's an example configuration:

//.env
POSTGRES_PASSWORD="your_password_here"
POSTGRES_USER="your_username_here"
DATABASE_URL="postgresql://your_username_here:your_password_here@localhost:5432/mydb?schema=public"
Enter fullscreen mode Exit fullscreen mode
  • Replace your_password_here and your_username_here with your own PostgreSQL credentials.
  • DATABASE_URL should point to your local database or a cloud database if you are using a provider.

Run the Docker Container

Once you’ve configured the docker-compose.yml file and set up the environment variables, you can start the Docker container by running the following command:

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

This command will start the PostgreSQL container in detached mode (-d), ensuring your database is up and running in the background. You can now proceed with the rest of the setup in your Next.js application.

If you ever need to stop the container, you can use:

docker compose down
Enter fullscreen mode Exit fullscreen mode

Option 2: Using a Hosted Database

If you're using a cloud database provider (such as Neon, PlanetScale, or others), you can skip the local Docker setup. Instead, simply copy the provided Database URL from your cloud provider and add it to your .env file.

For example:

# .env
DATABASE_URL="postgresql://username:password@host:port/database_name?sslmode=require"
Enter fullscreen mode Exit fullscreen mode

Ensure that the DATABASE_URL contains the correct connection details such as your:

  • username
  • password
  • host (database server URL)
  • port (usually 5432 for PostgreSQL)
  • database_name

Once you've added the correct URL, your application will be able to connect to the hosted database seamlessly.

Step 4: Setting Up Prisma

Initialize Prisma CLI

This will create a new prisma folder in your project, containing the schema.prisma file and configuration for Prisma.

pnpm dlx prisma init
Enter fullscreen mode Exit fullscreen mode

This will create a new prisma folder in your project, containing the schema.prisma file and configuration for Prisma.

Configure the Database Connection:

Open the prisma/schema.prisma file and ensure that the DATABASE_URL points to your PostgreSQL database. It should look something like this:

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}
Enter fullscreen mode Exit fullscreen mode

Prisma will automatically read the DATABASE_URL from your .env file.

Create a Database Folder

Inside the src directory of your project, create a folder named db. This will house all database-related files.

Create a Database Client File

Inside the db folder, create a file named index.ts. Add the following code to configure and export a singleton instance of the Prisma Client:

// src/db/index.ts
import { PrismaClient } from '@prisma/client'

const prismaClientSingleton = () => {
  return new PrismaClient()
}

declare const globalThis: {
  prismaGlobal: ReturnType<typeof prismaClientSingleton>;
} & typeof global;

const prisma = globalThis.prismaGlobal ?? prismaClientSingleton()

export default prisma

if (process.env.NODE_ENV !== 'production') globalThis.prismaGlobal = prisma
Enter fullscreen mode Exit fullscreen mode

Create Schema for auth

In this step, you'll define a database schema to manage authentication-related data, such as users, sessions, accounts, and verification tokens.

  1. Open the prisma/schema.prisma file in your project.
  2. Replace its contents with the following schema:
// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id               String    @id @default(cuid())
  name             String
  email            String
  emailVerified    Boolean   @default(false)
  image            String?
  createdAt        DateTime  @default(now())
  updatedAt        DateTime  @updatedAt
  twoFactorEnabled Boolean   @default(false)
  Session          Session[]
  Account          Account[]

  @@unique([email])
  @@map("user")
}

model Session {
  id        String   @id @default(cuid())
  expiresAt DateTime
  token     String   @unique
  ipAddress String?
  userAgent String?
  userId    String
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@map("session")
}

model Account {
  id           String    @id @default(cuid())
  accountId    String
  providerId   String
  userId       String
  user         User      @relation(fields: [userId], references: [id], onDelete: Cascade)
  accessToken  String?
  refreshToken String?
  idToken      String?
  expiresAt    DateTime?
  password     String?
  createdAt    DateTime  @default(now())
  updatedAt    DateTime  @updatedAt

  accessTokenExpiresAt  DateTime?
  refreshTokenExpiresAt DateTime?
  scope                 String?

  @@map("account")
}

model Verification {
  id         String    @id @default(cuid())
  identifier String
  value      String
  expiresAt  DateTime
  createdAt  DateTime? @default(now())
  updatedAt  DateTime? @updatedAt

  @@map("verification")
}
Enter fullscreen mode Exit fullscreen mode

Explanation of the Schema

  • User: Contains basic user information and manages relationships to Account and Session models.
  • Session: Tracks user sessions, including tokens, IP addresses, and user agents.
  • Account: Manages linked OAuth accounts for third-party login providers such as Google or GitHub.
  • Verification: Handles email or token-based verification (e.g., passwordless login or two-factor authentication).

Generate and Migrate the Prisma Schema

After defining your models in the schema.prisma file, you need to generate the Prisma client and apply the database migrations.

  1. Generate Prisma Client

    First, generate the Prisma Client, which provides an API to interact with your database:

pnpx prisma generate
Enter fullscreen mode Exit fullscreen mode

This will generate the necessary client files for accessing the database from your application.

  1. Run Migrations

Apply the migrations to your database by running the following command:

pnpx prisma migrate dev --name auth
Enter fullscreen mode Exit fullscreen mode

This will apply the migration to your database and generate the required tables (e.g., for User, Session, Account, etc.).

Once this setup is complete, Prisma will be ready to use for querying your database in your application.

Step-4: Integrate Better_Auth

Setting Up Environment Variables:

Add the following configuration to your .env file to provide the necessary environment variables for authentication:

# General authentication settings
BETTER_AUTH_SECRET="your-secret-key" # Replace with your own secure key or generate one using "pnpm dlx auth secret"
BETTER_AUTH_URL="http://localhost:3000" # Base URL of your app during local development
NEXT_PUBLIC_APP_URL="http://localhost:3000" # Public-facing base URL of your app

# Google OAuth credentials
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"

# GitHub OAuth credentials
GITHUB_CLIENT_ID="your-github-client-id"
GITHUB_CLIENT_SECRET="your-github-client-secret"

Enter fullscreen mode Exit fullscreen mode

Explanation:

  • BETTER_AUTH_SECRET: A secret key used by Better_Auth for signing JWTs. You can generate one using pnpm dlx auth secret.
  • BETTER_AUTH_URL: The base URL for your application (used for redirecting after authentication).
  • Google and GitHub OAuth credentials: Replace the placeholders with the actual Client ID and Client Secret you obtain from Google and GitHub developer portals. Ensure the redirect URIs match the paths configured in your OAuth provider’s settings.
  • NEXT_PUBLIC_APP_URL: The public URL of your app, which is used for client-side requests.

Notes on Obtaining OAuth Credentials:

For Google OAuth

  1. Go to the Google Cloud Console.
  2. Navigate to Credentials > Create Credentials > OAuth 2.0 Client IDs.
  3. Under Authorized Redirect URIs, set the following:

    • For local development: http://localhost:3000/api/auth/callback/google
    • For production: Use your application's domain, e.g., https://example.com/api/auth/callback/google.
    💡⚠️ If you change the base path of your auth routes, update the redirect URI accordingly.

For GitHub OAuth

  1. Visit the GitHub Developer Settings.
  2. Create a new OAuth App under Developer Applications.
  3. Set the following redirect URIs:

    • For local development: http://localhost:3000/api/auth/callback/github
    • For production: Use your application's domain, e.g., https://example.com/api/auth/callback/github.
    💡⚠️ Similar to Google, update the redirect URI if your auth route base path changes.

💡### Why These Redirect URIs Matter

The redirect URIs are critical for OAuth authentication. They specify the exact location where the OAuth provider (Google or GitHub) should send users after they authenticate. Make sure the URIs you provide in the OAuth configuration match exactly with those used in your application; otherwise, the authentication process will fail.

Setting Up the Authentication Configuration:

  • Create the auth.ts File

    Inside the lib folder of your project, create a file named auth.ts. This file will contain the configuration for Better_Auth.

  • Add the Following Code

    Copy and paste the code below into the auth.ts file:

// auth.ts
import prisma from '@/db';
import {
    betterAuth
} from 'better-auth';
import { prismaAdapter } from 'better-auth/adapters/prisma';

export const auth = betterAuth({
    appName: "better_auth_nextjs",
    database: prismaAdapter(prisma, {
        provider: "postgresql"
    }),
    socialProviders: {
        google: {
            clientId: process.env.GOOGLE_CLIENT_ID!,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
            redirectURI: process.env.BETTER_AUTH_URL + "/api/auth/callback/google",
        },
        github: {
            clientId: process.env.GITHUB_CLIENT_ID!,
            clientSecret: process.env.GITHUB_CLIENT_SECRET!,
            redirectURI: process.env.BETTER_AUTH_URL + "/api/auth/callback/github",
        }
    },
});
Enter fullscreen mode Exit fullscreen mode

Explanation of the Code:

  1. betterAuth: Initializes the authentication library with the following parameters:
    • appName: Specifies the name of your application.
    • database: Connects the Prisma adapter to the PostgreSQL database defined in your .env file.
    • socialProviders: Configures Google and GitHub OAuth providers.
  2. Dynamic Redirect URIs:
    • The redirectURI dynamically appends the callback path to the base URL (BETTER_AUTH_URL) defined in your environment variables. This ensures compatibility with both local and production environments.

Setting Up the Authentication Client

  • Create the auth-client.ts File

    Inside the lib folder, create a new file named auth-client.ts. This file will manage client-side authentication interactions.

  • Add the Following Code

    Paste the code below into the newly created file:

// src/lib/auth-client.ts
import {
    createAuthClient
} from "better-auth/react";

export const authClient = createAuthClient({
    baseURL: process.env.NEXT_PUBLIC_APP_URL,

})

export const {
    signIn,
    signOut,
    signUp,
    useSession
} = authClient;
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • createAuthClient:
    • This function initializes the client-side authentication logic using Better_Auth.
    • The baseURL is sourced from the NEXT_PUBLIC_APP_URL environment variable, ensuring compatibility with both local and production environments.
  • Exported Methods:

    • signIn: Initiates the sign-in process for users.
    • signOut: Logs the user out.
    • signUp: Handles user registration.
    • useSession: Retrieves and manages the current user's authentication session.

    💡 Why This File is Important

    The auth-client.ts file abstracts client-side authentication functions, making them reusable and straightforward to integrate into React components. By centralizing the authentication logic, you maintain cleaner code and enhance the maintainability of your project.

Creating an API Route Handler for Authentication

To handle authentication API requests, you'll need to set up a route handler in your application. This will process all requests directed to the /api/auth/* endpoint (or any custom base path you configure).

  1. Create the Route Handler

    In your framework's designated directory for API routes (e.g., /app/api/auth for Next.js), create a catch-all route handler to manage authentication requests.

  2. Add the Following Code

    For a Next.js application, create a file named route.ts inside the /app/api/auth/[...all] directory and paste the following code:

// /app/api/auth/[...all]/route.ts
import { auth } from "@/lib/auth"; // path to your auth file
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth);
Enter fullscreen mode Exit fullscreen mode

Explanation:

  1. toNextJsHandler:
    • Converts the Better_Auth configuration into route handlers compatible with Next.js.
    • Automatically sets up handlers for the HTTP methods (e.g., POST and GET) required for authentication.
  2. Catch-All Route (/api/auth/*):
    • Ensures that all authentication-related requests (e.g., sign-in, callbacks) are routed through this handler.
    • This centralizes your authentication logic for better maintainability.

💡 Why This Setup is Necessary

By creating this route handler:

  • You streamline the handling of authentication-related API requests.
  • The /api/auth/* endpoint acts as a dedicated entry point for Better_Auth to manage user sessions, social logins, and other auth operations.

Step 5: Create Sign-In Component

Create a Reusable CardWrapper Component

To improve modularity and reusability, let's create a CardWrapper component. This component will wrap content inside a styled card layout, making it easy to display various types of content consistently throughout the app.

Here’s the improved version of the CardWrapper component:

import React from 'react'
import { Card, CardContent, CardDescription, cardHeader, CardTitle } from './ui/card'
import Link from 'next/link'

interface CardWrapperType {
    children: React.ReactNode,
    cardTitle: string,
    cardDescription: string
}

const CardWrapper = ({
    children,
    cardTitle,
    cardDescription,
}: CardWrapperType) => {
    return (
        <Card className="w-[400px] relative">
            <CardHeader>
                <CardTitle>{cardTitle}</CardTitle>
                <CardDescription>{cardDescription}</CardDescription>
            </CardHeader>
            <CardContent>
                {children}
            </CardContent>
         </Card>
    )
}

export default CardWrapper
Enter fullscreen mode Exit fullscreen mode

Explanation:

  1. Component Structure:
    • children: This is the content that will be rendered inside the card.
    • cardTitle: The title of the card, which will be prominently displayed at the top.
    • cardDescription: A brief description under the title that provides more context for the card.
  2. Styling:
    • The Card container has utility classes like w-full, max-w-md, mx-auto, bg-white, rounded-lg, and shadow-md to control the width, margin, background color, border radius, and shadow of the card. This ensures the card looks well-aligned, centered, and visually distinct.
    • Inside the card header, the CardTitle and CardDescription have additional styling for text size, weight, and color to improve readability and contrast.
  3. Modularity:
    • By separating the card layout into its own reusable component (CardWrapper), it becomes easy to reuse this structure throughout the app wherever you need a card with a title and description. This promotes consistency in the design and reduces code duplication.

Create FormError and FormSuccess Components:

To improve error and success message handling in forms, let's create reusable components for displaying error and success messages.

  1. FormError Component:

    The `FormError` component will display error messages with an icon and a      styled container to alert the user.
    
// app/components/form-error.tsx
import React from 'react'
import { AiFillExclamationCircle } from "react-icons/ai";

type FormErrorProps = {
    message?: string
}

const FormError = ({message}: FormErrorProps) => {
    if (!message) return null
  return (
    <div className="bg-destructive/15 p-3 rounded-md flex items-center gap-x-2 text-sm text-destructive">
        <AiFillExclamationCircle className='w-4 h-4'/>
        {message}
    </div>
  )
}

export default FormError
Enter fullscreen mode Exit fullscreen mode

Explanation:

  1. Props:
    • message: A string containing the error message that will be displayed. If no message is provided, the component returns null.
  2. Styling:

    • bg-red-100: Light red background for the error message.
    • text-red-600: Red text color for visibility and to emphasize the error.
    • p-3: Padding inside the message box.
    • rounded-md: Rounded corners for a smooth appearance.
    • flex items-center gap-x-2: A flex container with horizontal spacing between the icon and the message text.
    • The AiFillExclamationCircle icon is used to represent the error visually.
  3. FormSuccess Component:

The FormSuccess component is similar to the FormError, but it's used for success messages.

// app/components/form-success.tsx
import React from 'react'
import { AiFillExclamationCircle } from "react-icons/ai";

type FormErrorProps = {
    message?: string
}

const FormError = ({message}: FormErrorProps) => {
    if (!message) return null
  return (
    <div className="bg-destructive/15 p-3 rounded-md flex items-center gap-x-2 text-sm text-destructive">
        <AiFillExclamationCircle className='w-4 h-4'/>
        {message}
    </div>
  )
}

export default FormError
Enter fullscreen mode Exit fullscreen mode

Explanation:

  1. Props:
    • message: A string containing the success message to be displayed. If no message is provided, the component returns null.
  2. Styling:
    • bg-green-100: Light green background to indicate success.
    • text-green-600: Green text color to match the success color scheme.
    • p-3: Padding inside the message box for better spacing.
    • rounded-md: Rounded corners for a sleek and modern design.
    • flex items-center gap-x-2: Flexbox container with horizontal spacing between the success icon and message text.
    • The AiFillCheckCircle icon represents a successful action.

Create the sign-in.tsx file

Inside the components/auth folder, create a new file named sign-in.tsx. This file will contain the component responsible for rendering the sign-in UI and handling the authentication logic.

Here's how to structure your component:

// components/auth/sign-in.tsx
"use client"
import React, { useEffect, useState } from 'react'
import { Button } from '../ui/button'
import CardWrapper from '../card-wrapper'import { FaGithub } from 'react-icons/fa'
import { FcGoogle } from 'react-icons/fc'
import { signIn } from '@/lib/auth-client'
import FormError from '../form-error'
import { FormSuccess } from '../form-success'
import { useRouter } from 'next/navigation'

const SignIn = () => {
    const router = useRouter()
    const [error, setError] = useState("")
    const [success, setSuccess] = useState("")
    const [loading, setLoading] = useState(false)

    useEffect(() => {
        setError("")
        setSuccess("")
        setLoading(false)
    }, [])

    const githubSignIn = async () => {
        try {
            await signIn.social({
                provider: "github",
                callbackURL: "/"
            }, {
                onResponse: () => {
                    setLoading(false)
                },
                onRequest: () => {
                    setSuccess("")
                    setError("")
                    setLoading(true)
                },
                onSuccess: () => {
                    setSuccess("Your are loggedIn successfully")
                },
                onError: (ctx) => {
                    setError(ctx.error.message)
                }
            })
        } catch (error: unknown) {
            console.log(error)
            setError("Something went wrong")
        }
    }

    const googleSignIn = async () => {
        try {
            await signIn.social({
                provider: "google"
            }, {
                onResponse: () => {
                    setLoading(false)
                },
                onRequest: () => {
                    setSuccess("")
                    setError("")
                    setLoading(true)
                },
                onSuccess: () => {
                    setSuccess("Your are loggedIn successfully")
                    router.replace('/')
                },
                onError: (ctx) => {
                    setError(ctx.error.message)
                }
            })
        } catch (error: unknown) {
            console.error(error)
            setError("Something went wrong")
        }
    }

    return (
        <CardWrapper
            cardTitle='Sign In'
            cardDescription='Enter your email below to login to your account'
        >
            <div className='flex gap-y-2 flex-col'>
                <FormError message={error} />
                <FormSuccess message={success} />
                <Button
                    variant={"outline"}
                    onClick={githubSignIn}
                    disabled={loading}
                >
                    <FaGithub />
                    Sign in With Github
                </Button>
                <Button
                    variant={"outline"}
                    onClick={googleSignIn}
                    disabled={loading}
                >
                    <FcGoogle />
                    Sign in with Google
                </Button>
            </div>
        </CardWrapper>
    )
}

export default SignIn
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • State management: The component uses useState for managing error, success, and loading states.
  • OAuth sign-in: The githubSignIn and googleSignIn functions handle authentication with GitHub and Google respectively. They use the signIn.social method from the auth-client.ts file.
  • Form feedback: FormError and FormSuccess components display any errors or success messages during the sign-in process.
  • UI: The Button component is used to create sign-in buttons for GitHub and Google. The buttons are disabled while the sign-in process is in progress

This component will handle the authentication process and provide users with an interface to sign in using their Google or GitHub accounts.

Create the sign-in folder

Inside the app folder, create a new folder named sign-in. This folder will contain the page and components related to the sign-in process.

Create the page.tsx file

Inside the sign-in folder, create a new file named page.tsx. This will be the main page that renders the sign-in component and handles the routing logic

Here's how to structure the page.tsx file:

// /app/signin/page.tsx
import SignIn from '@/components/auth/sign-in'
import React from 'react'

const SignInPage = () => {
  return (
    <SignIn />
  )
}

export default SignInPage
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Component Import: The SignIn component from components/auth/sign-in is imported and used to display the sign-in form.
  • Styling: The min-h-screen, bg-gray-50, flex, justify-center, and items-center utility classes are used to center the sign-in form vertically and horizontally, ensuring a clean and responsive layout. The max-w-md class is applied to restrict the width of the sign-in form to a medium size for better presentation on different screen sizes.

Now, when you navigate to /sign-in in your application, it will render the sign-in page with the form and authentication options.

Create a Layout for the Sign-In Page

To ensure consistency in the design and layout of the sign-in page, you can create a layout.tsx file inside the sign-in folder. This layout will serve as a wrapper for the sign-in page and allow you to manage common elements like headers, footers, or sidebars if needed in the future.

Here’s how to structure the layout.tsx file:

import React from 'react'

const SignupLayout = ({children}: {children: React.ReactNode}) => {
  return (
    <div className='flex items-center justify-center w-screen h-screen'>{children}</div>
  )
}

export default SignupLayout
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Layout Component: The SignInLayout component wraps the entire sign-in page content (children). This layout is useful for organizing the structure of the page and allows for consistent styling and placement of content.
  • Styling: The layout applies utility classes like min-h-screen, bg-gray-50, flex, justify-center, and items-center to center the content both vertically and horizontally on the page. Additionally, the w-full max-w-md classes control the width of the container, while p-6, bg-white, rounded-lg, and shadow-lg provide padding, background color, rounded corners, and a shadow effect for a polished look.

Step 6 - Run the Application:

To start your development server and preview your application:

  1. Open your terminal and navigate to your project directory.
  2. Run the following command:
pnpm dev
Enter fullscreen mode Exit fullscreen mode

This command will launch the development server and make your application accessible at http://localhost:3000 by default. You can now test and view your application in the browser.

Once the development server is running, visit the following URL in your browser to access the sign-in page:

http://localhost:3000/signin
Enter fullscreen mode Exit fullscreen mode

This will load the sign-in page of your application, where you can test the OAuth authentication flow.

Image description
Congratulations! You have successfully integrated OAuth login into your application, providing users with a seamless and secure authentication experience. 🎉

If you enjoyed this blog, please consider following and supporting me! Your encouragement motivates me to create more helpful content for you. 😊

Reference Links:

Better_Auth Docs: https://www.better-auth.com/

pnpm Docs: https://pnpm.io/

Docker Docs: https://docs.docker.com/

Prisma Docs: https://www.prisma.io/docs/getting-started

Shadcn Docs: https://ui.shadcn.com/

Next.js Docs: https://nextjs.org/

Tailwindcss Docs: https://tailwindcss.com/

Github repository: https://github.com/Daanish2003/better_auth_nextjs

Top comments (0)