Bhaskar-Guthula-137/React_BetterAuth_GoogleOAuth_Cloudflare_SQLite

โ˜… 0Forks 0TypeScriptGitHub โ†—Compare

README

๐Ÿ” React + Better Auth + Google OAuth + Cloudflare

A modern, full-stack authentication system built with React, Better Auth, and deployed on Cloudflare infrastructure. Features email whitelisting, Google OAuth, and a beautiful glassmorphic UI.

Sign In Preview

โœจ Features

๐ŸŽจ Modern UI/UX

  • Clean, minimalist sign-in page with glassmorphism design
  • Purple gradient background with smooth animations
  • Responsive design that works on all devices
  • Loading states and error handling with visual feedback

๐Ÿ”’ Secure Authentication

  • Google OAuth integration via Better Auth
  • Email whitelist system for controlled access
  • Secure cookie-based sessions with SameSite=None and secure flags
  • Custom error handling and user-friendly error pages

โ˜๏ธ Cloudflare-Powered Backend

  • Cloudflare Workers for serverless API
  • D1 SQLite database for data persistence
  • Drizzle ORM for type-safe database operations
  • Global edge network for low latency

๐Ÿ› ๏ธ Developer Experience

  • TypeScript for type safety across the stack
  • Hot module replacement with Vite
  • Automated database migrations with Drizzle Kit
  • Environment-based configuration

๐Ÿ—๏ธ Architecture

BaGOuthApp/
โ”œโ”€โ”€ ba-gouth-app/          # Frontend (React + Vite)
โ”‚   โ”œโ”€โ”€ src/
โ”‚   โ”‚   โ”œโ”€โ”€ routes/        # Page components
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ SignIn.tsx
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AuthError.tsx
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ Blog.tsx
โ”‚   โ”‚   โ””โ”€โ”€ lib/
โ”‚   โ”‚       โ””โ”€โ”€ auth-client.ts  # Better Auth client
โ”‚   โ””โ”€โ”€ package.json
โ”‚
โ””โ”€โ”€ ba-gouth-apis/         # Backend (Cloudflare Workers + Hono)
    โ”œโ”€โ”€ src/
    โ”‚   โ”œโ”€โ”€ index.ts       # API routes & auth configuration
    โ”‚   โ””โ”€โ”€ schemas/       # Drizzle ORM schemas
    โ”œโ”€โ”€ migrations/        # Database migrations
    โ””โ”€โ”€ package.json

๐Ÿš€ Getting Started

Prerequisites

1. Clone the Repository

git clone https://github.com/Shisui-Genjutsu/React_BetterAuth_GoogleOAuth_Cloudflare_SQLite.git
cd React_BetterAuth_GoogleOAuth_Cloudflare_SQLite

2. Setup Backend (ba-gouth-apis)

cd ba-gouth-apis
bun install  # or npm install

Configure Environment Variables

Create a wrangler.jsonc file:

{
  "name": "ba-gouth-apis",
  "main": "src/index.ts",
  "compatibility_date": "2024-01-01",
  "vars": {
    "CLOUDFLARE_BASE_URL": "https://your-worker.workers.dev",
    "CLOUDFLARE_FRONTEND_BASE_URL": "https://your-app.pages.dev"
  },
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "ba-gouth-db",
      "database_id": "your-database-id"
    }
  ],
  "secrets": [
    "GOOGLE_CLIENT_ID",
    "GOOGLE_CLIENT_SECRET"
  ]
}

Setup Google OAuth

  1. Go to Google Cloud Console
  2. Create a new project or select an existing one
  3. Enable Google+ API
  4. Create OAuth 2.0 credentials:
    • Authorized JavaScript origins: http://localhost:5173, https://your-app.pages.dev
    • Authorized redirect URIs: https://your-worker.workers.dev/api/auth/callback/google

Add Secrets to Cloudflare

npx wrangler secret put GOOGLE_CLIENT_ID
npx wrangler secret put GOOGLE_CLIENT_SECRET

Create D1 Database

npx wrangler d1 create ba-gouth-db

Copy the database ID to your wrangler.jsonc.

Run Migrations

bun run db:generate  # Generate migrations
bun run db:push      # Apply to local DB
npx wrangler d1 execute ba-gouth-db --remote --file=./migrations/0000_*.sql
npx wrangler d1 execute ba-gouth-db --remote --file=./migrations/0001_*.sql

Add Whitelisted Emails

