Skip to main content
zerotal

Documentation


Documentation / zerotal / auth / Auth

Variable: Auth

const Auth: object

Defined in: packages/auth/src/facades/Auth.ts:274

The Auth facade — reads and manages the authenticated user for the current request. This is the primary developer surface for session-based authentication.

Type Declaration

Attempting

attempt()

attempt(credentials, remember?): Promise<boolean>

Attempt to authenticate a user with the given credentials.

Finds the user by every credential except password, verifies the password against the stored hash, and — on success — logs them in (session + ctx.user) and returns true. Returns false without logging in when the user is not found or the password is wrong.

On success it also transparently re-hashes the stored password when its algorithm is outdated (see Hash.needsRehash). On failure it emits a LoginFailed event and, for an unknown user, burns one password-verify's worth of CPU so timing can't be used to enumerate accounts.

Parameters
credentials

Credentials

Bag of columns to match plus password. Keys matching /password/i and the remember key are excluded from the user lookup.

remember?

boolean = false

When true, also issue a persistent "remember me" token/cookie.

Returns

Promise<boolean>

true when the user was found and the password matched (they are now logged in).

Example
if (await Auth.attempt({ email, password })) {
  return redirect('/dashboard');
}
return redirect().back().withErrors({ email: 'These credentials do not match our records.' });

// "Remember me":
await Auth.attempt({ email, password }, remember);

attemptWhen()

attemptWhen(credentials, callback, remember?): Promise<boolean>

Like attempt, but only logs the user in when callback(user) also returns truthy. Useful for extra checks such as "is the account active?".

Parameters
credentials

Credentials

Credential bag, as in attempt.

callback

(user) => boolean | Promise<boolean>

Extra predicate run on the matched user; login proceeds only when it returns truthy.

remember?

boolean = false

When true, also issue a persistent "remember me" token/cookie.

Returns

Promise<boolean>

true only when the credentials matched AND the callback passed.

Example
await Auth.attemptWhen({ email, password }, (user) => user.active === true);

validate()

validate(credentials): Promise<boolean>

Validate credentials WITHOUT logging the user in. Neither the session nor ctx.user is touched. Applies the same user-enumeration timing defence as attempt when no user matches.

Parameters
credentials

Credentials

Returns

Promise<boolean>

true when the credentials are valid.

once()

once(credentials): Promise<boolean>

Authenticate for THIS request only — sets ctx.user but writes nothing to the session. The next request is a guest again. Underpins BasicAuthMiddleware and other stateless flows.

Parameters
credentials

Credentials

Returns

Promise<boolean>

true when the credentials matched and ctx.user was set for this request.

Authorization

hasRole()

hasRole(role): boolean

True when the authenticated user has the given role. Always false for guests, or for user models that don't compose the roles concern.

Parameters
role

string

Returns

boolean

hasAnyRole()

hasAnyRole(roles): boolean

True when the authenticated user has at least one of the given roles.

Parameters
roles

string[]

Returns

boolean

hasAllRoles()

hasAllRoles(roles): boolean

True when the authenticated user has every one of the given roles.

Parameters
roles

string[]

Returns

boolean

can()

can(ability): boolean

True when the authenticated user has the ability (directly or via a role). For richer, model-aware authorization prefer the Gate facade.

Parameters
ability

string

Returns

boolean

hasPermission()

hasPermission(ability): boolean

Alias of can — reads naturally for permission names.

Parameters
ability

string

Returns

boolean

authorize()

authorize(ability): void

Assert the authenticated user has the ability, throwing otherwise.

Parameters
ability

string

Returns

void

Throws

when the user lacks the ability (or is a guest).

roles()

roles(): string[]

The authenticated user's role names (empty for guests).

Returns

string[]

Current user

user()

user(): UserModel

Returns the authenticated user for the current request.

Returns

UserModel

The current user, typed as the app's UserModel.

Throws

when there is no authenticated user (a guest).

userOrNull()

userOrNull(): UserModel | undefined

Returns the authenticated user, or undefined when the request is a guest — the non-throwing counterpart to user.

Returns

UserModel | undefined

id()

id(): number

Returns the authenticated user's identifier (getAuthId()).

Returns

number

Throws

