Codapult
FeaturesPricingAPIHelpChangelog
Codapult

Ship Your SaaS Faster

Product

  • Features
  • Pricing
  • Plugins
  • API Reference
  • Help Center
  • Feature Requests
  • Changelog

Company

  • Contact
  • GitHub

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Codapult. All rights reserved.

All articles

Getting Started

  • Introduction
  • Quick Start
  • Project Structure

Configuration

  • Environment Variables
  • App Configuration

Authentication

  • Authentication

Database

  • Database

Teams

  • Teams & Organizations

Payments

  • Payments & Billing

Api

  • API Layer

Ai

  • AI Features

Email

  • Email

Infrastructure

  • Infrastructure

Ui

  • UI & Theming

I18n

  • Internationalization

Content Management

  • Content Management

Admin

  • Admin Panel

Security

  • Security

Monitoring

  • Analytics & Monitoring

Modules

  • Module Architecture

Plugins

  • Plugin System

Deployment

  • Deployment
  • Troubleshooting

Upgrading

  • Upgrading Codapult

Developer Tools

  • MCP Server
  • Testing
Authentication

Authentication

Set up authentication with Better-Auth or Kinde, configure OAuth, magic links, 2FA, passkeys, and enterprise SSO.

Codapult uses the adapter pattern for authentication. Two providers are supported out of the box — switch between them with a single environment variable, no code changes required.

ProviderTypeKey features
Better-Auth (default)Self-hostedEmail/password, OAuth, magic links, TOTP 2FA, passkeys, user impersonation
KindeHostedManaged auth pages, OAuth, SSO, built-in user management

Choosing a provider

Set AUTH_PROVIDER in your .env.local:

# Better-Auth (default — omit to use this)
AUTH_PROVIDER="better-auth"

# Kinde
AUTH_PROVIDER="kinde"

# Disable auth entirely (public-only app, no sign-in)
AUTH_PROVIDER="none"

Both providers produce the same AppSession object used throughout the app, so all downstream code (guards, server actions, API routes) works identically regardless of which provider is active.


Better-Auth setup

Better-Auth is the default provider. It stores sessions and accounts in your database (Turso or PostgreSQL).

Required variables

BETTER_AUTH_SECRET="your-secret-here"   # openssl rand -base64 32
BETTER_AUTH_URL="http://localhost:3000"  # your app URL

Sign-in methods

Better-Auth supports multiple sign-in methods, all configurable in src/config/app.ts:

auth: {
  oauthProviders: ['google', 'github'],
  magicLink: true,
  passkeys: true,
  twoFactor: true,
},

Disable any method by removing it from the array or setting the boolean to false. The sign-in page automatically adjusts to show only enabled methods.


Kinde setup

Kinde provides fully managed, hosted authentication pages.

Required variables

AUTH_PROVIDER="kinde"
KINDE_CLIENT_ID="your-client-id"
KINDE_CLIENT_SECRET="your-client-secret"
KINDE_ISSUER_URL="https://your-app.kinde.com"
KINDE_SITE_URL="http://localhost:3000"
KINDE_POST_LOGOUT_REDIRECT_URL="http://localhost:3000"
KINDE_POST_LOGIN_REDIRECT_URL="http://localhost:3000/dashboard"

Create an application in the Kinde dashboard, copy the credentials, and add the callback URLs.


OAuth providers

OAuth buttons appear on the sign-in page when the corresponding credentials are configured. Codapult supports Google, GitHub, Apple, Discord, Twitter, and Microsoft.

Google

  1. Go to the Google Cloud Console
  2. Create an OAuth 2.0 Client ID (Web application)
  3. Add authorized redirect URI: https://your-app.com/api/auth/callback/google
  4. Copy the credentials to .env.local:
GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
GOOGLE_CLIENT_SECRET="GOCSPX-your-secret"

GitHub

  1. Go to GitHub Developer Settings → OAuth Apps
  2. Create a new OAuth App
  3. Set the authorization callback URL: https://your-app.com/api/auth/callback/github
  4. Copy the credentials to .env.local:
GITHUB_CLIENT_ID="your-client-id"
GITHUB_CLIENT_SECRET="your-client-secret"

Adding more providers

Add the provider name to the oauthProviders array in src/config/app.ts, then add the corresponding environment variables. Supported values: 'google', 'github', 'apple', 'discord', 'twitter', 'microsoft'.


Magic links

Magic links provide passwordless email sign-in. When a user enters their email, they receive a link that signs them in directly — no password required.

Prerequisites

  • RESEND_API_KEY must be set (magic links are sent via Resend)
  • magicLink: true in src/config/app.ts

The magic link expires after 10 minutes. If the user doesn't have an account, one is created automatically.