npx wrangler d1 execute ba-gouth-db --remote --command="INSERT INTO allowed_emails (id, email, created_at) VALUES ('uuid-here', '[email protected]', datetime('now'))"

Deploy Backend

bun run deploy

3. Setup Frontend (ba-gouth-app)

cd ../ba-gouth-app
bun install  # or npm install

Configure Environment Variables

Create a .env file:

VITE_BETTER_AUTH_URL=https://your-worker.workers.dev

Run Development Server

bun run dev

Visit http://localhost:5173/sign-in

Deploy Frontend

bun run deploy

๐Ÿ“Š Database Schema

user Table

  • id: User ID (primary key)
  • name: User's full name
  • email: User's email address
  • emailVerified: Email verification status
  • image: Profile picture URL
  • createdAt: Account creation timestamp
  • updatedAt: Last update timestamp

session Table

  • id: Session ID (primary key)
  • expiresAt: Session expiration time
  • token: Session token
  • ipAddress: User's IP address
  • userAgent: Browser user agent
  • userId: Foreign key to user table

account Table

  • id: Account ID (primary key)
  • accountId: OAuth provider account ID
  • providerId: OAuth provider (e.g., "google")
  • userId: Foreign key to user table
  • accessToken: OAuth access token
  • refreshToken: OAuth refresh token
  • expiresAt: Token expiration time

allowed_emails Table (Custom)

  • id: Record ID (primary key)
  • email: Whitelisted email address
  • created_at: Timestamp when email was added

๐Ÿ”ง Tech Stack

Frontend

  • React 19 - UI library
  • TypeScript - Type safety
  • Vite - Build tool and dev server
  • React Router 7 - Client-side routing
  • Better Auth Client - Authentication SDK

Backend

  • Cloudflare Workers - Serverless runtime
  • Hono - Lightweight web framework
  • Better Auth - Authentication framework
  • Drizzle ORM - Type-safe database toolkit
  • D1 - Cloudflare's SQLite database

๐ŸŽฏ Key Implementation Details

Email Whitelist Plugin

The backend uses a custom Better Auth plugin to enforce email whitelisting:

const emailWhitelistPlugin = (db: any) => ({
  id: "email-whitelist",
  init: (instance: any) => {
    return {
      options: {
        databaseHooks: {
          user: {
            create: {
              async before(user: any) {
                const email = user.email.toLowerCase()
                const allowedUser = await db.select()
                  .from(schema.allowedEmails)
                  .where(eq(schema.allowedEmails.email, email))
                  .limit(1)

                if (!allowedUser || allowedUser.length === 0) {
                  const error: any = new Error("unauthorized_email")
                  error.status = 403
                  throw error
                }
                return user
              }
            }
          }
        }
      }
    }
  }
})

CORS Configuration

Configured for cross-origin requests with credentials:

app.use(cors({
  origin: (origin, c) => {
    const allowedOrigins = [
      "http://localhost:5173",
      c.env.CLOUDFLARE_FRONTEND_BASE_URL
    ];
    return origin && allowedOrigins.some(allowed => origin.includes(allowed)) ? origin : null;
  },
  allowMethods: ['POST', 'GET', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization', 'cookie'],
  credentials: true,
  exposeHeaders: ["set-cookie"]
}))

๐Ÿ› Troubleshooting

"Email not authorized" Error

  • Ensure your email is added to the allowed_emails table in D1
  • Check that the email matches exactly (case-insensitive comparison is used)

CORS Errors

  • Verify CLOUDFLARE_FRONTEND_BASE_URL is set correctly in wrangler.jsonc
  • Check that your frontend URL is in the trustedOrigins array

Database Connection Issues

  • Confirm D1 database is created and bound correctly
  • Verify migrations have been applied to the remote database
  • Check database ID in wrangler.jsonc matches your D1 database

OAuth Redirect Issues

  • Ensure redirect URIs in Google Console match your worker URL exactly
  • Check that baseURL and basePath are configured correctly in Better Auth

๐Ÿ“ License

This project is open source and available under the MIT License.


๐Ÿค Contributing

Contributions, issues, and feature requests are welcome! Feel free to check the issues page.


๐Ÿ‘ค Author

Bhaskar G


โญ Show Your Support

Give a โญ๏ธ if this project helped you!


Error Handling

The application includes a dedicated error page for authentication failures with clear messaging and navigation options.


Built with โค๏ธ using React, Better Auth, and Cloudflare

Contributors

Bhaskar-Guthula-137

Issues