Updated March 31, 2026
10 min read
Authentication & Sessions
Implement secure admin authentication with username/password login, session management, and role-based access control.
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));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
}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");
}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");This page maps to convex/adminAuth.ts in the repository.