Gates
Gates are functions that determine whether a session is allowed to perform an action. They return true, false, or a GateResult with an explicit error code.
Gate Type
type Gate = (session: Session | null) => Promise<GateResultType> | GateResultType
type GateResultType = GateResult | boolean
A gate receives the current session (possibly null) and returns:
true-- access grantedfalse-- access denied (defaults to 403)GateResult-- access denied with a specific error code (401 or 403)
GateResult
import { createGateResult } from '@repo/auth'
// Success
createGateResult(true)
// Failure with error code
createGateResult(false, 401) // unauthenticated
createGateResult(false, 403) // unauthorized
The GateResult class has two readonly properties: success (boolean) and errorCode (401 | 403 | undefined).
Creating Custom Gates
import type { Gate } from '@repo/auth'
import { createGateResult } from '@repo/auth'
export function createAuthorityGate(authorities: string[]): Gate {
return (session) => {
if (!session?.user) {
return createGateResult(false, 401)
}
const hasAll = authorities.every(
(val) => session.user.authorities.includes(val)
)
if (!hasAll) {
return createGateResult(false, 403)
}
return true
}
}
Built-in Gates
isAuthenticatedGate
Returns createGateResult(false, 401) when session.user.id is missing. Otherwise returns true.
import { isAuthenticatedGate } from '@repo/auth'
permissionGate
Factory that creates a gate checking domain + action permissions on the session entity.
import { permissionGate } from '@repo/auth'
const gate = permissionGate('invoices', ['read', 'update'])
Uses hasPermission internally against session.entity.permissions.
hasAccess
Evaluates multiple gates concurrently. Returns a GateResult reflecting the most restrictive failure (401 takes precedence over 403).
import { hasAccess } from '@repo/auth'
const result = await hasAccess(session, [isAuthenticatedGate, permissionGate('users', ['delete'])])
// result.success -- boolean
// result.errorCode -- 401 | 403 | undefined
Server-side hasAccess
The server re-export automatically reads the session from the current request context:
import { hasAccess } from '@repo/auth/server'
const result = await hasAccess([isAuthenticatedGate])
Client-side hasAccess
Checks gates against page.data.session and resolves to a boolean:
import { hasAccess } from '@repo/auth/client'
const allowed = await hasAccess([permissionGate('users', ['read'])])
// allowed: boolean