Packages
Elevate
Getting started with @railman/auth-elevate — step-up / sudo for Better Auth.
Getting started — Elevate
@railman/auth-elevate adds a short step-up window on an existing session. It does not unlock vault material.
Demo: /elevate · Guide: Elevate and sudo · HTTP: API
Install
pnpm add @railman/auth-elevate @railman/auth-login-factor
# optional TOTP storage:
# better-auth twoFactor plugin
# optional passkey step-up:
# @better-auth/passkey @railman/auth-zero-access-passkeyMinimal — password / TOTP only
import { betterAuth } from "better-auth";
import { twoFactor } from "better-auth/plugins";
import { elevate, requireElevate } from "@railman/auth-elevate";
import { loginFactors } from "@railman/auth-login-factor";
export const auth = betterAuth({
plugins: [
loginFactors(),
twoFactor(),
elevate({
deploymentMode: "single-instance",
// omit passkeyCounterGuard → passkey step-up off
passwordOnlyIfNoStronger: true,
elevatedTtlSec: 300,
}),
],
});Gate a route:
await requireElevate(session.session.elevateClaim, {
userId: session.user.id,
sessionToken: session.session.token ?? session.session.id,
secret: process.env.BETTER_AUTH_SECRET!,
ttlSec: 300,
});With passkey step-up
import { passkey } from "@better-auth/passkey";
import { enhancePasskey } from "@railman/auth-zero-access-passkey";
const passkeyStack = enhancePasskey(passkey, {
rpID: "example.com",
origin: ["https://example.com"],
assertCredentialAccess: "session",
});
elevate({
deploymentMode: "single-instance",
passkeyCounterGuard: passkeyStack.controller,
passwordOnlyIfNoStronger: true,
elevatedTtlSec: 300,
});Client
import { elevateClient } from "@railman/auth-elevate/client";
createAuthClient({ plugins: [elevateClient()] });Key options
| Option | Default intent |
|---|---|
deploymentMode | "single-instance" lab · "multi-instance" + shared stores in prod |
elevatedTtlSec | 300 |
passwordOnlyIfNoStronger | true |
passkeyCounterGuard | Optional — omit to disable passkey method |