Skip to main content

Overview

Maxw AI uses Better-Auth for authentication and session management. Better-Auth provides a secure, flexible authentication system with support for email/password and OAuth providers.

Authentication Flow

1. Sign Up

Users create accounts via email and password:
import { authClient } from "@/lib/auth-client";

const { data, error } = await authClient.signUp.email({
  email: "[email protected]",
  password: "securepassword123",
  name: "John Doe"
});

2. Sign In

Authenticate with existing credentials:
import { authClient } from "@/lib/auth-client";

const { data, error } = await authClient.signIn.email({
  email: "[email protected]",
  password: "securepassword123"
});

3. Session Management

Better-Auth automatically creates session cookies with these attributes:

Auth API Endpoints

Better-Auth exposes multiple HTTP methods at /api/auth/[...all]:

Core Endpoints

POST /api/auth/sign-up/email
POST
Create a new user account with email and passwordRequest Body:
{
  "email": "string",
  "password": "string",
  "name": "string"
}
POST /api/auth/sign-in/email
POST
Authenticate with email and passwordRequest Body:
{
  "email": "string",
  "password": "string"
}
POST /api/auth/sign-out
POST
Invalidate current session and clear cookies
GET /api/auth/session
GET
Retrieve current session dataResponse:
{
  "session": {
    "id": "string",
    "userId": "string",
    "expiresAt": "timestamp",
    "token": "string"
  },
  "user": {
    "id": "string",
    "email": "string",
    "name": "string",
    "emailVerified": boolean,
    "image": "string | null",
    "settings": {}
  }
}
PATCH /api/auth/update-user
PATCH
Update user profile information
PUT /api/auth/change-password
PUT
Change user password (requires current password)
DELETE /api/auth/delete-user
DELETE
Delete user account and all associated data

Making Authenticated Requests

Server-Side (Next.js)

Use the auth.api.getSession() method to verify authentication:
import { auth } from "@/lib/auth";
import { headers } from "next/headers";

export async function POST(request: Request) {
  // Get session from request headers
  const authData = await auth.api.getSession({ 
    headers: await headers() 
  });

  // Check if user is authenticated
  if (!authData?.user) {
    return new Response(
      JSON.stringify({ error: "Unauthorized" }), 
      { status: 401 }
    );
  }

  const userId = authData.user.id;
  const userEmail = authData.user.email;
  
  // Process authenticated request...
}

Client-Side (React)

The Better-Auth client automatically manages session cookies:
import { authClient } from "@/lib/auth-client";
import { useSession } from "@/hooks/use-session";

function ProtectedComponent() {
  const { data: session, isPending } = useSession();

  if (isPending) return <div>Loading...</div>;
  if (!session?.user) return <div>Please sign in</div>;

  return <div>Welcome, {session.user.name}!</div>;
}

Database Schema

Better-Auth uses these tables in PostgreSQL:

User Table

user
table
Core user accounts
id
text
required
Primary key, auto-generated unique identifier
name
text
required
User’s display name
email
text
required
Unique email address
emailVerified
boolean
default:"false"
Whether email has been verified
image
text
Profile image URL (optional)
settings
jsonb
default:"{}"
User preferences and configuration (Canvas API tokens, etc.)
createdAt
timestamp
Account creation timestamp
updatedAt
timestamp
Last update timestamp

Session Table

session
table
Active user sessions
id
text
required
Primary key
token
text
required
Unique session token (stored in HTTP-only cookie)
userId
text
required
Foreign key to user table
expiresAt
timestamp
required
Session expiration time
ipAddress
text
IP address of session creation
userAgent
text
Browser/client user agent string
createdAt
timestamp
Session creation timestamp
updatedAt
timestamp
Last activity timestamp

Account Table

account
table
OAuth provider credentials (for future OAuth integration)
id
text
required
Primary key
accountId
text
required
Provider-specific account ID
providerId
text
required
OAuth provider (e.g., “google”, “github”)
userId
text
required
Foreign key to user table
accessToken
text
OAuth access token
refreshToken
text
OAuth refresh token
accessTokenExpiresAt
timestamp
Access token expiration
scope
text
OAuth permission scopes

Verification Table

verification
table
Email verification tokens
id
text
required
Primary key
identifier
text
required
Email address being verified
value
text
required
Verification token
expiresAt
timestamp
required
Token expiration time

Security Best Practices

Session Security

Sessions automatically expire based on the expiresAt timestamp. Better-Auth handles token rotation and invalidation.
Session cookies include:
  • httpOnly: true - Prevents XSS attacks
  • secure: true - Requires HTTPS (production)
  • sameSite: "none" - Required for mobile app (Expo)

Password Requirements

Implement password validation on the client side:
const passwordSchema = z
  .string()
  .min(8, "Password must be at least 8 characters")
  .regex(/[A-Z]/, "Password must contain an uppercase letter")
  .regex(/[0-9]/, "Password must contain a number");

Rate Limiting

Consider implementing rate limiting on authentication endpoints to prevent brute force attacks. Use middleware or services like Upstash Rate Limit.

Error Responses

Authentication Errors

{
  "error": "Invalid email or password",
  "code": "INVALID_CREDENTIALS"
}

Mobile App (Expo)

The Better-Auth Expo plugin enables authentication in the React Native app:
import { expo } from "@better-auth/expo";
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  // ... other config
  trustedOrigins: ["exp://"],
  advanced: {
    defaultCookieAttributes: {
      sameSite: "none",
      secure: true,
      httpOnly: true,
    },
  },
  plugins: [expo()],
});
The expo() plugin handles session persistence in React Native’s secure storage.

Environment Variables

Required environment variables for authentication: Configure in your .env file:
AUTH_SECRET="your-secret-key-here"
DATABASE_URL="postgresql://user:password@host:5432/database"

Next Steps

Chat API

Make authenticated requests to the AI chat endpoint

User Schema

Learn about user data models and settings

Better-Auth Docs

Explore Better-Auth documentation for advanced features

Build docs developers (and LLMs) love