Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/paramveer-cyber/Deployaar/llms.txt

Use this file to discover all available pages before exploring further.

Deployaar uses better-auth with a Drizzle/PostgreSQL adapter for all authentication. It supports three sign-in methods: email and password, Google OAuth, and GitHub OAuth. All auth routes are served under /api/auth/* on the Express API server — the Next.js web app never handles auth itself. The trustedOrigins list is set to [NEXT_PUBLIC_WEB_URL] so that better-auth accepts cookie-setting requests that originate from the frontend domain.

Auth Routes

better-auth automatically mounts the following endpoints at startup. All routes are prefixed with /api/auth:
MethodPathDescription
POST/api/auth/sign-in/emailEmail and password sign-in. Returns a session cookie on success
POST/api/auth/sign-up/emailEmail and password registration. Creates a new user and session
GET/api/auth/sign-in/googleInitiates the Google OAuth flow. Redirects to accounts.google.com
GET/api/auth/callback/googleGoogle OAuth callback. Verifies state, exchanges code for tokens, creates session
GET/api/auth/sign-in/githubInitiates the GitHub OAuth flow. Redirects to github.com/login/oauth/authorize
GET/api/auth/callback/githubGitHub OAuth callback. Verifies state, exchanges code for tokens, creates session
GET/api/auth/get-sessionReturns the currently authenticated session, or null if unauthenticated
POST/api/auth/sign-outInvalidates the current session and clears the session cookie

Setting Up Google OAuth

1

Open Google Cloud Console

Go to console.cloud.google.com and navigate to APIs & Services → Credentials.
2

Create an OAuth 2.0 Client ID

Click Create Credentials → OAuth 2.0 Client ID. Choose Web application as the application type and give it a name.
3

Add the Authorized Redirect URI

Under Authorized redirect URIs, add:
{BETTER_AUTH_URL}/api/auth/callback/google
Replace {BETTER_AUTH_URL} with your actual API public URL. For local development this is http://localhost:8000/api/auth/callback/google. For production it is https://deployaar.onrender.com/api/auth/callback/google.
4

Copy the Credentials

After saving, copy the Client ID and Client Secret into your environment:
GOOGLE_CLIENT_ID=123456789-abc.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxx

Setting Up GitHub OAuth

This is a GitHub OAuth App, used only for authenticating users into Deployaar. It is entirely separate from the GitHub App that Deployaar installs on repositories to read code and open pull requests. They have different credentials and serve different purposes.
1

Create a New OAuth App

Go to GitHub → Settings → Developer Settings → OAuth Apps → New OAuth App.
2

Set the Homepage URL

Set Homepage URL to your web app’s public URL. For example: https://deployaar.paramveer.xyz.
3

Set the Authorization Callback URL

Set Authorization callback URL to:
{BETTER_AUTH_URL}/api/auth/callback/github
Replace {BETTER_AUTH_URL} with your API’s public URL. For local development this is http://localhost:8000/api/auth/callback/github.
4

Copy the Credentials

After registering the app, copy the Client ID and generate a Client Secret, then add them to your environment:
GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxxxxxx
GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Critical Environment Variables

Getting these values wrong is the most common cause of broken auth in Deployaar. Review them carefully before deploying.
  • BETTER_AUTH_URL must equal the API’s own public URL — the same value as BASE_URL. better-auth embeds this URL in the OAuth state parameter and validates it during the callback. Any mismatch results in state_security_mismatch.
  • NEXT_PUBLIC_WEB_URL must be the web app’s real public origin. It is passed to trustedOrigins in the better-auth config — requests from unlisted origins will be rejected.
  • BETTER_AUTH_SECRET must be a long, random string. Generate one with:
    openssl rand -base64 32
    
The relevant snippet from packages/services/auth/auth.ts shows exactly how these values are wired:
import db, { schema } from "@repo/database";
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { env } from "../env";

export const auth = betterAuth({
  trustedOrigins: [env.NEXT_PUBLIC_WEB_URL],
  database: drizzleAdapter(db, {
    provider: "pg",
    schema,
  }),
  emailAndPassword: {
    enabled: true,
  },
  socialProviders: {
    google: {
      clientId: env.GOOGLE_CLIENT_ID as string,
      clientSecret: env.GOOGLE_CLIENT_SECRET as string,
    },
    github: {
      clientId: env.GITHUB_CLIENT_ID as string,
      clientSecret: env.GITHUB_CLIENT_SECRET as string,
    },
  },
});

The Verification Table

If social login fails with state_security_mismatch on a fresh database deployment, the most likely cause is a missing verification table.The verification table is created by migration 0001_icy_lyja.sql. better-auth uses it to temporarily store the OAuth state value between the redirect to the provider and the callback. If this table does not exist, the state lookup fails and the OAuth flow aborts.Always run all migrations in order before deploying:
pnpm db:migrate
Migration order reference:
MigrationDescription
0000_dusty_morg.sqlInitial schema: users, sessions, accounts
0001_icy_lyja.sqlCreates the verification table (required for OAuth)
0002_colorful_valkyrie.sqlAdditional schema additions
0003_naive_songbird.sqlFurther schema additions
0004_billing_plan_pro_max.sqlAdds the pro_max billing tier

Session Management

Sessions are stored server-side in the session database table and tied to a signed cookie set on the browser. The BETTER_AUTH_SECRET environment variable is the signing key for all cookies and session tokens — rotating it invalidates all active sessions immediately. Key session behaviours:
  • GET /api/auth/get-session — Returns the current session object including the user record. Returns null for unauthenticated requests. This endpoint is used by both the tRPC context and the Next.js middleware to gate protected routes.
  • POST /api/auth/sign-out — Deletes the session row from the database and clears the session cookie.
  • The account table stores the OAuth access tokens for each connected provider (Google, GitHub), linked to the user row by userId.

OAuth Flow Diagram

The sequence below shows the Google OAuth flow end-to-end. GitHub OAuth follows the same pattern with github.com as the provider.
Browser                      apps/api                    accounts.google.com
   │                              │                               │
   │  GET /api/auth/sign-in/google│                               │
   │─────────────────────────────▶│                               │
   │                              │  store state in verification  │
   │                              │  table, build redirect URL    │
   │  302 → accounts.google.com   │                               │
   │◀─────────────────────────────│                               │
   │                              │                               │
   │  GET /?client_id=...&state=..│                               │
   │──────────────────────────────────────────────────────────────▶
   │                              │                               │
   │               User approves the consent screen               │
   │                              │                               │
   │  302 → /api/auth/callback/google?code=...&state=...          │
   │◀─────────────────────────────────────────────────────────────│
   │                              │                               │
   │  GET /api/auth/callback/google                               │
   │─────────────────────────────▶│                               │
   │                              │  verify state against         │
   │                              │  verification table           │
   │                              │  exchange code for tokens     │
   │                              │  upsert user + account rows   │
   │                              │  create session row           │
   │  302 → web app + Set-Cookie  │                               │
   │◀─────────────────────────────│                               │
   │                              │                               │

Build docs developers (and LLMs) love