auth
Sign users in and out, protect pages, and check who can do what.
AuthClient Server
Configuration
// config/auth.ts
defineConfig({
adapter: AuthAdapter<TUser, TCredentials>, // required
signInPath?: string, // where guards send anonymous users
eager?: boolean, // load the session before first render; default true
})
The provider binds auth in the container and, unless eager: false, restores the session during boot.
Session
interface Session<TUser> {
user: TUser | null
expiresAt?: number // epoch ms, when known
can(ability: string, subject?: unknown): boolean
}
The router's requireAuth() and can() guards read context.session, which the provider supplies.
Hooks
| Hook | Returns |
|---|---|
useAuth() |
The Auth object: session, user, load(), signIn(credentials), signOut(), refresh(), getToken(), subscribe(listener). |
useSession() |
The live Session. Re-renders on sign-in and sign-out. |
useUser() |
session.user. |
useCan() |
session.can. |
Adapters
tokenAdapter
tokenAdapter<TUser, TCredentials = { email: string; password: string }>({
fetchUser: (token) => Promise<TUser | null>, // required
signIn?: (credentials) => Promise<{ token; refreshToken?; user? }>,
refresh?: (refreshToken) => Promise<{ token; refreshToken? } | null>,
signOut?: (token) => Promise<void>,
storage?: TokenStorage, // default memoryStorage()
refreshStorage?: TokenStorage, // default memoryStorage()
abilities?: Abilities<TUser>,
})
memoryStorage() and localStorageTokens(key = 'kitr:token') are the built-in TokenStorages. Write your own with { get(), set(token) }.
betterAuthAdapter
betterAuthAdapter<TUser>(client, { abilities?, signIn?: (client, credentials) => Promise<unknown> })
Uses client.signIn.email unless you pass signIn.
customAdapter
customAdapter<TUser, TCredentials>({
getSession: () => Promise<Session<TUser> | null>, // required
signIn?, signOut?, refresh?, getToken?, onChange?,
})
Build sessions with createSession(user, abilities?, { expiresAt? }).
defineAbilities
const abilities = defineAbilities<User>({ 'name': (user, subject?) => boolean })
abilities.can(user, 'name', subject) // false when user is null
abilities.for(user)('name', subject)
kitr/auth/server
No React. Works with any @kitr/api router.
authMiddleware<TUser>({
verify: (token, ctx) => TUser | null | Promise<TUser | null>, // required
from?: 'bearer' | { cookie: string }, // default 'bearer'
optional?: boolean, // let anonymous requests through
abilities?: Abilities<TUser>,
})
requireUser<TUser>(ctx): TUser // throws 401 when anonymous
currentUser<TUser>(ctx): TUser | null
The middleware sets ctx.locals.user and ctx.locals.can(ability, subject), and throws 401 UNAUTHORIZED when there is no valid user and optional is off.