Skip to main content

Session Management

This guide explains how to work with authentication sessions in your application, both on the client and server side.

Client-Side Sessions

Getting Session Data

There are multiple ways to access the session on the client side:

1. React Hook

import { useSession } from "better-auth/react";

function MyComponent() {
const session = useSession();

if (!session) {
return <div>Not authenticated</div>;
}

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

2. Direct Session Access

import { getSession } from "better-auth/client";

async function checkSession() {
const session = await getSession();

if (session) {
// Access session data
const { user, expires } = session;
}
}

Session Updates

Listen for session changes in your components:

import { useSessionUpdate } from "better-auth/react";

function SessionListener() {
useSessionUpdate((newSession) => {
if (newSession) {
// Session created or updated
} else {
// Session expired or user signed out
}
});
}

Server-Side Sessions

Middleware Protection

Protect your API routes in src/middleware.ts:

import { withAuth } from "better-auth/middleware";

export default withAuth({
// Paths that require authentication
protected: ["/api/protected/:path*"],
// Public paths
public: ["/api/public/:path*"],
});

Route Handlers

Access session in your API routes:

import { getServerSession } from "better-auth/next";

// Server Component
async function ProtectedComponent() {
const session = await getServerSession();

if (!session) {
redirect("/login");
}

return <div>Protected Content for {session.user.email}</div>;
}

// API Route
export async function GET(request: Request) {
const session = await getServerSession();

if (!session) {
return new Response("Unauthorized", { status: 401 });
}

// Access session data
const { user, expires } = session;
}

Server Actions

Use sessions in server actions:

"use server";

import { getServerSession } from "better-auth/next";

export async function protectedAction() {
const session = await getServerSession();

if (!session) {
throw new Error("Unauthorized");
}

// Perform authenticated action
return { userId: session.user.id };
}

Advanced Usage

Custom Session Validation

import { validateSession } from "better-auth/server";

async function customSessionCheck() {
const result = await validateSession({
requireVerified: true,
allowExpired: false,
});

return result.valid;
}

Session Management

import { authClient } from "better-auth/client";

// Sign out from current device
async function signOut() {
await authClient.signOut();
}

// Sign out from all devices
async function signOutAll() {
await authClient.signOutAll();
}

// Refresh session
async function refreshSession() {
await authClient.refreshSession();
}

Type Safety

Use TypeScript types for session data:

import type { Session, User } from "better-auth/types";

// Custom user type
interface CustomUser extends User {
role: string;
preferences: {
theme: 'light' | 'dark';
};
}

// Use with hooks
const session = useSession<CustomUser>();

Security Considerations

Session Configuration

Configure session behavior in src/lib/auth.ts:

export const auth = betterAuth({
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 days
updateAge: 24 * 60 * 60, // 24 hours
rememberMe: true,
},
security: {
csrfProtection: true,
requireSecureCookie: process.env.NODE_ENV === "production",
}
});

Error Handling

try {
const session = await getServerSession();
} catch (error) {
if (error.code === "SESSION_EXPIRED") {
// Handle expired session
} else if (error.code === "INVALID_TOKEN") {
// Handle invalid session token
}
}
Best Practices
  • Always verify sessions on sensitive operations
  • Use appropriate session timeouts
  • Implement proper error handling
  • Consider implementing session refresh strategies
Security Note
  • Never store sensitive information in the session
  • Always validate sessions server-side
  • Use HTTPS in production
  • Implement proper CSRF protection