Authorization Requirements
Use authorization requirements with the current published Askr packages.
@askrjs/askr0.0.59
How to use authorization requirements
Start with this complete authorization requirements shape, then replace the example data and application service with your own.
- Import the published @askrjs/askr entrypoint.
- Keep authorization requirements configuration next to the component, route, or server composition root that owns it.
- Handle pending, unavailable, cancellation, and failure states, then verify the production path.
route('/admin', AdminPage, {
auth: { requirement: 'authenticated' },
policy: ({ auth }) => auth.permissions.includes('admin') ? allow() : forbidden(),
});Route requirements
requireUser(), requireAnonymous(), requireScope(scope), requireRole(role), and requirePermission(permission) are all factories that return an AuthRequirement - a function of (context: AuthContext) => AuthDecision. @askrjs/server's router accepts them directly as a route's auth option, as in router.get('/reports', handler, { auth: requirePermission('reports:read') }), so there's no separate middleware registration step.
Policy evaluation
allOf(...requirements) and anyOf(...requirements) combine multiple AuthRequirement functions into a single one, evaluating each against the same AuthContext and applying AND or OR semantics respectively. Because both return another AuthRequirement, they compose - allOf(requireUser(), anyOf(requireRole('admin'), requirePermission('reports:read'))) reads the same way it evaluates.
Unauthorized and forbidden
AuthDecision is a discriminated union: {allowed: true} or {allowed: false, reason: 'unauthenticated' | 'forbidden' | 'already_authenticated'}. requireUser() returns 'unauthenticated' when there's no principal at all and 'forbidden' territory is reserved for role/permission/scope checks failing against an authenticated principal - those two cases need different HTTP responses. requireAnonymous() uses the third reason, 'already_authenticated', for endpoints like login or registration that should reject a caller who already has a session.
Server enforcement
The router evaluates a route's auth requirement before calling its handler and turns a false AuthDecision into the corresponding 401 or 403 response, so most handlers never need to check ctx.auth themselves. Handlers still reach for ctx.auth directly when they need the resolved data rather than a pass/fail - reading ctx.auth.principal?.id to scope a query, for example - which is safe to do even on routes without an auth requirement, since ctx.auth is always present.