when there is no authenticated user (delegates to user).

check()

check(): boolean

True when the current request has an authenticated user.

Returns

boolean

guest()

guest(): boolean

True when the current request has no authenticated user — the inverse of check.

Returns

boolean

viaRemember()

viaRemember(): boolean

True when the current request was authenticated via the persistent "remember me" cookie rather than an active session. Set by RememberMeMiddleware. Use it to require a fresh login (or password confirmation) before sensitive actions.

Returns

boolean

Guards

viaRequest()

viaRequest(name, resolver): void

Register a custom request guard that resolves a user directly from the incoming request. Reach it with Auth.guard(name). Typically used for stateless API auth (bearer tokens, JWTs, API keys).

Parameters
name

string

Guard name to register (used later with guard).

resolver

RequestGuardResolver

Resolves a user (or null) from the incoming Request.

Returns

void

guard()

guard(name?): Guard

Access an authentication guard by name. With no name (or "web") you get the default session guard — the same identity the top-level Auth.* methods read. Named guards registered via viaRequest resolve from the request.

Parameters
name?

string

Guard name, or omit / "web" for the default session guard.

Returns

Guard

A Guard whose read methods are all async.

Throws

when name is not "web" and no guard was registered under it via viaRequest.

Example
await Auth.guard("api").userOrNull();

Logout

logout()

logout(): Promise<void>

Log the current user out.

Flushes the session bag, issues a fresh session id, and clears ctx.user, so no state the authenticated session earned — a completed 2FA challenge, a confirmed password, an intended URL — survives into whoever uses the browser next. Also invalidates the persistent "remember me" token (nulling it on the user and persisting) and queues the remember cookie for deletion, so it can't re-authenticate. Emits LoggedOut.

Returns

Promise<void>

Example
await Auth.logout();
ctx.redirect('/login');

logoutOtherDevices()

logoutOtherDevices(password): Promise<boolean>

Invalidate the user's sessions on other devices while keeping the current session signed in. Requires the user to confirm their current password.

Driver-agnostic: it re-hashes the same password and persists the new hash, so every other session — whose AuthenticateSessionMiddleware snapshot no longer matches — is torn down on its next request. The current session's snapshot is refreshed so it survives. Returns false when the password is wrong. Attach AuthenticateSessionMiddleware to your routes for this to take effect.

Parameters
password

string

The current user's plain-text password, re-verified before proceeding.

Returns

Promise<boolean>

false when the password is wrong; true once other sessions are invalidated. Emits OtherDeviceLogout.

Example
if (!(await Auth.logoutOtherDevices(currentPassword))) {
  return back().withErrors({ password: ['Incorrect password.'] });
}

Password confirmation

confirmPassword()

confirmPassword(password): Promise<boolean>

Verify the authenticated user's password and, on success, mark the password as freshly confirmed for this session. Pairs with ConfirmPasswordMiddleware to gate sensitive routes. Returns false (without marking) when the password is wrong or there is no user.

Parameters
password

string

The plain-text password to verify against the current user's hash.

Returns

Promise<boolean>

true when the password matched and confirmation was recorded.

Example
if (await Auth.confirmPassword(password)) return redirect().intended();
return back().withErrors({ password: ['Incorrect password.'] });

markPasswordConfirmed()

markPasswordConfirmed(): void

Record that the user's password was confirmed just now, without re-checking it (use when you've already verified the password yourself). Emits PasswordConfirmed.

Returns

void

hasRecentlyConfirmedPassword()

hasRecentlyConfirmedPassword(timeoutSeconds?): boolean

True when the user confirmed their password within timeoutSeconds (default 3 hours). Mirrors the check ConfirmPasswordMiddleware makes.

Parameters
timeoutSeconds?

number = DEFAULT_PASSWORD_TIMEOUT

Confirmation validity window in seconds (default DEFAULT_PASSWORD_TIMEOUT, 3 hours).

Returns

boolean

Sessions & login

loginUsingId()

loginUsingId(id, remember?): Promise<UserModel | null>

Log a user in by their primary key. Looks the user up via the model's find(id) and, when found, delegates to login.

Parameters
id

number

Primary key of the user to log in.

remember?

boolean = false

When true, also issue a persistent "remember me" token/cookie.

