auth.sessions
Listing and revoking sessions, and elevating one into sudo mode.
A session is one authenticated period for one user on one device. It is not the token — tokens rotate underneath it — and it survives a refresh, which is why revoking a session is meaningful while "expiring a token" is not.
Everything here needs a session of its own, and most of it needs sudo on top.
list
list() → Session[]
Every active session the user has, across every device.
const { data: sessions } = await nulvless.auth.sessions.list();Each carries:
idstringRequiredWhat revoke takes.
is_current_sessionbooleanRequiredMarks the one making the request. Render it differently and do not offer to revoke it by accident — that is a sign-out, not a revocation.
finger_printSessionFingerPrintOptionalDevice, browser, OS and approximate location. Populated only when the client
was created with trackUser, and on the server only when you forward the
user's headers — otherwise every session looks like it came from your
infrastructure.
amr{ method, timestamp }[]RequiredHow this session was authenticated, in order. A session that used a password and then a TOTP code carries both.
scopesstring[]RequiredWhat the session carries independent of any resource.
invalidatedbooleanRequiredRevoked, but not yet gone from the list.
sudo_expires_atstring | nullOptionalWhen sudo lapses. Absent or null when the session is not elevated.
created_atstringRequiredupdated_atstringRequiredexpires_atstringRequiredThis is exactly what a "where you're signed in" screen renders — the fingerprint
gives you the device line, amr gives you "signed in with password and
authenticator", and is_current_session gives you "this device".
revoke
revoke({ id, nonce }) → null
Ends one session immediately. Its tokens stop working; a refresh in flight fails.
await nulvless.auth.sessions.revoke({ id, nonce: code });idstringRequiredFrom list(), or from auth.getSession() for the current one.
noncestringOptionalSudo confirmation for this one call. See below.
Requires sudo
Revoking is protected under manage_sessions. A stolen session must not be able
to quietly evict the real owner.
To end every session but the current one,
auth.signOut('others') is one call instead of a loop
over list().
sudo
sudo(method?) → { challenge }
Starts a sudo elevation by sending a confirmation code.
const { data } = await nulvless.auth.sessions.sudo();
const { data: viaEmail } = await nulvless.auth.sessions.sudo('email_otp');methodSudoMethodOptionalWhich factor to confirm with. Omit and the platform picks, the same way it does for an MFA challenge.
totpThe authenticator app. Nothing is sent.email_otpA code by email.sms_otpA code by SMS.Returns a Challenge. What you do with the code decides which of the two paths
below you are on.
sudoVerify
sudoVerify({ code }) → Authenticated
Completes the elevation, for the whole session.
const { data } = await nulvless.auth.sessions.sudoVerify({ code });
// data.sudo.expires_in → seconds the window lastscodestringRequiredWhat the user typed.
No challenge token is needed. The pending sudo challenge is resolved by the session itself, which is why this call takes only the code.
On success the session is re-issued with sudo active and stored automatically.
data.sudo.expires_in is the seconds remaining — use it to show the window
closing rather than guessing.
checkSudo
checkSudo(params?) → null
Asks whether sudo is currently active. Answers 204 when it is, and an error
when it is not.
const { error } = await nulvless.auth.sessions.checkSudo();
if (error) startSudoFlow();Useful on entering a settings screen, so the prompt appears once at the door instead of on the first destructive click.
Sudo mode
A valid session says who signed in. It does not say who is at the keyboard now. Sudo mode is a short window where that has just been re-proven.
Two ways to satisfy it
Both start with sudo(), which sends the code. They differ in what you spend it
on.
await nulvless.auth.sessions.sudo();
const { data } = await nulvless.auth.sessions.sudoVerify({ code });
// everything sudo-protected passes until data.sudo.expires_in runs outRight when the user is about to do several sensitive things in a row.
nonce goes inside the params, not in the options. It travels as
nlv-sudo-nonce and is single-use.
Knowing when it is needed
Do not hard-code which of your calls are protected — it is per-environment configuration and can change without you. React to the event instead:
nulvless.auth.on('sudo-required', async () => {
await nulvless.auth.sessions.sudo();
openSudoPrompt();
});It fires on 403 protected_action_denied. See Events.
What is protected
An environment names the groups it wants covered: manage_mfa,
manage_credentials, manage_grants, manage_identities, manage_sessions
and manage_passwords. A master switch turns the whole thing off, and one
setting controls how long an elevation lasts.
Sudo mode covers the whole flow, including doing the same on your own routes.