Authentication
UseBetter Console supports three authentication methods. You configure them in the sessions option of betterConsole(). At least one method must be enabled.
Auto-approve (development)
Section titled “Auto-approve (development)”Auto-approve issues a stateless JWT immediately when a session is initiated — no database, no email flow. It is intended for local development only.
import { betterConsole } from "@usebetterdev/console";
const consoleInstance = betterConsole({ connectionTokenHash: process.env.BETTER_CONSOLE_TOKEN_HASH!, sessions: { autoApprove: process.env.NODE_ENV === "development" },});Magic link (production)
Section titled “Magic link (production)”Magic link uses a 3-step handshake with email verification. It requires a database adapter (Drizzle) for storing session and magic link records.
import { betterConsole } from "@usebetterdev/console";import { drizzleConsoleAdapter } from "@usebetterdev/console/drizzle";
const consoleInstance = betterConsole({ adapter: drizzleConsoleAdapter(db), connectionTokenHash: process.env.BETTER_CONSOLE_TOKEN_HASH!, sessions: { magicLink: { allowedEmails: process.env.BETTER_CONSOLE_ALLOWED_EMAILS!, }, },});Try it yourself
Section titled “Try it yourself”Step through each authentication flow to see the HTTP requests and responses at each stage.
Email allow-list
Section titled “Email allow-list”Only emails matching the allowedEmails list can initiate a session. Emails that don’t match receive a ConsoleEmailNotAllowedError. You can use exact addresses or glob patterns with * wildcards.
sessions: { magicLink: { // Single email // Multiple emails // Glob pattern — allow any email from a domain allowedEmails: "*@myapp.com", // Mix exact emails and patterns // From environment variable (comma-separated) allowedEmails: process.env.BETTER_CONSOLE_ALLOWED_EMAILS!, },},The universal wildcard * allows any email to initiate a session. In production, this requires explicit opt-in:
sessions: { magicLink: { allowedEmails: "*", allowUnauthenticatedEmails: true, },},Email delivery
Section titled “Email delivery”When sendMagicLinkEmail is not provided, the verification code is delivered automatically via the Console email relay (console.usebetter.dev). The relay only sends to emails that have a registered Console account — no additional configuration is needed.
The Console UI sends appName and baseUrl in the session init request. These are used to construct the verification link in the email.
Custom email sender
Section titled “Custom email sender”To use your own email provider instead of the Console email relay, provide the sendMagicLinkEmail callback:
sessions: { magicLink: { allowedEmails: process.env.BETTER_CONSOLE_ALLOWED_EMAILS!, sendMagicLinkEmail: async ({ email, sessionId, code }) => { await sendEmail({ to: email, subject: "Your Console access code", body: `Your verification code is: ${code}`, }); }, },},Brute-force protection
Section titled “Brute-force protection”Magic link verification has a configurable attempt limit. After maxAttempts failed code entries, the magic link is locked out and a new session must be initiated.
sessions: { magicLink: { maxAttempts: 3, // default: 5 },},The magic link code expires after 10 minutes regardless of attempts.
Custom authenticate hook
Section titled “Custom authenticate hook”Session management
Section titled “Session management”Token lifetime
Section titled “Token lifetime”Session tokens expire after 24 hours by default. Configure with tokenLifetime:
sessions: { tokenLifetime: "8h", // valid range: 1h to 7d},Token rotation
Section titled “Token rotation”To rotate the connection token (e.g., if compromised):
npx @usebetterdev/console-cli token rotateThis generates a new token pair. Update BETTER_CONSOLE_TOKEN_HASH in your environment and restart your server. All existing sessions are invalidated because session JWTs are signed with the connection token secret.
Next steps
Section titled “Next steps”- Configuration — full config reference, CORS, environment variables
- CLI — all CLI commands including token management
- Troubleshooting — common auth issues and fixes