Configuration Options
The Kerberos constructor accepts an optional third parameter with configuration options:
const kerberos = new Kerberos(policies, derivedRoles, {
logger: true, // Legacy console audit logging with summary + table + debug(json)
onError: 'deny', // 'throw' (default) or 'deny' — fail-closed evaluation errors
telemetry, // Optional: OpenTelemetry traces + metrics ({ api } or { tracer, meter })
cache, // Optional: any cache solution exposing get(key) (keyv, cacheable, ...)
cacheRetry: { attempts: 3 }, // Optional: retry policy for transient cache.get failures
codec, // Optional: (de)serialization codec for dynamic policies ({ jsep } or { deserialize })
relations, // Optional: ReBAC resolver for relation-backed derived roles
z, // Optional: validate with Zod
ajv, // Optional: validate with Ajv
typebox: Type, // Optional: switch Ajv validation to TypeBox builders
getCallId: () => `custom-${Date.now()}`, // Custom call ID generator (optional)
});Options
logger(boolean | KerberosLogger): Enable audit logging.truekeeps the legacy console behavior withgroup + summary + table + debug(json)falseor omitted disables logging- a custom
console-like logger keeps the legacy table/json flow - a structured logger such as
Pinoreceives one structured audit entry per evaluated action - Logging is pure observability: it never changes decisions or error behavior (that is
onError's job), and a throwing logger is swallowed — it can never affect authorization.
onError('throw' | 'deny', default'throw'): What happens when policy evaluation fails at runtime (a throwing condition function, a failing cache backend, a ReBAC resolver error).'throw'propagates the error to the caller;'deny'fails closed:isAllowedresolves tofalse,checkResourcesto{ results: [], kerberosCallId, reqId? },planResourcesto aKIND_ALWAYS_DENIEDfilter.- Malformed arguments are programming errors and always throw
KerberosValidationError, regardless of this option.
javascript// Fail-closed setup: evaluation errors deny instead of throwing. const kerberos = new Kerberos(policies, derivedRoles, { onError: 'deny' });telemetry(KerberosTelemetryOptions): Enable OpenTelemetry traces and metrics. Pass{ api }(the@opentelemetry/apimodule) or{ tracer, meter }instances — see OpenTelemetry.cache(CacheLike): An optional cache used as a fallback source for dynamic/stored policies. Any object exposing aget(key)method is accepted (keyv, cacheable, cache-manager, ...). See Caching / Storing policies.cacheRetry({ attempts?: number }, default{ attempts: 3 }): Retry policy for transientcache.getfailures. After the attempts are exhausted the failure surfaces asKerberosCacheError(and then followsonError).attempts: 1disables retrying.codec(PolicyCodec): How cached policy documents are transformed before construction:{ jsep }enables the built-in safe$exprevaluator,{ deserialize }plugs in your own logic, and when omitted cached values are passed to policy constructors as-is — seecodecoption — three modes.relations(KerberosRelationsResolver): ReBAC resolver used by relation-backed derived roles — any object with acheck(args, opts)method (and an optional batchedlist). See ReBAC (Relations).z: Enables validation using the built-in Zod schema builders.ajv: Enables validation using the built-in JSON Schema builders compiled with Ajv.typebox: When used together withajv, switches validation to the built-in TypeBox builders.getCallId(function): Custom function to generate call IDs for audit tracking.- Default behavior: Uses
crypto.randomUUID()in Node.js,window.crypto.randomUUID()in browsers, or falls back to a pseudo UUID generator - Custom example:
() => \req-${Date.now()}-${Math.random()}``
- Default behavior: Uses
Using Pino for Production Logging
If you want machine-readable audit logs in production, pass a Pino instance as the logger option:
import pino from 'pino';
import { Kerberos } from '@alexify/kerberos';
const logger = pino({ level: 'info' });
const kerberos = new Kerberos(policies, derivedRoles, {
logger,
});With Pino, Kerberos emits structured audit entries that include callId, reqId, reqKind, principalId, resourceId, action, effect, outputs, and meta. This mode is better suited for production ingestion than the default console table output.
It also emits lifecycle logs such as IsAllowed.start, IsAllowed.error, IsAllowed.finish, CheckResources.start, CheckResources.finish and PlanResources.*. Errors are always logged, but whether they are rethrown or converted into a fail-closed response is decided solely by the onError option — never by the logger.
Call ID Generation
Every request (isAllowed / checkResources / planResources) automatically generates a unique kerberosCallId for audit tracking:
- Node.js: Uses
crypto.randomUUID() - Browser: Uses
window.crypto.randomUUID() - Fallback: Pseudo UUID v4 generator if crypto APIs are unavailable
- Custom: Provide your own
getCallIdfunction for custom ID formats
This ID is included in both the response and audit logs for correlation.