UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

40 lines • 1.91 kB
import { readContextAccessor, tenantIdFromContext, userRefFromContext } from './agora-context.js'; /** * An {@link ActorResolver} that reads the caller from the Agora context authkit populates * (`userRef`, `tenantId`) and takes the caller's roles from authz (`effectiveRoles`). It ignores * the transport `req` and reads the active Agora context store, so it needs no `ctx.auth` and is * framework-agnostic. * * Security posture — FAIL-CLOSED: no `userRef.id` in context → throws (the provider replies 401). * An identity is never fabricated. The context `userRef` is passed straight to `effectiveRoles`; * authz reads its `.id`/`.type` and re-reads `globalRoles` from the same context, so global roles * (e.g. `ADMIN`) land in the result with no extra wiring. */ export class AuthzActorResolver { #authz; constructor(config) { this.#authz = config.authz; } async resolve(_req) { const accessor = readContextAccessor(); const ref = userRefFromContext(accessor); if (ref?.id === undefined || ref.id === null || String(ref.id).length === 0) { throw new Error('authzActorResolver: no authenticated identity in @agora/context. The agent route must ' + 'sit behind authkit auth middleware (which populates the context), with the ' + '@adonis-agora/context provider registered.'); } const tenantId = tenantIdFromContext(accessor); const scope = tenantId ? { tenantId } : undefined; const roles = await this.#authz.effectiveRoles(ref, scope); return { id: String(ref.id), roles, ...(tenantId ? { tenantRef: tenantId } : {}), }; } } /** Factory for {@link AuthzActorResolver}. */ export function authzActorResolver(config) { return new AuthzActorResolver(config); } //# sourceMappingURL=authz-actor-resolver.js.map