Security

Updated March 31, 2026

10 min read

Authentication & Sessions

Implement secure admin authentication with username/password login, session management, and role-based access control.

admin authenticationsession managementlogin flowadmin sessionsrole based access
Overview

Handover uses a secure session-based authentication system for admin users. This guide covers the complete authentication flow from initial setup to session management.

Bootstrap: First-Time Setup

When a client site is first deployed, an owner account must be bootstrapped. This creates the first admin user with full privileges.

The bootstrap process requires the client password (set when creating the project in Handover dashboard).

const { token, user } = await handover.bootstrapAdmin(
  clientPassword,    // From project creation
  "admin",          // Choose username
  "SecurePass123!"  // Choose password (10+ chars, upper, lower, number)
);

// Store session
localStorage.setItem("handover_admin_session", token);
localStorage.setItem("handover_admin_user", JSON.stringify(user));
typescript

Login Flow

After bootstrap, all admin users log in with username and password. Sessions are valid for 7 days and can be revoked at any time.

const { token, user, expiresAt } = await handover.loginAdmin(
  username,
  password
);

localStorage.setItem("handover_admin_session", token);

// Check expiry
if (Date.now() > expiresAt) {
  // Session expired, redirect to login
}
typescript

Session Validation

Always validate the session before showing protected content. Sessions can be revoked server-side if passwords are reset.

const token = localStorage.getItem("handover_admin_session");
if (!token) {
  router.push("/admin/login");
  return;
}

const session = await handover.getAdminSession(token);
if (!session.isValid) {
  localStorage.clear();
  router.push("/admin/login");
}
typescript

Password Requirements

All passwords must meet security requirements to prevent weak credentials.

  • Minimum length: 10 characters
  • Maximum length: 128 characters
  • Must contain uppercase letter
  • Must contain lowercase letter
  • Must contain number

Rate Limiting & Security

Handover implements automatic rate limiting to prevent brute force attacks. After 5 failed login attempts within 15 minutes, the account is locked for 30 minutes.

Logout

Always log out when done to revoke the session server-side. This prevents session reuse if the token is compromised.

await handover.logoutAdmin(token);
localStorage.clear();
router.push("/admin/login");
typescript
Source doc

This page maps to convex/adminAuth.ts in the repository.