Two-factor authentication (2FA)

Codapult supports TOTP-based two-factor authentication using authenticator apps (Google Authenticator, Authy, 1Password, etc.).

Setup flow for end-users

  1. Navigate to Settings → Two-Factor Authentication
  2. Click Enable 2FA
  3. Scan the QR code with an authenticator app
  4. Enter the 6-digit verification code to confirm
  5. Save the backup codes in a secure location

Once enabled, users are prompted for a TOTP code after entering their password on sign-in.

Configuration

Set twoFactor: true in src/config/app.ts to enable the 2FA option in user settings. The TOTP issuer name (shown in authenticator apps) is read from appConfig.brand.name.


Passkeys (WebAuthn)

Passkeys let users sign in with biometrics (fingerprint, face ID) or hardware security keys instead of passwords.

Prerequisites

  • passkeys: true in src/config/app.ts
  • HTTPS in production (WebAuthn requires a secure origin)

The passkey relying party ID and origin are derived from NEXT_PUBLIC_APP_URL automatically.


Enterprise SSO (SAML)

Codapult includes enterprise-grade SSO via BoxyHQ Jackson, supporting SAML 2.0 identity providers (Okta, Azure AD, Google Workspace, OneLogin, etc.).

Admin setup

  1. Go to Admin → Enterprise SSO
  2. Click Add Connection
  3. Enter the tenant slug (matches the organization) and paste the IdP metadata XML or URL
  4. Share the following with the customer's IT team:
    • ACS URL: https://your-app.com/api/auth/sso/callback
    • Entity ID / Audience: https://your-app.com/api/auth/sso

Environment variables

SSO_PROVIDER="jackson"
SSO_PRODUCT="your-product-name"

# Production: use Postgres for durable storage
SSO_DB_ENGINE="sql"
SSO_DB_TYPE="postgres"
SSO_DB_URL="postgres://user:password@host:5432/jackson"

For development, Jackson defaults to in-memory storage (no database configuration needed). For production, configure a PostgreSQL database for persistent SSO connections.

SSO sign-in flow

  1. User enters their email on the sign-in page
  2. Codapult detects the SSO connection by email domain
  3. User is redirected to their company's identity provider
  4. After IdP authentication, the user is redirected back and signed in

Auth guards

Codapult provides server-side guard functions for protecting API routes, server actions, and pages.

getAppSession()

Returns the current session or null. Use in API routes and server components:

import { getAppSession } from '@/lib/auth';

export async function GET() {
  const session = await getAppSession();
  if (!session) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }
  // session.user.id, session.user.email, session.user.role
}

requireAuth()

Throws if the user is not authenticated. Returns an AuthContext with the session:

import { requireAuth } from '@/lib/guards';

export async function someAction() {
  const { session } = await requireAuth();
  // session is guaranteed to exist
}

Organization guards

GuardDescription
requireOrgMembership(orgId)User must be a member of the organization
requireOrgAdmin(orgId)User must be an owner or admin of the organization
requireOrgPermission(orgId, permission)User must have a specific RBAC permission

All org guards return an OrgAuthContext with the session, orgId, and the user's role. Global admins bypass org permission checks automatically.

import { requireOrgPermission } from '@/lib/guards';

export async function updateProject(orgId: string, data: unknown) {
  const { session, role } = await requireOrgPermission(orgId, 'project:update');
  // proceed with the update
}

Session shape

Both providers produce the same AppSession interface:

interface AppSession {
  user: {
    id: string;
    name: string;
    email: string;
    image?: string | null;
    role: UserRole; // 'user' | 'admin'
  };
  impersonatedBy?: string; // set when an admin is impersonating
}

Auth API endpoints

These endpoints are available at /api/auth/ when using Better-Auth:

EndpointMethodDescription
/api/auth/sign-up/emailPOSTCreate a new account with email and password
/api/auth/sign-in/emailPOSTSign in with email and password
/api/auth/sign-in/socialPOSTInitiate OAuth sign-in (provider specified in body)
/api/auth/sign-outPOSTSign out and clear the session cookie
/api/auth/get-sessionGETGet the current session
/api/auth/magic-link/sendPOSTSend a magic link email
/api/auth/two-factor/enablePOSTEnable TOTP 2FA for the current user
/api/auth/two-factor/verifyPOSTVerify a TOTP code during sign-in
/api/auth/passkey/registerPOSTRegister a new passkey
/api/auth/passkey/authenticatePOSTAuthenticate with a passkey
/api/auth/sso/callbackPOSTSAML SSO assertion consumer service (ACS)

Sessions are stored as HTTP-only cookies with a 5-minute cache for performance. The cookie is automatically refreshed on each request.

App ConfigurationDatabase