Returns

Promise<UserModel | null>

The logged-in user, or null when no user has that id.

login()

login(user, options?): Promise<void>

Log a user in for the current request.

Regenerates the session id (session-fixation defence), writes the user's auth id to the session so subsequent requests are automatically authenticated by PersistUserMiddleware, and sets ctx.user so user works for the rest of this request. With options.remember, also mints and queues a persistent "remember me" token/cookie. Emits LoginSucceeded.

Second factor. When the user has a confirmed second factor, the session is left pending instead: ctx.user stays unset, PersistUserMiddleware keeps subsequent requests as guests, and any remember cookie is withheld, until completeTwoFactor runs. Use twoFactorPending to branch after login and pendingTwoFactorUser to render the challenge.

Parameters
user

UserModel

The already-resolved user model to sign in.

options?

LoginOptions = {}

Login options; set remember: true for a persistent login.

Returns

Promise<void>

Example
const user = await User.where('email', email).first();
await Auth.login(user);
if (Auth.twoFactorPending()) return redirect('/two-factor/challenge');
ctx.redirect('/dashboard');

Two-factor

twoFactorPending()

twoFactorPending(): boolean

True when the password matched but the session is still waiting on its second factor.

While this is true the request is a guest everywhere — ctx.user is unset and check is false — so branch on it right after attempt/login to send the user to the challenge page.

Returns

boolean

Example
if (!(await Auth.attempt({ email, password }))) return back().withErrors(…);
if (Auth.twoFactorPending()) return redirect('/two-factor/challenge');
return redirect('/dashboard');

pendingTwoFactorUser()

pendingTwoFactorUser(): UserModel | undefined

The half-authenticated user behind a pending second factor, for the challenge page to render and to verify the submitted code against. undefined when nothing is pending.

This is deliberately not ctx.user: the request must stay a guest to every guard, route and Flow action until the factor is presented.

Returns

UserModel | undefined

The user awaiting their second factor, or undefined.

completeTwoFactor()

completeTwoFactor(): Promise<UserModel | null>

Complete the second-factor challenge for the pending session.

Call this only after the submitted TOTP or recovery code has been verified. It rotates the session id (the privilege level just changed), clears the pending marker, records the challenge as met for the rest of the session, promotes the user to ctx.user, and issues the remember cookie if the original login asked for one.

Returns

Promise<UserModel | null>

The now fully-authenticated user, or null when no challenge was pending.

Example
const user = Auth.pendingTwoFactorUser();
if (!user || !tf.verifyCode(user.twoFactorSecret, code)) return back().withErrors(…);
await Auth.completeTwoFactor();
return redirect().intended('/dashboard');

Remarks

The current-request user. Auth is request-scoped: every method reads (or writes) ctx.user / the session on the active RequestContext. The user is populated upstream by PersistUserMiddleware (registered globally by AuthProvider), which reads user_id from the session and loads the model. Reads like user, check, and id therefore work anywhere in the request lifecycle without wiring.

Session-based auth. login writes the user's auth id to the session so subsequent requests re-authenticate automatically; logout clears it. To credential-check a user, use attempt (find by credentials + verify password), which logs them in on success.

Session regeneration on login. login issues a fresh session id (session.regenerate()) before elevating privileges, defending against session fixation — a session id planted pre-auth cannot be reused post-auth.

Remember me. Passing remember: true (via attempt or login) mints a long-lived token, stores its hash on the user, and queues a persistent cookie that RememberMeMiddleware uses to re-authenticate after the session expires. viaRemember reports whether the current request was authenticated that way.

Guards. The top-level Auth.* methods read the default session (web) guard. Register additional stateless guards with viaRequest and reach them via guard.

Example

A login controller using attempt + redirect:

import { Auth } from '@zerotal/auth';

export class LoginController {
  async store(ctx: HttpContext) {
    const { email, password, remember } = ctx.validated();

    if (await Auth.attempt({ email, password }, remember)) {
      // Fresh session id already issued by Auth.login().
      return redirect().intended('/dashboard');
    }

    return back().withErrors({
      email: ['These credentials do not match our records.'],
    });
  }

  async destroy() {
    await Auth.logout();
    return redirect('/login');
  }
}