@glinr/theauth 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  export { and, eq, like } from 'drizzle-orm';
2
2
  export { createAgentModule } from './agent/index.js';
3
- import { D as Database, a as DatabaseConfig, K as KavachConfig, b as DelegateInput, P as Permission, c as DelegationChain, d as DidDocument, e as DidKeyPair, f as DidWebConfig, g as AgentDid, S as SignedPayload, V as VerificationResult, C as CreateAgentInput, A as AgentIdentity, h as AgentFilter, U as UpdateAgentInput, i as AuthorizeRequest, R as RequestContext, j as AuthorizeResult, k as AuditFilter, l as AuditEntry, m as AuditExportOptions, M as McpServerInput, n as McpServer, o as ResolvedUser, p as SessionManager, q as ApprovalRequest, r as MagicLinkModule, E as EmailOtpModule, T as TotpModule, s as PasskeyModule, O as OrgModule, t as SsoModule, u as AdminModule, v as ApiKeyManagerModule, w as UsernameAuthModule, x as PasswordResetModule, y as EmailVerificationModule, z as OneTimeTokenModule, B as SessionFreshnessModule, F as PhoneAuthModule, G as CaptchaModule, W as WebhookModule$1, H as EvaluateInput, I as PolicyDecision, J as InvalidateScope, L as PolicyCacheStats, N as PluginEndpoint, Q as EndpointContext, X as KavachPlugin, Y as SessionConfig, Z as Session } from './types-D1sBnWrs.js';
4
- export { _ as AdminConfig, $ as AdminUser, a0 as AgentConfig, a1 as ApiKey, a2 as ApiKeyManagerConfig, a3 as ApprovalConfig, a4 as ApprovalModule, a5 as AuthAdapter, a6 as CaptchaConfig, a7 as CaptchaVerifyResult, a8 as CreateTokenInput, a9 as D1DatabaseBinding, aa as EmailOtpConfig, ab as EmailVerificationConfig, ac as KavachHooks, ad as KavachInstance, ae as MagicLinkConfig, af as McpMiddleware, ag as OidcProvider, ah as OneTimeTokenConfig, ai as OneTimeTokenPurpose, aj as OrgConfig, ak as OrgInvitation, al as OrgMember, am as OrgRole, an as Organization, ao as PasskeyConfig, ap as PasskeyCredential, aq as PasswordResetConfig, ar as PermissionConstraints, as as PhoneAuthConfig, at as PluginContext, au as PluginInitResult, av as RevokeTokensResult, aw as SSO_ERROR, ax as SamlProvider, ay as ServiceEndpoint, az as SessionFreshnessConfig, aA as SsoAuditEvent, aB as SsoConfig, aC as SsoConnection, aD as SsoError, aE as TokenValidationResult, aF as TotpConfig, aG as TotpSetup, aH as UsernameAuthConfig, aI as ValidateTokenResult, aJ as VerificationMethod, aK as agentCards, aL as agentDids, aM as agents, aN as apiKeysTable, aO as approvalRequests, aP as auditLogs, aQ as budgetPolicies, aR as classifyViolation, aS as createAdminModule, aT as createApiKeyManagerModule, aU as createApprovalModule, aV as createCaptchaModule, aW as createDatabase, aX as createDatabaseSync, aY as createEmailOtpModule, aZ as createEmailVerificationModule, a_ as createMagicLinkModule, a$ as createOneTimeTokenModule, b0 as createOrgModule, b1 as createPasskeyModule, b2 as createPasswordResetModule, b3 as createPhoneAuthModule, b4 as createSessionFreshnessModule, b5 as createSessionManager, b6 as createSsoModule, b7 as createTotpModule, b8 as createUsernameAuthModule, b9 as delegationChains, ba as emailOtps, bb as magicLinks, bc as mcpServers, bd as oauthAccessTokens, be as oauthAuthorizationCodes, bf as oauthClients, bg as orgInvitations, bh as orgMembers, bi as orgRoles, bj as organizations, bk as passkeyChallenges, bl as passkeyCredentials, bm as permissions, bn as rateLimits, bo as sessions, bp as ssoConnections, bq as tenants, br as totpRecords, bs as trustScores, bt as users } from './types-D1sBnWrs.js';
3
+ import { D as Database, a as DatabaseConfig, T as TheAuthConfig, b as DelegateInput, P as Permission, c as DelegationChain, d as DidDocument, e as DidKeyPair, f as DidWebConfig, g as AgentDid, S as SignedPayload, V as VerificationResult, h as PluginEndpoint, E as EndpointContext, i as TheAuthPlugin, j as SessionManager, k as SessionConfig, l as Session, C as CreateAgentInput, A as AgentIdentity, m as AgentFilter, U as UpdateAgentInput, n as AuthorizeRequest, R as RequestContext, o as AuthorizeResult, p as AuditFilter, q as AuditEntry, r as AuditExportOptions, M as McpServerInput, s as McpServer, t as ResolvedUser, u as ApprovalRequest, v as MagicLinkModule, w as EmailOtpModule, x as TotpModule, y as PasskeyModule, O as OrgModule, z as SsoModule, B as AdminModule, F as ApiKeyManagerModule, G as UsernameAuthModule, H as PasswordResetModule, I as EmailVerificationModule, J as OneTimeTokenModule, K as SessionFreshnessModule, L as PhoneAuthModule, N as CaptchaModule, W as WebhookModule$1, Q as EvaluateInput, X as PolicyDecision, Y as InvalidateScope, Z as PolicyCacheStats } from './types-JOx1R8-Q.js';
4
+ export { _ as AdminConfig, $ as AdminUser, a0 as AgentConfig, a1 as ApiKey, a2 as ApiKeyManagerConfig, a3 as ApprovalConfig, a4 as ApprovalModule, a5 as AuthAdapter, a6 as AuthConfig, a7 as AuthHooks, a8 as AuthInstance, a9 as AuthPlugin, aa as CaptchaConfig, ab as CaptchaVerifyResult, ac as CreateTokenInput, ad as D1DatabaseBinding, ae as EmailOtpConfig, af as EmailVerificationConfig, ag as MagicLinkConfig, ah as McpMiddleware, ai as OidcProvider, aj as OneTimeTokenConfig, ak as OneTimeTokenPurpose, al as OrgConfig, am as OrgInvitation, an as OrgMember, ao as OrgRole, ap as Organization, aq as PasskeyConfig, ar as PasskeyCredential, as as PasswordResetConfig, at as PermissionConstraints, au as PhoneAuthConfig, av as PluginContext, aw as PluginInitResult, ax as RevokeTokensResult, ay as SSO_ERROR, az as SamlProvider, aA as ServiceEndpoint, aB as SessionFreshnessConfig, aC as SsoAuditEvent, aD as SsoConfig, aE as SsoConnection, aF as SsoError, aG as TheAuthHooks, aH as TheAuthInstance, aI as TokenValidationResult, aJ as TotpConfig, aK as TotpSetup, aL as UsernameAuthConfig, aM as ValidateTokenResult, aN as VerificationMethod, aO as agentCards, aP as agentDids, aQ as agents, aR as apiKeysTable, aS as approvalRequests, aT as auditLogs, aU as budgetPolicies, aV as classifyViolation, aW as createAdminModule, aX as createApiKeyManagerModule, aY as createApprovalModule, aZ as createCaptchaModule, a_ as createDatabase, a$ as createDatabaseSync, b0 as createEmailOtpModule, b1 as createEmailVerificationModule, b2 as createMagicLinkModule, b3 as createOneTimeTokenModule, b4 as createOrgModule, b5 as createPasskeyModule, b6 as createPasswordResetModule, b7 as createPhoneAuthModule, b8 as createSessionFreshnessModule, b9 as createSessionManager, ba as createSsoModule, bb as createTotpModule, bc as createUsernameAuthModule, bd as delegationChains, be as emailOtps, bf as magicLinks, bg as mcpServers, bh as oauthAccessTokens, bi as oauthAuthorizationCodes, bj as oauthClients, bk as orgInvitations, bl as orgMembers, bm as orgRoles, bn as organizations, bo as passkeyChallenges, bp as passkeyCredentials, bq as permissions, br as rateLimits, bs as sessions, bt as ssoConnections, bu as tenants, bv as totpRecords, bw as trustScores, bx as users } from './types-JOx1R8-Q.js';
5
5
  export { createAuditModule } from './audit/index.js';
6
6
  export { AccessTokenClaims, AdditionalFieldsConfig, AdditionalFieldsModule, AnonymousAuthConfig, AnonymousAuthModule, AuthorizeParams, BearerAuthOptions, BudgetCheckResult, CheckParams, CheckResult, CheckoutOptions, CostAlert, CostAttributionConfig, CostAttributionModule, CostReport, CreateEphemeralSessionInput, CustomSessionConfig, CustomSessionModule, DEFAULT_ATLASSIAN_SCOPES, DEFAULT_DISCORD_SCOPES, DEFAULT_DROPBOX_SCOPES, DEFAULT_FIGMA_SCOPES, DEFAULT_NOTION_SCOPES, DEFAULT_REDDIT_SCOPES, DEFAULT_SLACK_SCOPES, DEFAULT_SPOTIFY_SCOPES, DEFAULT_TWITCH_SCOPES, DEFAULT_ZOOM_SCOPES, DeleteOptions, DeleteResult, DeviceAuthConfig, DeviceAuthModule, DeviceAuthStatus, DeviceCodeResponse, EVENT_TYPES, EndpointGroup, EndpointLimit, EphemeralSession, EphemeralSessionConfig, EphemeralSessionModule, EphemeralSessionValidateResult, EventStreamConfig, EventStreamModule, EventType, ExpandParams, FederatedAgent, FederationConfig, FederationModule, FederationToken, FederationWellKnown, FieldDefinition, GdprModule, GenericOIDCConfig, GetUserClaimsFn, GoogleUser, HeaderAuthOptions, HibpApiError, HibpBreachedError, HibpConfig, HibpModule, InstanceIdentity, IssueFederationTokenInput, JsonWebKeySet, JwtSessionConfig, JwtSessionModule, KVNamespace, KVStore, LastLoginConfig, LastLoginModule, ListObjectsParams, ListSubjectsParams, LoginEvent, LoginMethod, MemoryStore, OAuthAccount, OAuthCallbackResult, OAuthModule, OAuthModuleConfig, OAuthPluginConfig, OAuthProvider, OAuthProviderConfig, OAuthProxyConfig, OAuthProxyError, OAuthProxyModule, OAuthProxyPluginConfig, OAuthTokens, OAuthUserInfo, OidcClient, OidcDiscoveryDocument, OidcProviderConfig, OidcProviderModule, OneTapConfig, OneTapModule, OneTapVerifyError, OpenApiComponents, OpenApiConfig, OpenApiDocument, OpenApiInfo, OpenApiMediaType, OpenApiModule, OpenApiOperation, OpenApiParameter, OpenApiPathItem, OpenApiRequestBody, OpenApiResponse, OpenApiSchema, OpenApiSecurityRequirement, OpenApiSecurityScheme, OpenApiServer, PermissionRuleSet, PolarConfig, PolarModule, PolarSubscription, ProxyTokens, RateLimitConfig, RateLimitMiddlewareOptions, RateLimitPluginConfig, RateLimitResult, RateLimitStore, RateLimiter, ReBACConfig, ReBACModule, RecordCostInput, RecordLoginInput, RegisterClientInput, Relationship, ResourceNode, ScimConfig, ScimGroup, ScimModule, ScimUser, SessionTokens, SessionUser, SiweConfig, SiweModule, SiweVerifyResult, StreamEvent, StripeConfig, StripeModule, SubscriptionInfo, TokenParams, TokenResponse, TrustLevel, TrustedDevice, TrustedDeviceConfig, TrustedDeviceModule, TrustedInstance, TwoFactorConfig, UserDataExport, UserInfoClaims, ValidationResult, VerifiedSession, additionalFields, admin, anonymousAuth, apiKeys, atlassianProvider, auth0Provider, bearerAuth, bitbucketProvider, cognitoProvider, coinbaseProvider, createAdditionalFieldsModule, createAnonymousAuthModule, createAppleProvider, createAtlassianProvider, createCostAttributionModule, createCustomSessionModule, createDeviceAuthModule, createDiscordProvider, createDropboxProvider, createEphemeralSessionModule, createEventStreamModule, createFederationModule, createFigmaProvider, createGdprModule, createGithubProvider, createGitlabProvider, createGoogleProvider, createHibpModule, createJwtSessionModule, createLastLoginModule, createLinkedInProvider, createMicrosoftProvider, createNotionProvider, createOAuthModule, createOAuthProxyModule, createOidcProviderModule, createOneTapModule, createOpenApiModule, createPolarModule, createRateLimiter, createReBACModule, createRedditProvider, createScimModule, createSiweModule, createSlackProvider, createSpotifyProvider, createStripeModule, createTrustedDeviceModule, createTwitchProvider, createTwitterProvider, createZoomProvider, customAuth, customSession, deviceAuth, deviceLabelFromRequest, dropboxProvider, emailOtp, facebookProvider, figmaProvider, gdpr, genericOIDC, headerAuth, huggingfaceProvider, kakaoProvider, kickProvider, kvStore, lineProvider, linearProvider, magicLink, naverProvider, normalizeAtlassianProfile, normalizeDiscordProfile, normalizeDropboxProfile, normalizeFigmaProfile, normalizeNotionProfile, normalizeRedditProfile, normalizeSlackProfile, normalizeSpotifyProfile, normalizeTwitchProfile, normalizeZoomProfile, notionProvider, oauth, oauthProxy, oktaProvider, oneTap, organization, passkey, paypalProvider, polar, polarProvider, railwayProvider, rateLimit, redditProvider, robloxProvider, salesforceProvider, scim, siwe, spotifyProvider, stripe, tiktokProvider, twitchProvider, twoFactor, vercelProvider, vkProvider, wechatProvider, withRateLimit, yahooProvider, zoomProvider } from './auth/index.js';
7
7
  export { constantTimeEqual, fromBase64Url, fromHex, generateId, hmacSha1Raw, hmacSha256, hmacSha256Raw, importHmacKey, pbkdf2Hash, pbkdf2Verify, randomBytes, randomBytesHex, sha1, sha256, sha256Raw, toBase64Url, toHex } from './crypto/index.js';
8
+ export { PermissionTemplateName, createPermissionEngine, getPermissionTemplate, permissionTemplates } from './permission/index.js';
8
9
  import { RedirectChainManager } from './redirect/index.js';
9
10
  export { RedirectChainState, RedirectConfig, RedirectEntry, createRedirectChain } from './redirect/index.js';
10
- export { PermissionTemplateName, createPermissionEngine, getPermissionTemplate, permissionTemplates } from './permission/index.js';
11
- export { AuditCredentialSubject, AuditExportResult, AuditRecord, CredentialFormat, CredentialStatus, CredentialStatusSchema, CredentialSubject, CredentialSubjectSchema, DelegationLink, ExportAuditOptions, ExtractedPermissions, IssueAgentCredentialInput, IssueDelegationCredentialInput, IssuePermissionCredentialInput, KAVACH_AGENT_CREDENTIAL, KAVACH_DELEGATION_CREDENTIAL, KAVACH_PERMISSION_CREDENTIAL, Proof, ProofSchema, THEAUTH_AUDIT_CONTEXT, THEAUTH_AUDIT_CREDENTIAL, VCIssuer, VCIssuerConfig, VCJwtPayload, VCVerifier, VCVerifierConfig, VC_CONTEXT_V1, VC_CONTEXT_V2, VC_TYPE_CREDENTIAL, VC_TYPE_PRESENTATION, VerifiableCredential, VerifiableCredentialSchema, VerifiablePresentation, VerifiablePresentationSchema, VerifiedCredential, VerifiedPresentation, createVCIssuer, createVCVerifier, exportAuditAsVC, listAuditRecords } from './vc/index.js';
11
+ export { AUTH_AGENT_CREDENTIAL, AUTH_DELEGATION_CREDENTIAL, AUTH_PERMISSION_CREDENTIAL, AuditCredentialSubject, AuditExportResult, AuditRecord, CredentialFormat, CredentialStatus, CredentialStatusSchema, CredentialSubject, CredentialSubjectSchema, DelegationLink, ExportAuditOptions, ExtractedPermissions, IssueAgentCredentialInput, IssueDelegationCredentialInput, IssuePermissionCredentialInput, Proof, ProofSchema, THEAUTH_AGENT_CREDENTIAL, THEAUTH_AUDIT_CONTEXT, THEAUTH_AUDIT_CREDENTIAL, THEAUTH_DELEGATION_CREDENTIAL, THEAUTH_PERMISSION_CREDENTIAL, VCIssuer, VCIssuerConfig, VCJwtPayload, VCVerifier, VCVerifierConfig, VC_CONTEXT_V1, VC_CONTEXT_V2, VC_TYPE_CREDENTIAL, VC_TYPE_PRESENTATION, VerifiableCredential, VerifiableCredentialSchema, VerifiablePresentation, VerifiablePresentationSchema, VerifiedCredential, VerifiedPresentation, createVCIssuer, createVCVerifier, exportAuditAsVC, listAuditRecords } from './vc/index.js';
12
12
  import 'drizzle-orm/sqlite-core';
13
- import './types-BiUe9e8u.js';
13
+ import './types-XoCxTUZj.js';
14
14
  import 'zod';
15
15
  import './standards/index.js';
16
16
  import 'jose';
@@ -60,32 +60,20 @@ declare function createPrivilegeAnalyzer(db: Database): {
60
60
  };
61
61
  type PrivilegeAnalyzer = ReturnType<typeof createPrivilegeAnalyzer>;
62
62
 
63
- /**
64
- * Create TheAuth tables if they do not already exist.
65
- *
66
- * Uses `CREATE TABLE IF NOT EXISTS` so it is safe to call on every startup.
67
- * Tables are created in dependency order (no forward-reference FK issues).
68
- *
69
- * When `config` is provided, only tables required by the configured features
70
- * are created. When omitted, all tables are created (backward-compatible
71
- * behaviour for callers that do not pass a config).
72
- *
73
- * @param db Drizzle database instance returned by `createDatabase()`.
74
- * @param provider The database provider used to build the correct DDL syntax.
75
- * @param config Optional KavachConfig used to determine which feature tables
76
- * to create. When absent, all tables are created.
77
- *
78
- * @example
79
- * ```typescript
80
- * const db = await createDatabase({ provider: 'postgres', url: process.env.DATABASE_URL });
81
- * await createTables(db, 'postgres');
82
- * ```
83
- */
84
- declare function createTables(db: Database, provider: DatabaseConfig["provider"], config?: KavachConfig): Promise<void>;
63
+ declare function createTables(db: Database, provider: DatabaseConfig["provider"], config?: TheAuthConfig): Promise<void>;
85
64
 
86
65
  interface DelegationModuleConfig {
87
66
  db: Database;
88
67
  }
68
+ type DelegationErrorCode = "DELEGATION_PERMISSION_SUBSET" | "DELEGATION_DEPTH_EXCEEDED";
69
+ /**
70
+ * Typed error for delegation requests that are invalid by caller input.
71
+ * Adapters map it to HTTP 400 using `code`.
72
+ */
73
+ declare class DelegationError extends Error {
74
+ readonly code: DelegationErrorCode;
75
+ constructor(code: DelegationErrorCode, message: string);
76
+ }
89
77
  /**
90
78
  * Create the delegation module.
91
79
  * Handles agent-to-agent permission delegation with chain tracking.
@@ -294,1334 +282,1342 @@ declare const ja: TranslationKeys;
294
282
  declare const zh: TranslationKeys;
295
283
 
296
284
  /**
297
- * Create a TheAuth instance.
298
- *
299
- * The factory is **async** so it can open database connections for Postgres
300
- * and MySQL (which require async driver initialisation) and optionally run
301
- * `CREATE TABLE IF NOT EXISTS` for all schema tables.
302
- *
303
- * @example SQLite (simplest)
304
- * ```typescript
305
- * import { createKavach } from '@glinr/theauth';
306
- *
307
- * const kavach = await createKavach({
308
- * database: { provider: 'sqlite', url: 'kavach.db' },
309
- * });
310
- * ```
311
- *
312
- * @example Postgres
313
- * ```typescript
314
- * const kavach = await createKavach({
315
- * database: { provider: 'postgres', url: process.env.DATABASE_URL },
316
- * });
317
- * ```
285
+ * OpenAPI 3.1 specification generator for TheAuth REST API.
318
286
  *
319
- * @example MySQL – skip auto-migration (tables managed externally)
320
- * ```typescript
321
- * const kavach = await createKavach({
322
- * database: {
323
- * provider: 'mysql',
324
- * url: process.env.DATABASE_URL,
325
- * skipMigrations: true,
326
- * },
327
- * });
328
- * ```
287
+ * This generates the spec that enables auto-generated SDKs
288
+ * for Python, Go, Java, Rust, etc. via OpenAPI codegen tools.
329
289
  */
330
- declare function createKavach(config: KavachConfig): Promise<{
331
- agent: {
332
- create(input: CreateAgentInput): ReturnType<(input: CreateAgentInput) => Promise<AgentIdentity & {
333
- token: string;
334
- }>>;
335
- revoke(agentId: string): ReturnType<(agentId: string) => Promise<void>>;
336
- rotate(agentId: string): ReturnType<(agentId: string) => Promise<AgentIdentity & {
337
- token: string;
338
- }>>;
339
- get: (agentId: string) => Promise<AgentIdentity | null>;
340
- list: (filter?: AgentFilter) => Promise<AgentIdentity[]>;
341
- update: (agentId: string, input: UpdateAgentInput) => Promise<AgentIdentity>;
342
- validateToken: (token: string) => Promise<AgentIdentity | null>;
290
+ interface OpenAPISpec {
291
+ openapi: string;
292
+ info: {
293
+ title: string;
294
+ version: string;
295
+ description: string;
343
296
  };
344
- authorize: (agentId: string, request: AuthorizeRequest, context?: RequestContext) => Promise<AuthorizeResult>;
345
- authorizeByToken: (token: string, request: AuthorizeRequest, context?: RequestContext) => Promise<AuthorizeResult>;
346
- delegate: (input: DelegateInput) => Promise<DelegationChain>;
347
- delegation: {
348
- revoke: (chainId: string) => Promise<void>;
349
- getEffectivePermissions: (agentId: string) => Promise<Permission[]>;
350
- listChains: (agentId: string) => Promise<DelegationChain[]>;
297
+ servers: Array<{
298
+ url: string;
299
+ description: string;
300
+ }>;
301
+ paths: Record<string, Record<string, PathOperation>>;
302
+ components: {
303
+ schemas: Record<string, SchemaObject>;
304
+ securitySchemes: Record<string, SecurityScheme>;
351
305
  };
352
- audit: {
353
- query: (filter: AuditFilter) => Promise<AuditEntry[]>;
354
- export: (options: AuditExportOptions) => Promise<string>;
355
- cleanup: (options: {
356
- retentionDays: number;
357
- }) => Promise<{
358
- deleted: number;
306
+ }
307
+ interface PathOperation {
308
+ summary: string;
309
+ operationId: string;
310
+ tags: string[];
311
+ security?: Array<Record<string, string[]>>;
312
+ parameters?: ParameterObject[];
313
+ requestBody?: {
314
+ required: boolean;
315
+ content: Record<string, {
316
+ schema: SchemaRef;
359
317
  }>;
360
318
  };
361
- /**
362
- * MCP server registration.
363
- *
364
- * Register and look up MCP tool servers. Uses the `kavach_mcp_servers`
365
- * database table — no separate in-memory store needed.
366
- */
367
- mcp: {
368
- /**
369
- * Register a new MCP tool server.
370
- *
371
- * Persists the server entry to the `kavach_mcp_servers` table.
372
- * The returned record includes the generated `id` and `createdAt`.
373
- */
374
- register(input: McpServerInput): Promise<McpServer>;
375
- /**
376
- * List all registered MCP servers (active and inactive).
377
- */
378
- list(): Promise<McpServer[]>;
379
- /**
380
- * Get a single MCP server by ID. Returns null when not found.
381
- */
382
- get(id: string): Promise<McpServer | null>;
319
+ responses: Record<string, {
320
+ description: string;
321
+ content?: Record<string, {
322
+ schema: SchemaRef;
323
+ }>;
324
+ }>;
325
+ }
326
+ interface ParameterObject {
327
+ name: string;
328
+ in: "query" | "path" | "header";
329
+ required: boolean;
330
+ schema: SchemaRef;
331
+ }
332
+ interface SecurityScheme {
333
+ type: string;
334
+ scheme?: string;
335
+ bearerFormat?: string;
336
+ }
337
+ type SchemaRef = {
338
+ $ref: string;
339
+ } | SchemaObject;
340
+ interface SchemaObject {
341
+ type?: string;
342
+ properties?: Record<string, SchemaRef>;
343
+ required?: string[];
344
+ items?: SchemaRef;
345
+ enum?: string[];
346
+ description?: string;
347
+ format?: string;
348
+ nullable?: boolean;
349
+ }
350
+ /**
351
+ * Generate the full OpenAPI 3.1 specification for the TheAuth REST API.
352
+ */
353
+ declare function generateOpenAPISpec(options?: {
354
+ baseUrl?: string;
355
+ version?: string;
356
+ }): OpenAPISpec;
357
+
358
+ /**
359
+ * Create a plugin router that matches requests to registered plugin endpoints.
360
+ *
361
+ * The router strips `basePath` from the request URL before matching so plugins
362
+ * register paths relative to the mount point (e.g. `/auth/sign-in` instead
363
+ * of `/api/theauth/auth/sign-in`).
364
+ */
365
+ declare function createPluginRouter(endpoints: PluginEndpoint[]): {
366
+ /** Try to handle a request. Returns Response if matched, null if not. */
367
+ handle: (request: Request, basePath: string, endpointCtx: EndpointContext) => Promise<Response | null>;
368
+ /** Get all registered endpoints (for adapter mounting) */
369
+ getEndpoints: () => PluginEndpoint[];
370
+ };
371
+
372
+ interface PluginRegistry {
373
+ endpoints: PluginEndpoint[];
374
+ migrations: string[];
375
+ hooks: {
376
+ onRequest: Array<NonNullable<TheAuthPlugin["hooks"]>["onRequest"]>;
377
+ onAuthenticate: Array<NonNullable<TheAuthPlugin["hooks"]>["onAuthenticate"]>;
378
+ onSessionCreate: Array<NonNullable<TheAuthPlugin["hooks"]>["onSessionCreate"]>;
379
+ onSessionRevoke: Array<NonNullable<TheAuthPlugin["hooks"]>["onSessionRevoke"]>;
383
380
  };
381
+ pluginContext: Record<string, unknown>;
382
+ }
383
+ /**
384
+ * Initialize all plugins and collect their endpoints, migrations, and hooks
385
+ * into a single registry.
386
+ *
387
+ * Calls each plugin's `init()` in registration order. Migrations collected
388
+ * during init are executed before the registry is returned so that any
389
+ * subsequent requests can immediately use plugin tables.
390
+ */
391
+ declare function initializePlugins(plugins: TheAuthPlugin[], db: Database, config: TheAuthConfig, sessionManager: SessionManager | null): Promise<PluginRegistry>;
392
+
393
+ interface BudgetPolicy {
394
+ id: string;
395
+ agentId?: string;
396
+ userId?: string;
397
+ tenantId?: string;
398
+ limits: BudgetLimits;
399
+ currentUsage: BudgetUsage;
400
+ action: "warn" | "throttle" | "block" | "revoke";
401
+ status: "active" | "triggered" | "disabled";
402
+ createdAt: Date;
403
+ }
404
+ interface BudgetLimits {
405
+ maxTokensCostPerDay?: number;
406
+ maxTokensCostPerMonth?: number;
407
+ maxCallsPerDay?: number;
408
+ maxCallsPerMonth?: number;
409
+ }
410
+ interface BudgetUsage {
411
+ tokensCostToday: number;
412
+ tokensCostThisMonth: number;
413
+ callsToday: number;
414
+ callsThisMonth: number;
415
+ lastUpdated: string;
416
+ }
417
+ interface CreatePolicyInput {
418
+ agentId?: string;
419
+ userId?: string;
420
+ tenantId?: string;
421
+ limits: BudgetLimits;
422
+ action: "warn" | "throttle" | "block" | "revoke";
423
+ }
424
+ interface PolicyFilters {
425
+ agentId?: string;
426
+ userId?: string;
427
+ tenantId?: string;
428
+ }
429
+ declare function createPolicyModule(db: Database): {
430
+ create: (input: CreatePolicyInput) => Promise<BudgetPolicy>;
431
+ get: (policyId: string) => Promise<BudgetPolicy | null>;
432
+ list: (filters?: PolicyFilters) => Promise<BudgetPolicy[]>;
433
+ update: (policyId: string, updates: Partial<BudgetPolicy>) => Promise<BudgetPolicy>;
434
+ remove: (policyId: string) => Promise<void>;
435
+ checkBudget: (agentId: string, tokensCost?: number) => Promise<{
436
+ allowed: boolean;
437
+ reason?: string;
438
+ policy?: BudgetPolicy;
439
+ }>;
440
+ recordUsage: (agentId: string, tokensCost?: number) => Promise<void>;
441
+ resetDaily: () => Promise<{
442
+ reset: number;
443
+ }>;
444
+ resetMonthly: () => Promise<{
445
+ reset: number;
446
+ }>;
447
+ };
448
+
449
+ /**
450
+ * Cookie serialization and parsing utilities for TheAuth.
451
+ *
452
+ * Pure functions that work with Web API `Request`/`Response` objects and
453
+ * raw header strings. No framework dependencies.
454
+ */
455
+ type SameSite = "strict" | "lax" | "none";
456
+ interface CookieOptions {
457
+ /** Prevents JavaScript access to the cookie. Default: true. */
458
+ httpOnly?: boolean;
384
459
  /**
385
- * Least-privilege analyzer.
386
- *
387
- * Compare agent permissions against actual audit log usage to surface
388
- * wildcards, unused grants, and over-permissioned identities.
460
+ * Restricts transmission to HTTPS. Default: true in production
461
+ * (when `NODE_ENV === 'production'`), false otherwise.
389
462
  */
390
- analyzer: {
391
- analyzeAgent: (agentId: string, options?: {
392
- since?: Date;
393
- }) => Promise<PrivilegeAnalysis>;
394
- analyzeAll: (options?: {
395
- since?: Date;
396
- }) => Promise<PrivilegeAnalysis[]>;
397
- getSummary: () => Promise<PrivilegeSummary>;
398
- };
399
- /**
400
- * Human auth integration.
401
- *
402
- * `resolveUser` extracts the authenticated human from an inbound HTTP
403
- * request via the configured adapter. `session` is a full session
404
- * manager (create / validate / revoke) when `auth.session` was passed
405
- * to `createKavach()`.
406
- *
407
- * @example
408
- * ```typescript
409
- * app.use(async (req, res, next) => {
410
- * const user = await kavach.auth.resolveUser(req);
411
- * if (!user) return res.status(401).json({ error: 'Unauthorized' });
412
- * req.user = user;
413
- * next();
414
- * });
415
- * ```
416
- */
417
- auth: {
418
- resolveUser(request: Request): Promise<ResolvedUser | null>;
419
- session: SessionManager | null;
420
- };
421
- /**
422
- * Resolve a human user from an incoming HTTP request.
423
- *
424
- * @deprecated Use `kavach.auth.resolveUser(request)` instead.
425
- */
426
- resolveUser(request: Request): Promise<ResolvedUser | null>;
427
- /** Direct database access for advanced usage */
428
- db: Database;
429
- /**
430
- * Multi-tenant isolation.
431
- *
432
- * Create and manage tenants (organizations) that share a single
433
- * TheAuth instance with full data isolation. Agents can be scoped
434
- * to a tenant via `tenantId`.
435
- */
436
- tenant: {
437
- create: (input: CreateTenantInput) => Promise<Tenant>;
438
- get: (tenantId: string) => Promise<Tenant | null>;
439
- getBySlug: (slug: string) => Promise<Tenant | null>;
440
- list: () => Promise<Tenant[]>;
441
- update: (tenantId: string, updates: Partial<CreateTenantInput>) => Promise<Tenant>;
442
- suspend: (tenantId: string) => Promise<void>;
443
- activate: (tenantId: string) => Promise<void>;
444
- };
445
- /**
446
- * Agent execution budget policies.
447
- *
448
- * Set spending caps (token cost, call counts) per agent, user, or
449
- * tenant. Exceeded policies trigger a configurable action: warn,
450
- * throttle, block, or revoke.
451
- */
452
- policies: {
453
- create: (input: CreatePolicyInput) => Promise<BudgetPolicy>;
454
- get: (policyId: string) => Promise<BudgetPolicy | null>;
455
- list: (filters?: PolicyFilters) => Promise<BudgetPolicy[]>;
456
- update: (policyId: string, updates: Partial<BudgetPolicy>) => Promise<BudgetPolicy>;
457
- remove: (policyId: string) => Promise<void>;
458
- checkBudget: (agentId: string, tokensCost?: number) => Promise<{
459
- allowed: boolean;
460
- reason?: string;
461
- policy?: BudgetPolicy;
462
- }>;
463
- recordUsage: (agentId: string, tokensCost?: number) => Promise<void>;
464
- resetDaily: () => Promise<{
465
- reset: number;
466
- }>;
467
- resetMonthly: () => Promise<{
468
- reset: number;
469
- }>;
470
- };
471
- /**
472
- * CIBA-style async human approval flows.
473
- *
474
- * Create pending approval requests, notify humans via webhook or
475
- * custom handler, and resolve them with approve / deny.
476
- */
477
- approval: {
478
- request: (input: {
479
- agentId: string;
480
- userId: string;
481
- action: string;
482
- resource: string;
483
- arguments?: Record<string, unknown>;
484
- }) => Promise<ApprovalRequest>;
485
- approve: (requestId: string, respondedBy?: string) => Promise<ApprovalRequest>;
486
- deny: (requestId: string, respondedBy?: string) => Promise<ApprovalRequest>;
487
- get: (requestId: string) => Promise<ApprovalRequest | null>;
488
- listPending: (userId?: string) => Promise<ApprovalRequest[]>;
489
- cleanup: () => Promise<{
490
- expired: number;
491
- }>;
492
- };
493
- /**
494
- * Graduated autonomy trust scoring.
495
- *
496
- * Compute and persist 0-100 trust scores derived from audit history,
497
- * mapped to five levels: untrusted, limited, standard, trusted, elevated.
498
- */
499
- trust: {
500
- computeScore: (agentId: string) => Promise<TrustScore>;
501
- getScore: (agentId: string) => Promise<TrustScore | null>;
502
- computeAll: () => Promise<TrustScore[]>;
503
- getScores: (filters?: {
504
- level?: string;
505
- minScore?: number;
506
- }) => Promise<TrustScore[]>;
507
- };
508
- /**
509
- * W3C Decentralized Identifiers (DID) for agents.
510
- *
511
- * Generate did:key or did:web identities, sign payloads, and verify
512
- * signatures. Private keys are never stored — they are returned to
513
- * the caller on generation and must be stored securely.
514
- *
515
- * @example
516
- * ```typescript
517
- * const { agentDid, privateKeyJwk } = await kavach.did.generateKey(agentId);
518
- * const signed = await kavach.did.sign(agentId, { action: 'read' }, privateKeyJwk);
519
- * const result = await kavach.did.verify(signed.jws, agentDid.did);
520
- * ```
521
- */
522
- did: {
523
- generateKey: (agentId: string) => Promise<{
524
- agentDid: AgentDid;
525
- privateKeyJwk: JsonWebKey;
526
- }>;
527
- generateWeb: (agentId: string) => Promise<{
528
- agentDid: AgentDid;
529
- privateKeyJwk: JsonWebKey;
530
- }>;
531
- resolve: (did: string) => Promise<DidDocument | null>;
532
- getAgentDid: (agentId: string) => Promise<AgentDid | null>;
533
- sign: (agentId: string, payload: Record<string, unknown>, privateKeyJwk: JsonWebKey) => Promise<SignedPayload>;
534
- verify: (jws: string, did?: string) => Promise<VerificationResult>;
535
- createPresentation: (options: {
536
- agentId: string;
537
- privateKeyJwk: JsonWebKey;
538
- capabilities: string[];
539
- audience?: string;
540
- expiresIn?: number;
541
- }) => Promise<string>;
542
- verifyPresentation: (jwt: string) => Promise<VerificationResult & {
543
- capabilities?: string[];
544
- }>;
545
- };
546
- /**
547
- * Magic link (passwordless email) authentication.
548
- *
549
- * Null when `magicLink` config was not provided or `auth.session` is not
550
- * configured (sessions are required to issue tokens on verification).
551
- *
552
- * @example
553
- * ```typescript
554
- * // In your route handler
555
- * const response = await kavach.magicLink?.handleRequest(request);
556
- * if (response) return response;
557
- * ```
558
- */
559
- magicLink: MagicLinkModule | null;
560
- /**
561
- * Email OTP (one-time password) authentication.
562
- *
563
- * Null when `emailOtp` config was not provided or `auth.session` is not
564
- * configured.
565
- *
566
- * @example
567
- * ```typescript
568
- * const response = await kavach.emailOtp?.handleRequest(request);
569
- * if (response) return response;
570
- * ```
571
- */
572
- emailOtp: EmailOtpModule | null;
573
- /**
574
- * TOTP two-factor authentication.
575
- *
576
- * Null when `totp` config was not provided.
577
- *
578
- * @example
579
- * ```typescript
580
- * // On setup (show QR code to user)
581
- * const { secret, uri, backupCodes } = await kavach.totp.setup(userId);
582
- *
583
- * // After user scans QR and enters code
584
- * const { enabled } = await kavach.totp.enable(userId, totpCode);
585
- *
586
- * // On login (after password check)
587
- * const { valid } = await kavach.totp.verify(userId, totpCode);
588
- * ```
589
- */
590
- totp: TotpModule | null;
591
- /**
592
- * Passkey / WebAuthn authentication.
593
- *
594
- * Null when `passkey` config was not provided.
595
- *
596
- * @example
597
- * ```typescript
598
- * // Registration — step 1: get options, send to browser
599
- * const options = await kavach.passkey.getRegistrationOptions(userId, userName);
600
- *
601
- * // Registration — step 2: verify browser response
602
- * const { credential } = await kavach.passkey.verifyRegistration(userId, response);
603
- *
604
- * // Authentication — step 1: get options
605
- * const options = await kavach.passkey.getAuthenticationOptions(userId);
606
- *
607
- * // Authentication — step 2: verify browser response
608
- * const result = await kavach.passkey.verifyAuthentication(response);
609
- * if (result) console.log('Authenticated user:', result.userId);
610
- * ```
611
- */
612
- passkey: PasskeyModule | null;
613
- /**
614
- * Organizations + RBAC.
615
- *
616
- * Null when `org` config was not provided.
617
- *
618
- * @example
619
- * ```typescript
620
- * const org = await kavach.org?.create({ name: 'Acme', slug: 'acme', ownerId: userId });
621
- * const allowed = await kavach.org?.hasPermission(org.id, userId, 'agents:create');
622
- * ```
623
- */
624
- org: OrgModule | null;
625
- /**
626
- * SSO (SAML 2.0 + OIDC) enterprise authentication.
627
- *
628
- * Null when `sso` config was not provided.
629
- *
630
- * @example
631
- * ```typescript
632
- * const conn = await kavach.sso?.createConnection({ orgId, providerId: 'okta', type: 'saml', domain: 'acme.com' });
633
- * const url = await kavach.sso?.getSamlAuthUrl(conn.id);
634
- * ```
635
- */
636
- sso: SsoModule | null;
637
- /**
638
- * Admin module.
639
- *
640
- * Null when `admin` config was not provided.
641
- *
642
- * @example
643
- * ```typescript
644
- * await kavach.admin?.banUser(userId, 'Spam');
645
- * const { session } = await kavach.admin?.impersonate(adminId, userId);
646
- * ```
647
- */
648
- admin: AdminModule | null;
649
- /**
650
- * API key management.
651
- *
652
- * Null when `apiKeys` config was not provided.
653
- *
654
- * @example
655
- * ```typescript
656
- * const { key, apiKey } = await kavach.apiKeys?.create({ userId, name: 'CI', permissions: ['agents:read'] });
657
- * const result = await kavach.apiKeys?.validate(key);
658
- * ```
659
- */
660
- apiKeys: ApiKeyManagerModule | null;
661
- /**
662
- * Username + password authentication.
663
- *
664
- * Null when `username` config was not provided or `auth.session` is not
665
- * configured (sessions are required to issue tokens on sign-in/up).
666
- *
667
- * @example
668
- * ```typescript
669
- * const response = await kavach.username?.handleRequest(request);
670
- * if (response) return response;
671
- * ```
672
- */
673
- username: UsernameAuthModule | null;
674
- /**
675
- * Password reset (forgot password + reset password).
676
- *
677
- * Null when `passwordReset` config was not provided or `auth.session`
678
- * is not configured.
679
- *
680
- * @example
681
- * ```typescript
682
- * // In your route handler
683
- * const response = await kavach.passwordReset?.handleRequest(request);
684
- * if (response) return response;
685
- *
686
- * // Or programmatically
687
- * await kavach.passwordReset?.requestReset('alice@example.com');
688
- * await kavach.passwordReset?.resetPassword(token, 'new-password');
689
- * ```
690
- */
691
- passwordReset: PasswordResetModule | null;
692
- /**
693
- * Email address verification.
694
- *
695
- * Null when `emailVerification` config was not provided.
696
- *
697
- * @example
698
- * ```typescript
699
- * // Send a verification email after sign-up
700
- * await kavach.emailVerification?.sendVerification(userId, email);
701
- *
702
- * // Confirm from the link in the email
703
- * const result = await kavach.emailVerification?.verify(token);
704
- *
705
- * // Check status
706
- * const verified = await kavach.emailVerification?.isVerified(userId);
707
- * ```
708
- */
709
- emailVerification: EmailVerificationModule | null;
710
- /**
711
- * One-time tokens (email verify, password reset, invitations, custom).
712
- *
713
- * Always available. Used internally by password reset but exposed for
714
- * custom flows (email verification, invitation links, etc.).
715
- */
716
- oneTimeTokens: OneTimeTokenModule;
717
- /**
718
- * Session freshness enforcement for sensitive operations.
719
- *
720
- * Use as middleware before password changes, passkey registration,
721
- * billing updates, or any action that requires a recently-authenticated
722
- * session rather than an auto-refreshed one.
723
- *
724
- * @example
725
- * ```typescript
726
- * const stale = kavach.sessionFreshness.guard(session);
727
- * if (stale) return stale; // 403 SESSION_NOT_FRESH
728
- * ```
729
- */
730
- sessionFreshness: SessionFreshnessModule;
731
- /**
732
- * Phone number (SMS OTP) authentication.
733
- *
734
- * Null when `phone` config was not provided or `auth.session` is not
735
- * configured.
736
- *
737
- * @example
738
- * ```typescript
739
- * const response = await kavach.phone?.handleRequest(request);
740
- * if (response) return response;
741
- * ```
742
- */
743
- phone: PhoneAuthModule | null;
744
- /**
745
- * Captcha integration (reCAPTCHA, hCaptcha, Cloudflare Turnstile).
746
- *
747
- * Null when `captcha` config was not provided.
748
- *
749
- * @example
750
- * ```typescript
751
- * const result = await kavach.captcha?.verify(token, ip);
752
- * if (!result?.success) return new Response('Captcha failed', { status: 403 });
753
- * ```
754
- */
755
- captcha: CaptchaModule | null;
756
- /**
757
- * Webhook system.
758
- *
759
- * Null when `webhooks` config was not provided or the array is empty.
760
- *
761
- * @example
762
- * ```typescript
763
- * kavach.webhooks?.emit('user.created', { userId: user.id });
764
- * ```
765
- */
766
- webhooks: WebhookModule$1 | null;
767
- /**
768
- * Redirect chain manager.
769
- *
770
- * Capture the user's original destination before auth redirects, push
771
- * intermediate steps (onboarding, email verification), and pop them
772
- * back in order. Cookie-based, works across page transitions and tabs.
773
- *
774
- * @example
775
- * ```typescript
776
- * // In auth middleware — save where the user was going
777
- * const setCookie = kavach.redirects.capture(request);
778
- * return new Response(null, { status: 302, headers: { Location: '/sign-in', 'Set-Cookie': setCookie } });
779
- *
780
- * // After sign-in — send user to their original destination
781
- * const { url, clearCookie } = kavach.redirects.pop(request);
782
- * const headers: Record<string, string> = { Location: url };
783
- * if (clearCookie) headers['Set-Cookie'] = clearCookie;
784
- * return new Response(null, { status: 302, headers });
785
- * ```
786
- */
787
- redirects: RedirectChainManager;
788
- /**
789
- * Unified policy engine.
790
- *
791
- * Single decision point that combines RBAC role expansion, ABAC constraint
792
- * evaluation, and ReBAC graph queries. Backed by a process-local LRU cache
793
- * with deterministic invalidation.
794
- *
795
- * @example
796
- * ```typescript
797
- * const decision = await kavach.policy.evaluate({
798
- * subject: { agentId: 'agent-abc' },
799
- * action: 'read',
800
- * resource: 'tool:github:list_issues',
801
- * });
802
- * if (!decision.allowed) throw new Error(decision.reason);
803
- *
804
- * // Flush cached decisions after a permission change
805
- * kavach.policy.invalidate({ agentId: 'agent-abc' });
806
- *
807
- * // Inspect cache health
808
- * const { hits, misses, size, evictions } = kavach.policy.stats();
809
- * ```
810
- */
811
- policy: {
812
- evaluate: (input: EvaluateInput) => Promise<PolicyDecision>;
813
- invalidate: (scope: InvalidateScope) => void;
814
- stats: () => PolicyCacheStats;
815
- };
816
- /**
817
- * Plugin system.
818
- *
819
- * Route incoming HTTP requests through plugin-registered endpoints,
820
- * retrieve all endpoints for adapter mounting, or access plugin-provided
821
- * context values.
822
- *
823
- * @example
824
- * ```typescript
825
- * // In a framework adapter
826
- * app.all('/kavach/*', async (req) => {
827
- * const response = await kavach.plugins.handleRequest(req);
828
- * if (response) return response;
829
- * return new Response('Not Found', { status: 404 });
830
- * });
831
- * ```
832
- */
833
- plugins: {
834
- /** Route a request through plugin endpoints. Returns null if no plugin handles it. */
835
- handleRequest(request: Request, basePath?: string): Promise<Response | null>;
836
- /** Get all endpoints registered by plugins (for framework adapter mounting). */
837
- getEndpoints(): PluginEndpoint[];
838
- /** Get the merged plugin context (values returned from plugin init). */
839
- getContext(): Record<string, unknown>;
840
- /** Access the raw plugin registry (hooks, migrations, etc.). */
841
- registry: PluginRegistry;
842
- };
843
- }>;
844
- type Kavach = Awaited<ReturnType<typeof createKavach>>;
463
+ secure?: boolean;
464
+ /** Controls cross-site sending. Default: 'lax'. */
465
+ sameSite?: SameSite;
466
+ /** Cookie scope path. Default: '/'. */
467
+ path?: string;
468
+ /** Cookie scope domain (omitted when not set). */
469
+ domain?: string;
470
+ /** Lifetime in seconds from now. Sets both Max-Age and Expires. */
471
+ maxAge?: number;
472
+ /** Absolute expiry date (overridden by maxAge when both are set). */
473
+ expires?: Date;
474
+ /** Partitioned attribute (CHIPS). */
475
+ partitioned?: boolean;
476
+ }
477
+ /**
478
+ * Serialize a cookie name/value pair into a `Set-Cookie` header string.
479
+ *
480
+ * @param name Cookie name. Must be a valid cookie-name token.
481
+ * @param value Cookie value. Will be percent-encoded.
482
+ * @param options Cookie attributes. Defaults to `httpOnly=true`, `secure`
483
+ * based on `NODE_ENV`, `sameSite=lax`, `path=/`.
484
+ */
485
+ declare function serializeCookie(name: string, value: string, options?: CookieOptions): string;
486
+ /**
487
+ * Serialize a deletion cookie (zero Max-Age, past Expires) that will
488
+ * instruct browsers to remove the named cookie.
489
+ */
490
+ declare function serializeCookieDeletion(name: string, options?: Omit<CookieOptions, "maxAge" | "expires">): string;
491
+ /**
492
+ * Parse a `Cookie` request header string into a name → value map.
493
+ *
494
+ * Values are percent-decoded. Unknown or malformed pairs are skipped
495
+ * silently so that a single bad cookie does not break the entire request.
496
+ *
497
+ * @param header The raw value of the `Cookie` header (e.g. `"a=1; b=2"`).
498
+ */
499
+ declare function parseCookies(header: string): Record<string, string>;
500
+ /**
501
+ * Extract a single cookie value from a `Cookie` header string.
502
+ *
503
+ * Returns `undefined` when the cookie is absent.
504
+ */
505
+ declare function getCookie(header: string, name: string): string | undefined;
506
+ /**
507
+ * Extract cookies from a Web API `Request` object.
508
+ */
509
+ declare function parseCookiesFromRequest(request: Request): Record<string, string>;
845
510
 
846
511
  /**
847
- * OpenAPI 3.1 specification generator for TheAuth REST API.
512
+ * CSRF protection utilities for TheAuth.
513
+ *
514
+ * Implements two complementary defences:
515
+ *
516
+ * 1. **Origin/Referer validation** — checks the inbound request's `Origin`
517
+ * (or `Referer` as fallback) against a caller-supplied allowlist. This
518
+ * alone blocks the vast majority of CSRF attacks from browser clients.
519
+ *
520
+ * 2. **Double-submit cookie pattern** — a random token is stored in a cookie
521
+ * AND submitted by the client as a request header (or body field). The
522
+ * server verifies both values match using a timing-safe comparison.
523
+ *
524
+ * Use origin validation first; fall back to token comparison when the origin
525
+ * header is absent (e.g. same-origin requests on some browsers, server-side
526
+ * fetch).
848
527
  *
849
- * This generates the spec that enables auto-generated SDKs
850
- * for Python, Go, Java, Rust, etc. via OpenAPI codegen tools.
528
+ * @example
529
+ * ```typescript
530
+ * import { generateCsrfToken, validateCsrfToken, validateOrigin } from './csrf.js';
531
+ *
532
+ * // On form render: store token in cookie, embed in hidden field.
533
+ * const token = await generateCsrfToken();
534
+ *
535
+ * // On form submit:
536
+ * const originOk = validateOrigin(request, ['https://app.example.com']);
537
+ * const tokenOk = validateCsrfToken(submittedToken, cookieToken);
538
+ * if (!originOk && !tokenOk) throw new Error('CSRF check failed');
539
+ * ```
851
540
  */
852
- interface OpenAPISpec {
853
- openapi: string;
854
- info: {
855
- title: string;
856
- version: string;
857
- description: string;
858
- };
859
- servers: Array<{
860
- url: string;
861
- description: string;
862
- }>;
863
- paths: Record<string, Record<string, PathOperation>>;
864
- components: {
865
- schemas: Record<string, SchemaObject>;
866
- securitySchemes: Record<string, SecurityScheme>;
867
- };
868
- }
869
- interface PathOperation {
870
- summary: string;
871
- operationId: string;
872
- tags: string[];
873
- security?: Array<Record<string, string[]>>;
874
- parameters?: ParameterObject[];
875
- requestBody?: {
876
- required: boolean;
877
- content: Record<string, {
878
- schema: SchemaRef;
879
- }>;
880
- };
881
- responses: Record<string, {
882
- description: string;
883
- content?: Record<string, {
884
- schema: SchemaRef;
885
- }>;
886
- }>;
887
- }
888
- interface ParameterObject {
889
- name: string;
890
- in: "query" | "path" | "header";
891
- required: boolean;
892
- schema: SchemaRef;
893
- }
894
- interface SecurityScheme {
895
- type: string;
896
- scheme?: string;
897
- bearerFormat?: string;
898
- }
899
- type SchemaRef = {
900
- $ref: string;
901
- } | SchemaObject;
902
- interface SchemaObject {
903
- type?: string;
904
- properties?: Record<string, SchemaRef>;
905
- required?: string[];
906
- items?: SchemaRef;
907
- enum?: string[];
908
- description?: string;
909
- format?: string;
910
- nullable?: boolean;
541
+ interface CsrfValidationResult {
542
+ valid: boolean;
543
+ reason?: string;
911
544
  }
912
545
  /**
913
- * Generate the full OpenAPI 3.1 specification for the TheAuth REST API.
546
+ * Generate a cryptographically random CSRF token.
547
+ *
548
+ * Uses `crypto.getRandomValues` (Web Crypto API) so it works in both
549
+ * Node.js ≥ 19 and browser/edge runtimes.
550
+ *
551
+ * Returns a URL-safe base64 string (~43 chars).
914
552
  */
915
- declare function generateOpenAPISpec(options?: {
916
- baseUrl?: string;
917
- version?: string;
918
- }): OpenAPISpec;
919
-
553
+ declare function generateCsrfToken(): string;
920
554
  /**
921
- * Create a plugin router that matches requests to registered plugin endpoints.
555
+ * Validate a CSRF token from the request against the value stored in the
556
+ * cookie using a constant-time comparison to prevent timing attacks.
922
557
  *
923
- * The router strips `basePath` from the request URL before matching so plugins
924
- * register paths relative to the mount point (e.g. `/auth/sign-in` instead
925
- * of `/api/kavach/auth/sign-in`).
558
+ * Both `requestToken` and `cookieToken` must be non-empty strings produced
559
+ * by `generateCsrfToken()`. Any mismatch returns `{ valid: false }`.
560
+ *
561
+ * @param requestToken Token submitted with the request (header / body).
562
+ * @param cookieToken Token read from the CSRF cookie.
926
563
  */
927
- declare function createPluginRouter(endpoints: PluginEndpoint[]): {
928
- /** Try to handle a request. Returns Response if matched, null if not. */
929
- handle: (request: Request, basePath: string, endpointCtx: EndpointContext) => Promise<Response | null>;
930
- /** Get all registered endpoints (for adapter mounting) */
931
- getEndpoints: () => PluginEndpoint[];
932
- };
564
+ declare function validateCsrfToken(requestToken: string, cookieToken: string): CsrfValidationResult;
565
+ /**
566
+ * Validate the `Origin` (or `Referer` fallback) header of an incoming
567
+ * request against a list of trusted origins.
568
+ *
569
+ * Rules:
570
+ * - If `Origin` is present and matches a trusted origin → valid.
571
+ * - If `Origin` is `"null"` (opaque origin) → invalid.
572
+ * - If `Origin` is absent, falls back to the `Referer` header.
573
+ * - If neither header is present → result depends on `allowMissingOrigin`.
574
+ *
575
+ * @param request Incoming Web API `Request`.
576
+ * @param trustedOrigins Array of allowed origins, e.g. `['https://app.example.com']`.
577
+ * Trailing slashes are stripped before comparison.
578
+ * @param allowMissingOrigin When `true`, requests without an `Origin` or
579
+ * `Referer` header are considered valid (useful for
580
+ * server-to-server calls). Defaults to `false`.
581
+ */
582
+ declare function validateOrigin(request: Request, trustedOrigins: string[], allowMissingOrigin?: boolean): CsrfValidationResult;
933
583
 
934
- interface PluginRegistry {
935
- endpoints: PluginEndpoint[];
936
- migrations: string[];
937
- hooks: {
938
- onRequest: Array<NonNullable<KavachPlugin["hooks"]>["onRequest"]>;
939
- onAuthenticate: Array<NonNullable<KavachPlugin["hooks"]>["onAuthenticate"]>;
940
- onSessionCreate: Array<NonNullable<KavachPlugin["hooks"]>["onSessionCreate"]>;
941
- onSessionRevoke: Array<NonNullable<KavachPlugin["hooks"]>["onSessionRevoke"]>;
942
- };
943
- pluginContext: Record<string, unknown>;
944
- }
945
584
  /**
946
- * Initialize all plugins and collect their endpoints, migrations, and hooks
947
- * into a single registry.
585
+ * Cookie-aware session manager for TheAuth.
948
586
  *
949
- * Calls each plugin's `init()` in registration order. Migrations collected
950
- * during init are executed before the registry is returned so that any
951
- * subsequent requests can immediately use plugin tables.
587
+ * Wraps the lower-level `createSessionManager` with cookie serialization and
588
+ * optional CSRF protection so callers work with `Request`/`Response` objects
589
+ * directly rather than managing raw tokens and headers themselves.
590
+ *
591
+ * @example
592
+ * ```typescript
593
+ * import { createCookieSessionManager } from './manager.js';
594
+ *
595
+ * const sessions = createCookieSessionManager(
596
+ * { secret: process.env.SESSION_SECRET },
597
+ * db,
598
+ * );
599
+ *
600
+ * // On login
601
+ * const { session, setCookieHeader } = await sessions.createSession(user.id);
602
+ * return new Response(null, {
603
+ * status: 302,
604
+ * headers: { Location: '/dashboard', 'Set-Cookie': setCookieHeader },
605
+ * });
606
+ *
607
+ * // On each request
608
+ * const session = await sessions.validateSession(request.headers.get('cookie') ?? '');
609
+ * if (!session) return new Response('Unauthorized', { status: 401 });
610
+ *
611
+ * // On logout
612
+ * const deleteCookie = sessions.buildLogoutCookie();
613
+ * return new Response(null, {
614
+ * status: 302,
615
+ * headers: { Location: '/login', 'Set-Cookie': deleteCookie },
616
+ * });
617
+ * ```
952
618
  */
953
- declare function initializePlugins(plugins: KavachPlugin[], db: Database, config: KavachConfig, sessionManager: SessionManager | null): Promise<PluginRegistry>;
954
619
 
955
- interface BudgetPolicy {
956
- id: string;
957
- agentId?: string;
958
- userId?: string;
959
- tenantId?: string;
960
- limits: BudgetLimits;
961
- currentUsage: BudgetUsage;
962
- action: "warn" | "throttle" | "block" | "revoke";
963
- status: "active" | "triggered" | "disabled";
964
- createdAt: Date;
965
- }
966
- interface BudgetLimits {
967
- maxTokensCostPerDay?: number;
968
- maxTokensCostPerMonth?: number;
969
- maxCallsPerDay?: number;
970
- maxCallsPerMonth?: number;
971
- }
972
- interface BudgetUsage {
973
- tokensCostToday: number;
974
- tokensCostThisMonth: number;
975
- callsToday: number;
976
- callsThisMonth: number;
977
- lastUpdated: string;
620
+ interface CookieSessionConfig extends SessionConfig {
621
+ /**
622
+ * Name of the session cookie.
623
+ * Defaults to `"theauth_session"`.
624
+ */
625
+ sessionName?: string;
626
+ /**
627
+ * Additional cookie attributes applied when setting the session cookie.
628
+ * `maxAge` is derived from `SessionConfig.maxAge` when not explicitly set.
629
+ */
630
+ cookieOptions?: Omit<CookieOptions, "maxAge">;
631
+ /**
632
+ * When `true`, `validateSession` automatically refreshes the session
633
+ * expiry on every successful validation. Defaults to `true`.
634
+ */
635
+ autoRefresh?: boolean;
978
636
  }
979
- interface CreatePolicyInput {
980
- agentId?: string;
981
- userId?: string;
982
- tenantId?: string;
983
- limits: BudgetLimits;
984
- action: "warn" | "throttle" | "block" | "revoke";
637
+ interface CreateSessionResult {
638
+ /** The persisted session record. */
639
+ session: Session;
640
+ /** Ready-to-use `Set-Cookie` header value. */
641
+ setCookieHeader: string;
985
642
  }
986
- interface PolicyFilters {
987
- agentId?: string;
988
- userId?: string;
989
- tenantId?: string;
643
+ interface ValidateSessionResult {
644
+ /** The valid session, or `null` when the cookie is absent/invalid/expired. */
645
+ session: Session | null;
646
+ /**
647
+ * When `autoRefresh` is enabled and the session was valid, the refreshed
648
+ * `Set-Cookie` header to forward to the client. `null` otherwise.
649
+ */
650
+ refreshCookieHeader: string | null;
990
651
  }
991
- declare function createPolicyModule(db: Database): {
992
- create: (input: CreatePolicyInput) => Promise<BudgetPolicy>;
993
- get: (policyId: string) => Promise<BudgetPolicy | null>;
994
- list: (filters?: PolicyFilters) => Promise<BudgetPolicy[]>;
995
- update: (policyId: string, updates: Partial<BudgetPolicy>) => Promise<BudgetPolicy>;
996
- remove: (policyId: string) => Promise<void>;
997
- checkBudget: (agentId: string, tokensCost?: number) => Promise<{
998
- allowed: boolean;
999
- reason?: string;
1000
- policy?: BudgetPolicy;
1001
- }>;
1002
- recordUsage: (agentId: string, tokensCost?: number) => Promise<void>;
1003
- resetDaily: () => Promise<{
1004
- reset: number;
652
+ interface CookieSessionManager {
653
+ /**
654
+ * Create a new session for the given user and return the session record
655
+ * together with a `Set-Cookie` header string ready to attach to a response.
656
+ */
657
+ createSession(userId: string, metadata?: Record<string, unknown>): Promise<CreateSessionResult>;
658
+ /**
659
+ * Parse the `Cookie` header, look up the session in the database, and
660
+ * verify it has not expired.
661
+ *
662
+ * When `autoRefresh` is enabled the session is extended on each valid
663
+ * request and a new `Set-Cookie` header is returned for forwarding.
664
+ *
665
+ * @param cookieHeader Raw value of the `Cookie` request header.
666
+ */
667
+ validateSession(cookieHeader: string): Promise<ValidateSessionResult>;
668
+ /**
669
+ * Extend the session expiry to `now + maxAge`.
670
+ *
671
+ * Returns the updated session and a fresh `Set-Cookie` header.
672
+ * Returns `null` when the session does not exist.
673
+ */
674
+ refreshSession(sessionId: string): Promise<{
675
+ session: Session;
676
+ setCookieHeader: string;
677
+ } | null>;
678
+ /**
679
+ * Delete a session by ID (server-side) and return a deletion cookie that
680
+ * will clear the browser cookie on the next response.
681
+ */
682
+ revokeSession(sessionId: string): Promise<{
683
+ deleteCookieHeader: string;
1005
684
  }>;
1006
- resetMonthly: () => Promise<{
1007
- reset: number;
685
+ /**
686
+ * Revoke all sessions for the given user.
687
+ *
688
+ * Returns a deletion cookie header for clearing the current browser cookie.
689
+ */
690
+ revokeAllSessions(userId: string): Promise<{
691
+ deleteCookieHeader: string;
1008
692
  }>;
1009
- };
1010
-
1011
- /**
1012
- * Cookie serialization and parsing utilities for TheAuth.
1013
- *
1014
- * Pure functions that work with Web API `Request`/`Response` objects and
1015
- * raw header strings. No framework dependencies.
1016
- */
1017
- type SameSite = "strict" | "lax" | "none";
1018
- interface CookieOptions {
1019
- /** Prevents JavaScript access to the cookie. Default: true. */
1020
- httpOnly?: boolean;
1021
693
  /**
1022
- * Restricts transmission to HTTPS. Default: true in production
1023
- * (when `NODE_ENV === 'production'`), false otherwise.
694
+ * List all non-expired sessions for a user, newest first.
1024
695
  */
1025
- secure?: boolean;
1026
- /** Controls cross-site sending. Default: 'lax'. */
1027
- sameSite?: SameSite;
1028
- /** Cookie scope path. Default: '/'. */
1029
- path?: string;
1030
- /** Cookie scope domain (omitted when not set). */
1031
- domain?: string;
1032
- /** Lifetime in seconds from now. Sets both Max-Age and Expires. */
1033
- maxAge?: number;
1034
- /** Absolute expiry date (overridden by maxAge when both are set). */
1035
- expires?: Date;
1036
- /** Partitioned attribute (CHIPS). */
1037
- partitioned?: boolean;
696
+ listSessions(userId: string): Promise<Session[]>;
697
+ /**
698
+ * Build a `Set-Cookie` header that deletes the session cookie on the client
699
+ * without any database operation. Useful in error paths.
700
+ */
701
+ buildLogoutCookie(): string;
702
+ /** Expose the underlying low-level session manager for advanced usage. */
703
+ raw: SessionManager;
1038
704
  }
1039
705
  /**
1040
- * Serialize a cookie name/value pair into a `Set-Cookie` header string.
1041
- *
1042
- * @param name Cookie name. Must be a valid cookie-name token.
1043
- * @param value Cookie value. Will be percent-encoded.
1044
- * @param options Cookie attributes. Defaults to `httpOnly=true`, `secure`
1045
- * based on `NODE_ENV`, `sameSite=lax`, `path=/`.
1046
- */
1047
- declare function serializeCookie(name: string, value: string, options?: CookieOptions): string;
1048
- /**
1049
- * Serialize a deletion cookie (zero Max-Age, past Expires) that will
1050
- * instruct browsers to remove the named cookie.
1051
- */
1052
- declare function serializeCookieDeletion(name: string, options?: Omit<CookieOptions, "maxAge" | "expires">): string;
1053
- /**
1054
- * Parse a `Cookie` request header string into a name → value map.
1055
- *
1056
- * Values are percent-decoded. Unknown or malformed pairs are skipped
1057
- * silently so that a single bad cookie does not break the entire request.
706
+ * Create a cookie-aware session manager.
1058
707
  *
1059
- * @param header The raw value of the `Cookie` header (e.g. `"a=1; b=2"`).
1060
- */
1061
- declare function parseCookies(header: string): Record<string, string>;
1062
- /**
1063
- * Extract a single cookie value from a `Cookie` header string.
708
+ * Internally delegates all DB operations to `createSessionManager`.
1064
709
  *
1065
- * Returns `undefined` when the cookie is absent.
1066
- */
1067
- declare function getCookie(header: string, name: string): string | undefined;
1068
- /**
1069
- * Extract cookies from a Web API `Request` object.
710
+ * @param config Cookie-aware session configuration.
711
+ * @param db Drizzle database instance from `createDatabase()`.
1070
712
  */
1071
- declare function parseCookiesFromRequest(request: Request): Record<string, string>;
713
+ declare function createCookieSessionManager(config: CookieSessionConfig, db: Database): CookieSessionManager;
1072
714
 
1073
715
  /**
1074
- * CSRF protection utilities for TheAuth.
1075
- *
1076
- * Implements two complementary defences:
1077
- *
1078
- * 1. **Origin/Referer validation** — checks the inbound request's `Origin`
1079
- * (or `Referer` as fallback) against a caller-supplied allowlist. This
1080
- * alone blocks the vast majority of CSRF attacks from browser clients.
716
+ * Multi-session support for TheAuth.
1081
717
  *
1082
- * 2. **Double-submit cookie pattern** — a random token is stored in a cookie
1083
- * AND submitted by the client as a request header (or body field). The
1084
- * server verifies both values match using a timing-safe comparison.
718
+ * Allows users to maintain multiple concurrent sessions (phone, laptop, tablet)
719
+ * with optional per-user session caps. When the cap is reached, the oldest
720
+ * session is evicted automatically (configurable).
1085
721
  *
1086
- * Use origin validation first; fall back to token comparison when the origin
1087
- * header is absent (e.g. same-origin requests on some browsers, server-side
1088
- * fetch).
722
+ * Uses the existing `theauth_sessions` table — no additional schema required.
1089
723
  *
1090
724
  * @example
1091
725
  * ```typescript
1092
- * import { generateCsrfToken, validateCsrfToken, validateOrigin } from './csrf.js';
726
+ * const multiSession = createMultiSessionModule(
727
+ * { maxSessions: 5, overflowStrategy: 'evict-oldest' },
728
+ * db,
729
+ * sessionManager,
730
+ * );
1093
731
  *
1094
- * // On form render: store token in cookie, embed in hidden field.
1095
- * const token = await generateCsrfToken();
732
+ * // List all active sessions for a user
733
+ * const sessionList = await multiSession.listSessions(userId);
1096
734
  *
1097
- * // On form submit:
1098
- * const originOk = validateOrigin(request, ['https://app.example.com']);
1099
- * const tokenOk = validateCsrfToken(submittedToken, cookieToken);
1100
- * if (!originOk && !tokenOk) throw new Error('CSRF check failed');
735
+ * // Sign out everywhere except here
736
+ * const count = await multiSession.revokeOtherSessions(userId, currentSessionId);
1101
737
  * ```
1102
738
  */
1103
- interface CsrfValidationResult {
1104
- valid: boolean;
1105
- reason?: string;
739
+
740
+ interface MultiSessionConfig {
741
+ /** Max concurrent sessions per user (default: 10) */
742
+ maxSessions?: number;
743
+ /** Strategy when max is reached (default: 'evict-oldest') */
744
+ overflowStrategy?: "reject" | "evict-oldest";
745
+ }
746
+ interface SessionInfo {
747
+ id: string;
748
+ createdAt: Date;
749
+ expiresAt: Date;
750
+ metadata?: Record<string, unknown>;
751
+ /** Human-readable device string extracted from User-Agent, e.g. "Chrome on macOS" */
752
+ device?: string;
753
+ /** IP address recorded at session creation */
754
+ ip?: string;
755
+ }
756
+ interface MultiSessionModule {
757
+ /** List all non-expired sessions for a user, newest first. */
758
+ listSessions(userId: string): Promise<SessionInfo[]>;
759
+ /** Revoke a single session by ID. */
760
+ revokeSession(sessionId: string): Promise<void>;
761
+ /** Revoke every session except the given one. Returns the count revoked. */
762
+ revokeOtherSessions(userId: string, currentSessionId: string): Promise<number>;
763
+ /** Return the count of active (non-expired) sessions for a user. */
764
+ getSessionCount(userId: string): Promise<number>;
765
+ /**
766
+ * Enforce the session cap before creating a new session.
767
+ *
768
+ * Call this before `sessionManager.create()`. If the cap is reached:
769
+ * - `evict-oldest` deletes the oldest session and resolves.
770
+ * - `reject` throws a `MultiSessionLimitError`.
771
+ */
772
+ enforceSessionLimit(userId: string): Promise<void>;
1106
773
  }
774
+ declare class MultiSessionLimitError extends Error {
775
+ readonly code = "SESSION_LIMIT_REACHED";
776
+ constructor(userId: string, max: number);
777
+ }
778
+ declare function createMultiSessionModule(config: MultiSessionConfig, db: Database, sessionManager: SessionManager): MultiSessionModule;
1107
779
  /**
1108
- * Generate a cryptographically random CSRF token.
1109
- *
1110
- * Uses `crypto.getRandomValues` (Web Crypto API) so it works in both
1111
- * Node.js ≥ 19 and browser/edge runtimes.
780
+ * Build metadata to pass to `sessionManager.create()` that includes
781
+ * device info extracted from the incoming request.
1112
782
  *
1113
- * Returns a URL-safe base64 string (~43 chars).
783
+ * @example
784
+ * ```typescript
785
+ * const meta = buildSessionMetadata(request, { role: 'admin' });
786
+ * const { token } = await sessionManager.create(userId, meta);
787
+ * ```
1114
788
  */
1115
- declare function generateCsrfToken(): string;
789
+ declare function buildSessionMetadata(request: Request, extra?: Record<string, unknown>): Record<string, unknown>;
790
+
1116
791
  /**
1117
- * Validate a CSRF token from the request against the value stored in the
1118
- * cookie using a constant-time comparison to prevent timing attacks.
792
+ * Token family tracking for refresh token reuse detection.
1119
793
  *
1120
- * Both `requestToken` and `cookieToken` must be non-empty strings produced
1121
- * by `generateCsrfToken()`. Any mismatch returns `{ valid: false }`.
794
+ * Each refresh token belongs to a "family" — a chain of rotations that all
795
+ * originate from the same initial login. When `reuseDetection` is enabled,
796
+ * presenting an already-used token from a family immediately revokes every
797
+ * token in that family, because reuse indicates the token was stolen.
1122
798
  *
1123
- * @param requestToken Token submitted with the request (header / body).
1124
- * @param cookieToken Token read from the CSRF cookie.
799
+ * The database table `theauth_refresh_token_families` stores:
800
+ * - family-level metadata (userId, absolute expiry, revocation status)
801
+ *
802
+ * Each individual refresh token row in `theauth_refresh_tokens` links back to
803
+ * its family via `familyId`.
804
+ *
805
+ * @example
806
+ * ```typescript
807
+ * const families = createTokenFamilyStore(db);
808
+ *
809
+ * // On login — create a new family and issue the first token
810
+ * const family = await families.createFamily(userId, absoluteExpiresAt);
811
+ * const token = await families.issueToken(family.id, refreshTokenTTL);
812
+ *
813
+ * // On refresh — consume the token (marks it used, issues a new one)
814
+ * const result = await families.consumeToken(rawToken);
815
+ * if (result.status === 'reuse') {
816
+ * // Entire family revoked — force re-login
817
+ * }
818
+ * ```
1125
819
  */
1126
- declare function validateCsrfToken(requestToken: string, cookieToken: string): CsrfValidationResult;
820
+
821
+ interface TokenFamily {
822
+ id: string;
823
+ userId: string;
824
+ /** Absolute expiry — no refresh can extend beyond this date. */
825
+ absoluteExpiresAt: Date;
826
+ revoked: boolean;
827
+ createdAt: Date;
828
+ }
829
+ type ConsumeTokenStatus = "ok" /** Token valid, successfully consumed. */ | "expired" /** Token has passed its TTL. */ | "revoked" /** Entire family has been revoked (stolen token detected). */ | "reuse" /** Token was already used — family has now been revoked. */ | "not_found"; /** Token does not exist in the database. */
830
+ interface ConsumeTokenResult {
831
+ status: ConsumeTokenStatus;
832
+ /** Populated when status is `"ok"`. */
833
+ family?: TokenFamily;
834
+ }
835
+ interface TokenFamilyStore {
836
+ /**
837
+ * Create a new token family for a user.
838
+ * Call this once per login to anchor the refresh token chain.
839
+ */
840
+ createFamily(userId: string, absoluteExpiresAt: Date): Promise<TokenFamily>;
841
+ /**
842
+ * Issue a new opaque refresh token tied to the given family.
843
+ *
844
+ * Returns the raw token string (only returned once — never stored in the
845
+ * clear) and the token's individual expiry date.
846
+ */
847
+ issueToken(familyId: string, ttlMs: number): Promise<{
848
+ rawToken: string;
849
+ expiresAt: Date;
850
+ }>;
851
+ /**
852
+ * Consume a refresh token.
853
+ *
854
+ * - If the token is valid and unused, it is marked `used` and the caller
855
+ * should immediately call `issueToken` to rotate.
856
+ * - If the token was already used, the **entire family is revoked** (reuse
857
+ * detection — token theft assumed).
858
+ * - If the token has expired or is not found, returns the appropriate status.
859
+ */
860
+ consumeToken(rawToken: string): Promise<ConsumeTokenResult>;
861
+ /**
862
+ * Revoke all token families (and their tokens) for a user.
863
+ * Used on logout, password change, or explicit session termination.
864
+ */
865
+ revokeFamiliesForUser(userId: string): Promise<void>;
866
+ /**
867
+ * Revoke a specific family by ID and all its tokens.
868
+ */
869
+ revokeFamily(familyId: string): Promise<void>;
870
+ /**
871
+ * Check whether the absolute session timeout has been reached for a family.
872
+ * Returns `true` when the family is still within its absolute timeout.
873
+ */
874
+ isFamilyActive(family: TokenFamily): boolean;
875
+ }
1127
876
  /**
1128
- * Validate the `Origin` (or `Referer` fallback) header of an incoming
1129
- * request against a list of trusted origins.
1130
- *
1131
- * Rules:
1132
- * - If `Origin` is present and matches a trusted origin → valid.
1133
- * - If `Origin` is `"null"` (opaque origin) → invalid.
1134
- * - If `Origin` is absent, falls back to the `Referer` header.
1135
- * - If neither header is present → result depends on `allowMissingOrigin`.
1136
- *
1137
- * @param request Incoming Web API `Request`.
1138
- * @param trustedOrigins Array of allowed origins, e.g. `['https://app.example.com']`.
1139
- * Trailing slashes are stripped before comparison.
1140
- * @param allowMissingOrigin When `true`, requests without an `Origin` or
1141
- * `Referer` header are considered valid (useful for
1142
- * server-to-server calls). Defaults to `false`.
877
+ * Create a `TokenFamilyStore` backed by the TheAuth database.
1143
878
  */
1144
- declare function validateOrigin(request: Request, trustedOrigins: string[], allowMissingOrigin?: boolean): CsrfValidationResult;
879
+ declare function createTokenFamilyStore(db: Database): TokenFamilyStore;
1145
880
 
1146
881
  /**
1147
- * Cookie-aware session manager for TheAuth.
882
+ * Session refresh endpoint handler for TheAuth.
1148
883
  *
1149
- * Wraps the lower-level `createSessionManager` with cookie serialization and
1150
- * optional CSRF protection so callers work with `Request`/`Response` objects
1151
- * directly rather than managing raw tokens and headers themselves.
884
+ * Implements `POST /auth/refresh`:
885
+ * 1. Extracts the refresh token from an httpOnly cookie or the request body.
886
+ * 2. Validates the token (TTL, reuse detection, absolute timeout).
887
+ * 3. Issues a new short-lived access token (signed JWT).
888
+ * 4. Rotates the refresh token (one-time use — the old one is consumed).
889
+ * 5. Records the rotation in the audit log.
890
+ *
891
+ * Token family tracking (via `createTokenFamilyStore`) provides reuse
892
+ * detection: if an attacker uses a stolen refresh token after the legitimate
893
+ * user has already rotated it, the entire family is revoked and both parties
894
+ * are forced to re-authenticate.
1152
895
  *
1153
896
  * @example
1154
897
  * ```typescript
1155
- * import { createCookieSessionManager } from './manager.js';
1156
- *
1157
- * const sessions = createCookieSessionManager(
1158
- * { secret: process.env.SESSION_SECRET },
898
+ * const refresher = createSessionRefresher({
899
+ * secret: process.env.SESSION_SECRET,
900
+ * session: {
901
+ * accessTokenTTL: "15m",
902
+ * refreshTokenTTL: "30d",
903
+ * absoluteTimeout: "90d",
904
+ * rotateRefreshTokens: true,
905
+ * reuseDetection: true,
906
+ * },
1159
907
  * db,
1160
- * );
1161
- *
1162
- * // On login
1163
- * const { session, setCookieHeader } = await sessions.createSession(user.id);
1164
- * return new Response(null, {
1165
- * status: 302,
1166
- * headers: { Location: '/dashboard', 'Set-Cookie': setCookieHeader },
1167
908
  * });
1168
909
  *
1169
- * // On each request
1170
- * const session = await sessions.validateSession(request.headers.get('cookie') ?? '');
1171
- * if (!session) return new Response('Unauthorized', { status: 401 });
1172
- *
1173
- * // On logout
1174
- * const deleteCookie = sessions.buildLogoutCookie();
1175
- * return new Response(null, {
1176
- * status: 302,
1177
- * headers: { Location: '/login', 'Set-Cookie': deleteCookie },
910
+ * // In your Hono / Express router:
911
+ * app.post('/auth/refresh', async (ctx) => {
912
+ * const result = await refresher.handleRequest(ctx.req.raw);
913
+ * return result.response;
1178
914
  * });
1179
915
  * ```
1180
916
  */
1181
917
 
1182
- interface CookieSessionConfig extends SessionConfig {
918
+ interface RefreshSessionConfig {
1183
919
  /**
1184
- * Name of the session cookie.
1185
- * Defaults to `"kavach_session"`.
920
+ * Short-lived access token lifetime.
921
+ * Parsed duration string, e.g. `"15m"`.
922
+ * Defaults to `"15m"`.
1186
923
  */
1187
- sessionName?: string;
924
+ accessTokenTTL?: string;
1188
925
  /**
1189
- * Additional cookie attributes applied when setting the session cookie.
1190
- * `maxAge` is derived from `SessionConfig.maxAge` when not explicitly set.
926
+ * Long-lived refresh token lifetime.
927
+ * Parsed duration string, e.g. `"30d"`.
928
+ * Defaults to `"30d"`.
1191
929
  */
1192
- cookieOptions?: Omit<CookieOptions, "maxAge">;
930
+ refreshTokenTTL?: string;
1193
931
  /**
1194
- * When `true`, `validateSession` automatically refreshes the session
1195
- * expiry on every successful validation. Defaults to `true`.
932
+ * When `true` (default), each use of a refresh token rotates it: the old
933
+ * token is invalidated and a new one is issued.
1196
934
  */
1197
- autoRefresh?: boolean;
935
+ rotateRefreshTokens?: boolean;
936
+ /**
937
+ * Maximum session lifetime regardless of how many times the token is
938
+ * refreshed. Parsed duration string, e.g. `"90d"`.
939
+ * Defaults to `"90d"`.
940
+ */
941
+ absoluteTimeout?: string;
942
+ /**
943
+ * When `true` (default), presenting an already-used refresh token triggers
944
+ * reuse detection and revokes the entire token family.
945
+ */
946
+ reuseDetection?: boolean;
947
+ /**
948
+ * Name of the httpOnly cookie that carries the refresh token.
949
+ * Defaults to `"theauth_refresh"`.
950
+ */
951
+ refreshCookieName?: string;
952
+ /**
953
+ * Name of the httpOnly cookie that carries the access token (when cookie
954
+ * transport is used for the access token too).
955
+ * Defaults to `"theauth_access"`.
956
+ */
957
+ accessCookieName?: string;
1198
958
  }
1199
- interface CreateSessionResult {
1200
- /** The persisted session record. */
1201
- session: Session;
1202
- /** Ready-to-use `Set-Cookie` header value. */
1203
- setCookieHeader: string;
959
+ interface SessionRefresherConfig {
960
+ /** Signing secret — at least 32 characters. */
961
+ secret: string;
962
+ /** Refresh / rotation settings. */
963
+ session?: RefreshSessionConfig;
964
+ /** Drizzle database instance. */
965
+ db: Database;
1204
966
  }
1205
- interface ValidateSessionResult {
1206
- /** The valid session, or `null` when the cookie is absent/invalid/expired. */
1207
- session: Session | null;
967
+ /** The payload embedded in the short-lived access token JWT. */
968
+ interface AccessTokenPayload {
969
+ /** User ID. */
970
+ sub: string;
971
+ /** Token family ID — used for server-side token binding. */
972
+ familyId: string;
973
+ /** Token type discriminator. */
974
+ type: "access";
975
+ }
976
+ interface RefreshResult {
977
+ /** Signed access token JWT. */
978
+ accessToken: string;
979
+ /** Raw opaque refresh token (only returned once — store in httpOnly cookie). */
980
+ refreshToken: string;
981
+ /** Expiry date of the new access token. */
982
+ accessTokenExpiresAt: Date;
983
+ /** Expiry date of the new refresh token. */
984
+ refreshTokenExpiresAt: Date;
985
+ /** The token family these tokens belong to. */
986
+ family: TokenFamily;
987
+ }
988
+ type RefreshError = "token_missing" | "token_not_found" | "token_expired" | "token_reuse" | "family_revoked" | "absolute_timeout";
989
+ interface RefreshHandleResult {
990
+ /** HTTP Response ready to return to the caller. */
991
+ response: Response;
992
+ /** Populated on success. */
993
+ result?: RefreshResult;
994
+ /** Populated on failure. */
995
+ error?: RefreshError;
996
+ }
997
+ interface SessionRefresher {
998
+ /**
999
+ * Low-level refresh — takes a raw refresh token string directly.
1000
+ *
1001
+ * Returns `RefreshResult` on success or throws a `RefreshTokenError`.
1002
+ */
1003
+ refresh(rawRefreshToken: string): Promise<RefreshResult>;
1004
+ /**
1005
+ * High-level HTTP handler.
1006
+ *
1007
+ * Extracts the refresh token from the `Cookie` header (preferred) or the
1008
+ * JSON request body, calls `refresh()`, and returns a `Response` with
1009
+ * appropriate `Set-Cookie` headers.
1010
+ */
1011
+ handleRequest(request: Request): Promise<RefreshHandleResult>;
1012
+ /**
1013
+ * Issue an initial refresh token for a user (called once on login).
1014
+ *
1015
+ * Returns the access token, refresh token, and their expiry dates.
1016
+ */
1017
+ issueInitial(userId: string): Promise<RefreshResult>;
1018
+ /**
1019
+ * Revoke all refresh token families for a user (e.g. on logout or
1020
+ * password change).
1021
+ */
1022
+ revokeAll(userId: string): Promise<void>;
1023
+ }
1024
+ /** Thrown by `SessionRefresher.refresh()` on validation failure. */
1025
+ declare class RefreshTokenError extends Error {
1026
+ readonly code: RefreshError;
1027
+ constructor(code: RefreshError, message: string);
1028
+ }
1029
+ /**
1030
+ * Create a `SessionRefresher` backed by the TheAuth database.
1031
+ */
1032
+ declare function createSessionRefresher(config: SessionRefresherConfig): SessionRefresher;
1033
+
1034
+ interface Tenant {
1035
+ id: string;
1036
+ name: string;
1037
+ slug: string;
1038
+ settings: TenantSettings;
1039
+ status: "active" | "suspended";
1040
+ createdAt: Date;
1041
+ updatedAt: Date;
1042
+ }
1043
+ interface TenantSettings {
1044
+ maxAgents?: number;
1045
+ maxDelegationDepth?: number;
1046
+ auditRetentionDays?: number;
1047
+ allowedAgentTypes?: string[];
1048
+ }
1049
+ interface CreateTenantInput {
1050
+ name: string;
1051
+ slug: string;
1052
+ settings?: Partial<TenantSettings>;
1053
+ }
1054
+ declare function createTenantModule(db: Database): {
1055
+ create: (input: CreateTenantInput) => Promise<Tenant>;
1056
+ get: (tenantId: string) => Promise<Tenant | null>;
1057
+ getBySlug: (slug: string) => Promise<Tenant | null>;
1058
+ list: () => Promise<Tenant[]>;
1059
+ update: (tenantId: string, updates: Partial<CreateTenantInput>) => Promise<Tenant>;
1060
+ suspend: (tenantId: string) => Promise<void>;
1061
+ activate: (tenantId: string) => Promise<void>;
1062
+ };
1063
+
1064
+ /**
1065
+ * Create a TheAuth instance.
1066
+ *
1067
+ * The factory is **async** so it can open database connections for Postgres
1068
+ * and MySQL (which require async driver initialisation) and optionally run
1069
+ * `CREATE TABLE IF NOT EXISTS` for all schema tables.
1070
+ *
1071
+ * @example SQLite (simplest)
1072
+ * ```typescript
1073
+ * import { createTheAuth } from '@glinr/theauth';
1074
+ *
1075
+ * const auth = await createTheAuth({
1076
+ * database: { provider: 'sqlite', url: 'theauth.db' },
1077
+ * });
1078
+ * ```
1079
+ *
1080
+ * @example Postgres
1081
+ * ```typescript
1082
+ * const auth = await createTheAuth({
1083
+ * database: { provider: 'postgres', url: process.env.DATABASE_URL },
1084
+ * });
1085
+ * ```
1086
+ *
1087
+ * @example MySQL - skip auto-migration (tables managed externally)
1088
+ * ```typescript
1089
+ * const auth = await createTheAuth({
1090
+ * database: {
1091
+ * provider: 'mysql',
1092
+ * url: process.env.DATABASE_URL,
1093
+ * skipMigrations: true,
1094
+ * },
1095
+ * });
1096
+ * ```
1097
+ */
1098
+ declare function createTheAuth(config: TheAuthConfig): Promise<{
1099
+ agent: {
1100
+ create(input: CreateAgentInput): ReturnType<(input: CreateAgentInput) => Promise<AgentIdentity & {
1101
+ token: string;
1102
+ }>>;
1103
+ revoke(agentId: string): ReturnType<(agentId: string) => Promise<void>>;
1104
+ rotate(agentId: string): ReturnType<(agentId: string) => Promise<AgentIdentity & {
1105
+ token: string;
1106
+ }>>;
1107
+ get: (agentId: string) => Promise<AgentIdentity | null>;
1108
+ list: (filter?: AgentFilter) => Promise<AgentIdentity[]>;
1109
+ update: (agentId: string, input: UpdateAgentInput) => Promise<AgentIdentity>;
1110
+ validateToken: (token: string) => Promise<AgentIdentity | null>;
1111
+ };
1112
+ authorize: (agentId: string, request: AuthorizeRequest, context?: RequestContext) => Promise<AuthorizeResult>;
1113
+ authorizeByToken: (token: string, request: AuthorizeRequest, context?: RequestContext) => Promise<AuthorizeResult>;
1114
+ delegate: (input: DelegateInput) => Promise<DelegationChain>;
1115
+ delegation: {
1116
+ revoke: (chainId: string) => Promise<void>;
1117
+ getEffectivePermissions: (agentId: string) => Promise<Permission[]>;
1118
+ listChains: (agentId: string) => Promise<DelegationChain[]>;
1119
+ };
1120
+ audit: {
1121
+ query: (filter: AuditFilter) => Promise<AuditEntry[]>;
1122
+ export: (options: AuditExportOptions) => Promise<string>;
1123
+ cleanup: (options: {
1124
+ retentionDays: number;
1125
+ }) => Promise<{
1126
+ deleted: number;
1127
+ }>;
1128
+ };
1208
1129
  /**
1209
- * When `autoRefresh` is enabled and the session was valid, the refreshed
1210
- * `Set-Cookie` header to forward to the client. `null` otherwise.
1130
+ * MCP server registration.
1131
+ *
1132
+ * Register and look up MCP tool servers. Uses the `theauth_mcp_servers`
1133
+ * database table — no separate in-memory store needed.
1211
1134
  */
1212
- refreshCookieHeader: string | null;
1213
- }
1214
- interface CookieSessionManager {
1135
+ mcp: {
1136
+ /**
1137
+ * Register a new MCP tool server.
1138
+ *
1139
+ * Persists the server entry to the `theauth_mcp_servers` table.
1140
+ * The returned record includes the generated `id` and `createdAt`.
1141
+ */
1142
+ register(input: McpServerInput): Promise<McpServer>;
1143
+ /**
1144
+ * List all registered MCP servers (active and inactive).
1145
+ */
1146
+ list(): Promise<McpServer[]>;
1147
+ /**
1148
+ * Get a single MCP server by ID. Returns null when not found.
1149
+ */
1150
+ get(id: string): Promise<McpServer | null>;
1151
+ };
1215
1152
  /**
1216
- * Create a new session for the given user and return the session record
1217
- * together with a `Set-Cookie` header string ready to attach to a response.
1153
+ * Least-privilege analyzer.
1154
+ *
1155
+ * Compare agent permissions against actual audit log usage to surface
1156
+ * wildcards, unused grants, and over-permissioned identities.
1218
1157
  */
1219
- createSession(userId: string, metadata?: Record<string, unknown>): Promise<CreateSessionResult>;
1158
+ analyzer: {
1159
+ analyzeAgent: (agentId: string, options?: {
1160
+ since?: Date;
1161
+ }) => Promise<PrivilegeAnalysis>;
1162
+ analyzeAll: (options?: {
1163
+ since?: Date;
1164
+ }) => Promise<PrivilegeAnalysis[]>;
1165
+ getSummary: () => Promise<PrivilegeSummary>;
1166
+ };
1220
1167
  /**
1221
- * Parse the `Cookie` header, look up the session in the database, and
1222
- * verify it has not expired.
1168
+ * Human auth integration.
1223
1169
  *
1224
- * When `autoRefresh` is enabled the session is extended on each valid
1225
- * request and a new `Set-Cookie` header is returned for forwarding.
1170
+ * `resolveUser` extracts the authenticated human from an inbound HTTP
1171
+ * request via the configured adapter. `session` is a full session
1172
+ * manager (create / validate / revoke) when `auth.session` was passed
1173
+ * to `createTheAuth()`.
1226
1174
  *
1227
- * @param cookieHeader Raw value of the `Cookie` request header.
1175
+ * @example
1176
+ * ```typescript
1177
+ * app.use(async (req, res, next) => {
1178
+ * const user = await theauth.auth.resolveUser(req);
1179
+ * if (!user) return res.status(401).json({ error: 'Unauthorized' });
1180
+ * req.user = user;
1181
+ * next();
1182
+ * });
1183
+ * ```
1228
1184
  */
1229
- validateSession(cookieHeader: string): Promise<ValidateSessionResult>;
1185
+ auth: {
1186
+ resolveUser(request: Request): Promise<ResolvedUser | null>;
1187
+ session: SessionManager | null;
1188
+ };
1230
1189
  /**
1231
- * Extend the session expiry to `now + maxAge`.
1190
+ * Resolve a human user from an incoming HTTP request.
1232
1191
  *
1233
- * Returns the updated session and a fresh `Set-Cookie` header.
1234
- * Returns `null` when the session does not exist.
1192
+ * @deprecated Use `theauth.auth.resolveUser(request)` instead.
1235
1193
  */
1236
- refreshSession(sessionId: string): Promise<{
1237
- session: Session;
1238
- setCookieHeader: string;
1239
- } | null>;
1194
+ resolveUser(request: Request): Promise<ResolvedUser | null>;
1195
+ /** Direct database access for advanced usage */
1196
+ db: Database;
1240
1197
  /**
1241
- * Delete a session by ID (server-side) and return a deletion cookie that
1242
- * will clear the browser cookie on the next response.
1198
+ * Multi-tenant isolation.
1199
+ *
1200
+ * Create and manage tenants (organizations) that share a single
1201
+ * TheAuth instance with full data isolation. Agents can be scoped
1202
+ * to a tenant via `tenantId`.
1243
1203
  */
1244
- revokeSession(sessionId: string): Promise<{
1245
- deleteCookieHeader: string;
1246
- }>;
1204
+ tenant: {
1205
+ create: (input: CreateTenantInput) => Promise<Tenant>;
1206
+ get: (tenantId: string) => Promise<Tenant | null>;
1207
+ getBySlug: (slug: string) => Promise<Tenant | null>;
1208
+ list: () => Promise<Tenant[]>;
1209
+ update: (tenantId: string, updates: Partial<CreateTenantInput>) => Promise<Tenant>;
1210
+ suspend: (tenantId: string) => Promise<void>;
1211
+ activate: (tenantId: string) => Promise<void>;
1212
+ };
1247
1213
  /**
1248
- * Revoke all sessions for the given user.
1214
+ * Agent execution budget policies.
1249
1215
  *
1250
- * Returns a deletion cookie header for clearing the current browser cookie.
1216
+ * Set spending caps (token cost, call counts) per agent, user, or
1217
+ * tenant. Exceeded policies trigger a configurable action: warn,
1218
+ * throttle, block, or revoke.
1251
1219
  */
1252
- revokeAllSessions(userId: string): Promise<{
1253
- deleteCookieHeader: string;
1254
- }>;
1220
+ policies: {
1221
+ create: (input: CreatePolicyInput) => Promise<BudgetPolicy>;
1222
+ get: (policyId: string) => Promise<BudgetPolicy | null>;
1223
+ list: (filters?: PolicyFilters) => Promise<BudgetPolicy[]>;
1224
+ update: (policyId: string, updates: Partial<BudgetPolicy>) => Promise<BudgetPolicy>;
1225
+ remove: (policyId: string) => Promise<void>;
1226
+ checkBudget: (agentId: string, tokensCost?: number) => Promise<{
1227
+ allowed: boolean;
1228
+ reason?: string;
1229
+ policy?: BudgetPolicy;
1230
+ }>;
1231
+ recordUsage: (agentId: string, tokensCost?: number) => Promise<void>;
1232
+ resetDaily: () => Promise<{
1233
+ reset: number;
1234
+ }>;
1235
+ resetMonthly: () => Promise<{
1236
+ reset: number;
1237
+ }>;
1238
+ };
1255
1239
  /**
1256
- * List all non-expired sessions for a user, newest first.
1240
+ * CIBA-style async human approval flows.
1241
+ *
1242
+ * Create pending approval requests, notify humans via webhook or
1243
+ * custom handler, and resolve them with approve / deny.
1257
1244
  */
1258
- listSessions(userId: string): Promise<Session[]>;
1245
+ approval: {
1246
+ request: (input: {
1247
+ agentId: string;
1248
+ userId: string;
1249
+ action: string;
1250
+ resource: string;
1251
+ arguments?: Record<string, unknown>;
1252
+ }) => Promise<ApprovalRequest>;
1253
+ approve: (requestId: string, respondedBy?: string) => Promise<ApprovalRequest>;
1254
+ deny: (requestId: string, respondedBy?: string) => Promise<ApprovalRequest>;
1255
+ get: (requestId: string) => Promise<ApprovalRequest | null>;
1256
+ listPending: (userId?: string) => Promise<ApprovalRequest[]>;
1257
+ cleanup: () => Promise<{
1258
+ expired: number;
1259
+ }>;
1260
+ };
1259
1261
  /**
1260
- * Build a `Set-Cookie` header that deletes the session cookie on the client
1261
- * without any database operation. Useful in error paths.
1262
+ * Graduated autonomy trust scoring.
1263
+ *
1264
+ * Compute and persist 0-100 trust scores derived from audit history,
1265
+ * mapped to five levels: untrusted, limited, standard, trusted, elevated.
1262
1266
  */
1263
- buildLogoutCookie(): string;
1264
- /** Expose the underlying low-level session manager for advanced usage. */
1265
- raw: SessionManager;
1266
- }
1267
- /**
1268
- * Create a cookie-aware session manager.
1269
- *
1270
- * Internally delegates all DB operations to `createSessionManager`.
1271
- *
1272
- * @param config Cookie-aware session configuration.
1273
- * @param db Drizzle database instance from `createDatabase()`.
1274
- */
1275
- declare function createCookieSessionManager(config: CookieSessionConfig, db: Database): CookieSessionManager;
1276
-
1277
- /**
1278
- * Multi-session support for TheAuth.
1279
- *
1280
- * Allows users to maintain multiple concurrent sessions (phone, laptop, tablet)
1281
- * with optional per-user session caps. When the cap is reached, the oldest
1282
- * session is evicted automatically (configurable).
1283
- *
1284
- * Uses the existing `kavach_sessions` table — no additional schema required.
1285
- *
1286
- * @example
1287
- * ```typescript
1288
- * const multiSession = createMultiSessionModule(
1289
- * { maxSessions: 5, overflowStrategy: 'evict-oldest' },
1290
- * db,
1291
- * sessionManager,
1292
- * );
1293
- *
1294
- * // List all active sessions for a user
1295
- * const sessionList = await multiSession.listSessions(userId);
1296
- *
1297
- * // Sign out everywhere except here
1298
- * const count = await multiSession.revokeOtherSessions(userId, currentSessionId);
1299
- * ```
1300
- */
1301
-
1302
- interface MultiSessionConfig {
1303
- /** Max concurrent sessions per user (default: 10) */
1304
- maxSessions?: number;
1305
- /** Strategy when max is reached (default: 'evict-oldest') */
1306
- overflowStrategy?: "reject" | "evict-oldest";
1307
- }
1308
- interface SessionInfo {
1309
- id: string;
1310
- createdAt: Date;
1311
- expiresAt: Date;
1312
- metadata?: Record<string, unknown>;
1313
- /** Human-readable device string extracted from User-Agent, e.g. "Chrome on macOS" */
1314
- device?: string;
1315
- /** IP address recorded at session creation */
1316
- ip?: string;
1317
- }
1318
- interface MultiSessionModule {
1319
- /** List all non-expired sessions for a user, newest first. */
1320
- listSessions(userId: string): Promise<SessionInfo[]>;
1321
- /** Revoke a single session by ID. */
1322
- revokeSession(sessionId: string): Promise<void>;
1323
- /** Revoke every session except the given one. Returns the count revoked. */
1324
- revokeOtherSessions(userId: string, currentSessionId: string): Promise<number>;
1325
- /** Return the count of active (non-expired) sessions for a user. */
1326
- getSessionCount(userId: string): Promise<number>;
1267
+ trust: {
1268
+ computeScore: (agentId: string) => Promise<TrustScore>;
1269
+ getScore: (agentId: string) => Promise<TrustScore | null>;
1270
+ computeAll: () => Promise<TrustScore[]>;
1271
+ getScores: (filters?: {
1272
+ level?: string;
1273
+ minScore?: number;
1274
+ }) => Promise<TrustScore[]>;
1275
+ };
1327
1276
  /**
1328
- * Enforce the session cap before creating a new session.
1277
+ * W3C Decentralized Identifiers (DID) for agents.
1329
1278
  *
1330
- * Call this before `sessionManager.create()`. If the cap is reached:
1331
- * - `evict-oldest` deletes the oldest session and resolves.
1332
- * - `reject` throws a `MultiSessionLimitError`.
1279
+ * Generate did:key or did:web identities, sign payloads, and verify
1280
+ * signatures. Private keys are never stored — they are returned to
1281
+ * the caller on generation and must be stored securely.
1282
+ *
1283
+ * @example
1284
+ * ```typescript
1285
+ * const { agentDid, privateKeyJwk } = await theauth.did.generateKey(agentId);
1286
+ * const signed = await theauth.did.sign(agentId, { action: 'read' }, privateKeyJwk);
1287
+ * const result = await theauth.did.verify(signed.jws, agentDid.did);
1288
+ * ```
1333
1289
  */
1334
- enforceSessionLimit(userId: string): Promise<void>;
1335
- }
1336
- declare class MultiSessionLimitError extends Error {
1337
- readonly code = "SESSION_LIMIT_REACHED";
1338
- constructor(userId: string, max: number);
1339
- }
1340
- declare function createMultiSessionModule(config: MultiSessionConfig, db: Database, sessionManager: SessionManager): MultiSessionModule;
1341
- /**
1342
- * Build metadata to pass to `sessionManager.create()` that includes
1343
- * device info extracted from the incoming request.
1344
- *
1345
- * @example
1346
- * ```typescript
1347
- * const meta = buildSessionMetadata(request, { role: 'admin' });
1348
- * const { token } = await sessionManager.create(userId, meta);
1349
- * ```
1350
- */
1351
- declare function buildSessionMetadata(request: Request, extra?: Record<string, unknown>): Record<string, unknown>;
1352
-
1353
- /**
1354
- * Token family tracking for refresh token reuse detection.
1355
- *
1356
- * Each refresh token belongs to a "family" — a chain of rotations that all
1357
- * originate from the same initial login. When `reuseDetection` is enabled,
1358
- * presenting an already-used token from a family immediately revokes every
1359
- * token in that family, because reuse indicates the token was stolen.
1360
- *
1361
- * The database table `kavach_refresh_token_families` stores:
1362
- * - family-level metadata (userId, absolute expiry, revocation status)
1363
- *
1364
- * Each individual refresh token row in `kavach_refresh_tokens` links back to
1365
- * its family via `familyId`.
1366
- *
1367
- * @example
1368
- * ```typescript
1369
- * const families = createTokenFamilyStore(db);
1370
- *
1371
- * // On login — create a new family and issue the first token
1372
- * const family = await families.createFamily(userId, absoluteExpiresAt);
1373
- * const token = await families.issueToken(family.id, refreshTokenTTL);
1374
- *
1375
- * // On refresh — consume the token (marks it used, issues a new one)
1376
- * const result = await families.consumeToken(rawToken);
1377
- * if (result.status === 'reuse') {
1378
- * // Entire family revoked — force re-login
1379
- * }
1380
- * ```
1381
- */
1382
-
1383
- interface TokenFamily {
1384
- id: string;
1385
- userId: string;
1386
- /** Absolute expiry — no refresh can extend beyond this date. */
1387
- absoluteExpiresAt: Date;
1388
- revoked: boolean;
1389
- createdAt: Date;
1390
- }
1391
- type ConsumeTokenStatus = "ok" /** Token valid, successfully consumed. */ | "expired" /** Token has passed its TTL. */ | "revoked" /** Entire family has been revoked (stolen token detected). */ | "reuse" /** Token was already used — family has now been revoked. */ | "not_found"; /** Token does not exist in the database. */
1392
- interface ConsumeTokenResult {
1393
- status: ConsumeTokenStatus;
1394
- /** Populated when status is `"ok"`. */
1395
- family?: TokenFamily;
1396
- }
1397
- interface TokenFamilyStore {
1290
+ did: {
1291
+ generateKey: (agentId: string) => Promise<{
1292
+ agentDid: AgentDid;
1293
+ privateKeyJwk: JsonWebKey;
1294
+ }>;
1295
+ generateWeb: (agentId: string) => Promise<{
1296
+ agentDid: AgentDid;
1297
+ privateKeyJwk: JsonWebKey;
1298
+ }>;
1299
+ resolve: (did: string) => Promise<DidDocument | null>;
1300
+ getAgentDid: (agentId: string) => Promise<AgentDid | null>;
1301
+ sign: (agentId: string, payload: Record<string, unknown>, privateKeyJwk: JsonWebKey) => Promise<SignedPayload>;
1302
+ verify: (jws: string, did?: string) => Promise<VerificationResult>;
1303
+ createPresentation: (options: {
1304
+ agentId: string;
1305
+ privateKeyJwk: JsonWebKey;
1306
+ capabilities: string[];
1307
+ audience?: string;
1308
+ expiresIn?: number;
1309
+ }) => Promise<string>;
1310
+ verifyPresentation: (jwt: string) => Promise<VerificationResult & {
1311
+ capabilities?: string[];
1312
+ }>;
1313
+ };
1398
1314
  /**
1399
- * Create a new token family for a user.
1400
- * Call this once per login to anchor the refresh token chain.
1315
+ * Magic link (passwordless email) authentication.
1316
+ *
1317
+ * Null when `magicLink` config was not provided or `auth.session` is not
1318
+ * configured (sessions are required to issue tokens on verification).
1319
+ *
1320
+ * @example
1321
+ * ```typescript
1322
+ * // In your route handler
1323
+ * const response = await theauth.magicLink?.handleRequest(request);
1324
+ * if (response) return response;
1325
+ * ```
1401
1326
  */
1402
- createFamily(userId: string, absoluteExpiresAt: Date): Promise<TokenFamily>;
1327
+ magicLink: MagicLinkModule | null;
1403
1328
  /**
1404
- * Issue a new opaque refresh token tied to the given family.
1329
+ * Email OTP (one-time password) authentication.
1405
1330
  *
1406
- * Returns the raw token string (only returned once — never stored in the
1407
- * clear) and the token's individual expiry date.
1331
+ * Null when `emailOtp` config was not provided or `auth.session` is not
1332
+ * configured.
1333
+ *
1334
+ * @example
1335
+ * ```typescript
1336
+ * const response = await theauth.emailOtp?.handleRequest(request);
1337
+ * if (response) return response;
1338
+ * ```
1408
1339
  */
1409
- issueToken(familyId: string, ttlMs: number): Promise<{
1410
- rawToken: string;
1411
- expiresAt: Date;
1412
- }>;
1340
+ emailOtp: EmailOtpModule | null;
1413
1341
  /**
1414
- * Consume a refresh token.
1342
+ * TOTP two-factor authentication.
1415
1343
  *
1416
- * - If the token is valid and unused, it is marked `used` and the caller
1417
- * should immediately call `issueToken` to rotate.
1418
- * - If the token was already used, the **entire family is revoked** (reuse
1419
- * detection — token theft assumed).
1420
- * - If the token has expired or is not found, returns the appropriate status.
1344
+ * Null when `totp` config was not provided.
1345
+ *
1346
+ * @example
1347
+ * ```typescript
1348
+ * // On setup (show QR code to user)
1349
+ * const { secret, uri, backupCodes } = await theauth.totp.setup(userId);
1350
+ *
1351
+ * // After user scans QR and enters code
1352
+ * const { enabled } = await theauth.totp.enable(userId, totpCode);
1353
+ *
1354
+ * // On login (after password check)
1355
+ * const { valid } = await theauth.totp.verify(userId, totpCode);
1356
+ * ```
1421
1357
  */
1422
- consumeToken(rawToken: string): Promise<ConsumeTokenResult>;
1358
+ totp: TotpModule | null;
1423
1359
  /**
1424
- * Revoke all token families (and their tokens) for a user.
1425
- * Used on logout, password change, or explicit session termination.
1360
+ * Passkey / WebAuthn authentication.
1361
+ *
1362
+ * Null when `passkey` config was not provided.
1363
+ *
1364
+ * @example
1365
+ * ```typescript
1366
+ * // Registration — step 1: get options, send to browser
1367
+ * const options = await theauth.passkey.getRegistrationOptions(userId, userName);
1368
+ *
1369
+ * // Registration — step 2: verify browser response
1370
+ * const { credential } = await theauth.passkey.verifyRegistration(userId, response);
1371
+ *
1372
+ * // Authentication — step 1: get options
1373
+ * const options = await theauth.passkey.getAuthenticationOptions(userId);
1374
+ *
1375
+ * // Authentication — step 2: verify browser response
1376
+ * const result = await theauth.passkey.verifyAuthentication(response);
1377
+ * if (result) console.log('Authenticated user:', result.userId);
1378
+ * ```
1426
1379
  */
1427
- revokeFamiliesForUser(userId: string): Promise<void>;
1380
+ passkey: PasskeyModule | null;
1428
1381
  /**
1429
- * Revoke a specific family by ID and all its tokens.
1382
+ * Organizations + RBAC.
1383
+ *
1384
+ * Null when `org` config was not provided.
1385
+ *
1386
+ * @example
1387
+ * ```typescript
1388
+ * const org = await theauth.org?.create({ name: 'Acme', slug: 'acme', ownerId: userId });
1389
+ * const allowed = await theauth.org?.hasPermission(org.id, userId, 'agents:create');
1390
+ * ```
1430
1391
  */
1431
- revokeFamily(familyId: string): Promise<void>;
1392
+ org: OrgModule | null;
1432
1393
  /**
1433
- * Check whether the absolute session timeout has been reached for a family.
1434
- * Returns `true` when the family is still within its absolute timeout.
1394
+ * SSO (SAML 2.0 + OIDC) enterprise authentication.
1395
+ *
1396
+ * Null when `sso` config was not provided.
1397
+ *
1398
+ * @example
1399
+ * ```typescript
1400
+ * const conn = await theauth.sso?.createConnection({ orgId, providerId: 'okta', type: 'saml', domain: 'acme.com' });
1401
+ * const url = await theauth.sso?.getSamlAuthUrl(conn.id);
1402
+ * ```
1435
1403
  */
1436
- isFamilyActive(family: TokenFamily): boolean;
1437
- }
1438
- /**
1439
- * Create a `TokenFamilyStore` backed by the TheAuth database.
1440
- */
1441
- declare function createTokenFamilyStore(db: Database): TokenFamilyStore;
1442
-
1443
- /**
1444
- * Session refresh endpoint handler for TheAuth.
1445
- *
1446
- * Implements `POST /auth/refresh`:
1447
- * 1. Extracts the refresh token from an httpOnly cookie or the request body.
1448
- * 2. Validates the token (TTL, reuse detection, absolute timeout).
1449
- * 3. Issues a new short-lived access token (signed JWT).
1450
- * 4. Rotates the refresh token (one-time use — the old one is consumed).
1451
- * 5. Records the rotation in the audit log.
1452
- *
1453
- * Token family tracking (via `createTokenFamilyStore`) provides reuse
1454
- * detection: if an attacker uses a stolen refresh token after the legitimate
1455
- * user has already rotated it, the entire family is revoked and both parties
1456
- * are forced to re-authenticate.
1457
- *
1458
- * @example
1459
- * ```typescript
1460
- * const refresher = createSessionRefresher({
1461
- * secret: process.env.SESSION_SECRET,
1462
- * session: {
1463
- * accessTokenTTL: "15m",
1464
- * refreshTokenTTL: "30d",
1465
- * absoluteTimeout: "90d",
1466
- * rotateRefreshTokens: true,
1467
- * reuseDetection: true,
1468
- * },
1469
- * db,
1470
- * });
1471
- *
1472
- * // In your Hono / Express router:
1473
- * app.post('/auth/refresh', async (ctx) => {
1474
- * const result = await refresher.handleRequest(ctx.req.raw);
1475
- * return result.response;
1476
- * });
1477
- * ```
1478
- */
1479
-
1480
- interface RefreshSessionConfig {
1404
+ sso: SsoModule | null;
1481
1405
  /**
1482
- * Short-lived access token lifetime.
1483
- * Parsed duration string, e.g. `"15m"`.
1484
- * Defaults to `"15m"`.
1406
+ * Admin module.
1407
+ *
1408
+ * Null when `admin` config was not provided.
1409
+ *
1410
+ * @example
1411
+ * ```typescript
1412
+ * await theauth.admin?.banUser(userId, 'Spam');
1413
+ * const { session } = await theauth.admin?.impersonate(adminId, userId);
1414
+ * ```
1415
+ */
1416
+ admin: AdminModule | null;
1417
+ /**
1418
+ * API key management.
1419
+ *
1420
+ * Null when `apiKeys` config was not provided.
1421
+ *
1422
+ * @example
1423
+ * ```typescript
1424
+ * const { key, apiKey } = await theauth.apiKeys?.create({ userId, name: 'CI', permissions: ['agents:read'] });
1425
+ * const result = await theauth.apiKeys?.validate(key);
1426
+ * ```
1427
+ */
1428
+ apiKeys: ApiKeyManagerModule | null;
1429
+ /**
1430
+ * Username + password authentication.
1431
+ *
1432
+ * Null when `username` config was not provided or `auth.session` is not
1433
+ * configured (sessions are required to issue tokens on sign-in/up).
1434
+ *
1435
+ * @example
1436
+ * ```typescript
1437
+ * const response = await theauth.username?.handleRequest(request);
1438
+ * if (response) return response;
1439
+ * ```
1485
1440
  */
1486
- accessTokenTTL?: string;
1441
+ username: UsernameAuthModule | null;
1487
1442
  /**
1488
- * Long-lived refresh token lifetime.
1489
- * Parsed duration string, e.g. `"30d"`.
1490
- * Defaults to `"30d"`.
1443
+ * Password reset (forgot password + reset password).
1444
+ *
1445
+ * Null when `passwordReset` config was not provided or `auth.session`
1446
+ * is not configured.
1447
+ *
1448
+ * @example
1449
+ * ```typescript
1450
+ * // In your route handler
1451
+ * const response = await theauth.passwordReset?.handleRequest(request);
1452
+ * if (response) return response;
1453
+ *
1454
+ * // Or programmatically
1455
+ * await theauth.passwordReset?.requestReset('alice@example.com');
1456
+ * await theauth.passwordReset?.resetPassword(token, 'new-password');
1457
+ * ```
1491
1458
  */
1492
- refreshTokenTTL?: string;
1459
+ passwordReset: PasswordResetModule | null;
1493
1460
  /**
1494
- * When `true` (default), each use of a refresh token rotates it: the old
1495
- * token is invalidated and a new one is issued.
1461
+ * Email address verification.
1462
+ *
1463
+ * Null when `emailVerification` config was not provided.
1464
+ *
1465
+ * @example
1466
+ * ```typescript
1467
+ * // Send a verification email after sign-up
1468
+ * await theauth.emailVerification?.sendVerification(userId, email);
1469
+ *
1470
+ * // Confirm from the link in the email
1471
+ * const result = await theauth.emailVerification?.verify(token);
1472
+ *
1473
+ * // Check status
1474
+ * const verified = await theauth.emailVerification?.isVerified(userId);
1475
+ * ```
1496
1476
  */
1497
- rotateRefreshTokens?: boolean;
1477
+ emailVerification: EmailVerificationModule | null;
1498
1478
  /**
1499
- * Maximum session lifetime regardless of how many times the token is
1500
- * refreshed. Parsed duration string, e.g. `"90d"`.
1501
- * Defaults to `"90d"`.
1479
+ * One-time tokens (email verify, password reset, invitations, custom).
1480
+ *
1481
+ * Always available. Used internally by password reset but exposed for
1482
+ * custom flows (email verification, invitation links, etc.).
1502
1483
  */
1503
- absoluteTimeout?: string;
1484
+ oneTimeTokens: OneTimeTokenModule;
1504
1485
  /**
1505
- * When `true` (default), presenting an already-used refresh token triggers
1506
- * reuse detection and revokes the entire token family.
1486
+ * Session freshness enforcement for sensitive operations.
1487
+ *
1488
+ * Use as middleware before password changes, passkey registration,
1489
+ * billing updates, or any action that requires a recently-authenticated
1490
+ * session rather than an auto-refreshed one.
1491
+ *
1492
+ * @example
1493
+ * ```typescript
1494
+ * const stale = theauth.sessionFreshness.guard(session);
1495
+ * if (stale) return stale; // 403 SESSION_NOT_FRESH
1496
+ * ```
1507
1497
  */
1508
- reuseDetection?: boolean;
1498
+ sessionFreshness: SessionFreshnessModule;
1509
1499
  /**
1510
- * Name of the httpOnly cookie that carries the refresh token.
1511
- * Defaults to `"kavach_refresh"`.
1500
+ * Phone number (SMS OTP) authentication.
1501
+ *
1502
+ * Null when `phone` config was not provided or `auth.session` is not
1503
+ * configured.
1504
+ *
1505
+ * @example
1506
+ * ```typescript
1507
+ * const response = await theauth.phone?.handleRequest(request);
1508
+ * if (response) return response;
1509
+ * ```
1512
1510
  */
1513
- refreshCookieName?: string;
1511
+ phone: PhoneAuthModule | null;
1514
1512
  /**
1515
- * Name of the httpOnly cookie that carries the access token (when cookie
1516
- * transport is used for the access token too).
1517
- * Defaults to `"kavach_access"`.
1513
+ * Captcha integration (reCAPTCHA, hCaptcha, Cloudflare Turnstile).
1514
+ *
1515
+ * Null when `captcha` config was not provided.
1516
+ *
1517
+ * @example
1518
+ * ```typescript
1519
+ * const result = await theauth.captcha?.verify(token, ip);
1520
+ * if (!result?.success) return new Response('Captcha failed', { status: 403 });
1521
+ * ```
1518
1522
  */
1519
- accessCookieName?: string;
1520
- }
1521
- interface SessionRefresherConfig {
1522
- /** Signing secret — at least 32 characters. */
1523
- secret: string;
1524
- /** Refresh / rotation settings. */
1525
- session?: RefreshSessionConfig;
1526
- /** Drizzle database instance. */
1527
- db: Database;
1528
- }
1529
- /** The payload embedded in the short-lived access token JWT. */
1530
- interface AccessTokenPayload {
1531
- /** User ID. */
1532
- sub: string;
1533
- /** Token family ID — used for server-side token binding. */
1534
- familyId: string;
1535
- /** Token type discriminator. */
1536
- type: "access";
1537
- }
1538
- interface RefreshResult {
1539
- /** Signed access token JWT. */
1540
- accessToken: string;
1541
- /** Raw opaque refresh token (only returned once — store in httpOnly cookie). */
1542
- refreshToken: string;
1543
- /** Expiry date of the new access token. */
1544
- accessTokenExpiresAt: Date;
1545
- /** Expiry date of the new refresh token. */
1546
- refreshTokenExpiresAt: Date;
1547
- /** The token family these tokens belong to. */
1548
- family: TokenFamily;
1549
- }
1550
- type RefreshError = "token_missing" | "token_not_found" | "token_expired" | "token_reuse" | "family_revoked" | "absolute_timeout";
1551
- interface RefreshHandleResult {
1552
- /** HTTP Response ready to return to the caller. */
1553
- response: Response;
1554
- /** Populated on success. */
1555
- result?: RefreshResult;
1556
- /** Populated on failure. */
1557
- error?: RefreshError;
1558
- }
1559
- interface SessionRefresher {
1523
+ captcha: CaptchaModule | null;
1560
1524
  /**
1561
- * Low-level refresh — takes a raw refresh token string directly.
1525
+ * Webhook system.
1562
1526
  *
1563
- * Returns `RefreshResult` on success or throws a `RefreshTokenError`.
1527
+ * Null when `webhooks` config was not provided or the array is empty.
1528
+ *
1529
+ * @example
1530
+ * ```typescript
1531
+ * theauth.webhooks?.emit('user.created', { userId: user.id });
1532
+ * ```
1564
1533
  */
1565
- refresh(rawRefreshToken: string): Promise<RefreshResult>;
1534
+ webhooks: WebhookModule$1 | null;
1566
1535
  /**
1567
- * High-level HTTP handler.
1536
+ * Redirect chain manager.
1568
1537
  *
1569
- * Extracts the refresh token from the `Cookie` header (preferred) or the
1570
- * JSON request body, calls `refresh()`, and returns a `Response` with
1571
- * appropriate `Set-Cookie` headers.
1538
+ * Capture the user's original destination before auth redirects, push
1539
+ * intermediate steps (onboarding, email verification), and pop them
1540
+ * back in order. Cookie-based, works across page transitions and tabs.
1541
+ *
1542
+ * @example
1543
+ * ```typescript
1544
+ * // In auth middleware — save where the user was going
1545
+ * const setCookie = theauth.redirects.capture(request);
1546
+ * return new Response(null, { status: 302, headers: { Location: '/sign-in', 'Set-Cookie': setCookie } });
1547
+ *
1548
+ * // After sign-in — send user to their original destination
1549
+ * const { url, clearCookie } = theauth.redirects.pop(request);
1550
+ * const headers: Record<string, string> = { Location: url };
1551
+ * if (clearCookie) headers['Set-Cookie'] = clearCookie;
1552
+ * return new Response(null, { status: 302, headers });
1553
+ * ```
1572
1554
  */
1573
- handleRequest(request: Request): Promise<RefreshHandleResult>;
1555
+ redirects: RedirectChainManager;
1574
1556
  /**
1575
- * Issue an initial refresh token for a user (called once on login).
1557
+ * Unified policy engine.
1576
1558
  *
1577
- * Returns the access token, refresh token, and their expiry dates.
1559
+ * Single decision point that combines RBAC role expansion, ABAC constraint
1560
+ * evaluation, and ReBAC graph queries. Backed by a process-local LRU cache
1561
+ * with deterministic invalidation.
1562
+ *
1563
+ * @example
1564
+ * ```typescript
1565
+ * const decision = await theauth.policy.evaluate({
1566
+ * subject: { agentId: 'agent-abc' },
1567
+ * action: 'read',
1568
+ * resource: 'tool:github:list_issues',
1569
+ * });
1570
+ * if (!decision.allowed) throw new Error(decision.reason);
1571
+ *
1572
+ * // Flush cached decisions after a permission change
1573
+ * theauth.policy.invalidate({ agentId: 'agent-abc' });
1574
+ *
1575
+ * // Inspect cache health
1576
+ * const { hits, misses, size, evictions } = theauth.policy.stats();
1577
+ * ```
1578
1578
  */
1579
- issueInitial(userId: string): Promise<RefreshResult>;
1579
+ policy: {
1580
+ evaluate: (input: EvaluateInput) => Promise<PolicyDecision>;
1581
+ invalidate: (scope: InvalidateScope) => void;
1582
+ stats: () => PolicyCacheStats;
1583
+ };
1580
1584
  /**
1581
- * Revoke all refresh token families for a user (e.g. on logout or
1582
- * password change).
1585
+ * Plugin system.
1586
+ *
1587
+ * Route incoming HTTP requests through plugin-registered endpoints,
1588
+ * retrieve all endpoints for adapter mounting, or access plugin-provided
1589
+ * context values.
1590
+ *
1591
+ * @example
1592
+ * ```typescript
1593
+ * // In a framework adapter
1594
+ * app.all('/theauth/*', async (req) => {
1595
+ * const response = await theauth.plugins.handleRequest(req);
1596
+ * if (response) return response;
1597
+ * return new Response('Not Found', { status: 404 });
1598
+ * });
1599
+ * ```
1583
1600
  */
1584
- revokeAll(userId: string): Promise<void>;
1585
- }
1586
- /** Thrown by `SessionRefresher.refresh()` on validation failure. */
1587
- declare class RefreshTokenError extends Error {
1588
- readonly code: RefreshError;
1589
- constructor(code: RefreshError, message: string);
1590
- }
1601
+ plugins: {
1602
+ /** Route a request through plugin endpoints. Returns null if no plugin handles it. */
1603
+ handleRequest(request: Request, basePath?: string): Promise<Response | null>;
1604
+ /** Get all endpoints registered by plugins (for framework adapter mounting). */
1605
+ getEndpoints(): PluginEndpoint[];
1606
+ /** Get the merged plugin context (values returned from plugin init). */
1607
+ getContext(): Record<string, unknown>;
1608
+ /** Access the raw plugin registry (hooks, migrations, etc.). */
1609
+ registry: PluginRegistry;
1610
+ };
1611
+ }>;
1612
+ type TheAuth = Awaited<ReturnType<typeof createTheAuth>>;
1591
1613
  /**
1592
- * Create a `SessionRefresher` backed by the TheAuth database.
1614
+ * @deprecated Use `createTheAuth` instead. Will be removed in a future major version.
1593
1615
  */
1594
- declare function createSessionRefresher(config: SessionRefresherConfig): SessionRefresher;
1595
-
1596
- interface Tenant {
1597
- id: string;
1598
- name: string;
1599
- slug: string;
1600
- settings: TenantSettings;
1601
- status: "active" | "suspended";
1602
- createdAt: Date;
1603
- updatedAt: Date;
1604
- }
1605
- interface TenantSettings {
1606
- maxAgents?: number;
1607
- maxDelegationDepth?: number;
1608
- auditRetentionDays?: number;
1609
- allowedAgentTypes?: string[];
1610
- }
1611
- interface CreateTenantInput {
1612
- name: string;
1613
- slug: string;
1614
- settings?: Partial<TenantSettings>;
1615
- }
1616
- declare function createTenantModule(db: Database): {
1617
- create: (input: CreateTenantInput) => Promise<Tenant>;
1618
- get: (tenantId: string) => Promise<Tenant | null>;
1619
- getBySlug: (slug: string) => Promise<Tenant | null>;
1620
- list: () => Promise<Tenant[]>;
1621
- update: (tenantId: string, updates: Partial<CreateTenantInput>) => Promise<Tenant>;
1622
- suspend: (tenantId: string) => Promise<void>;
1623
- activate: (tenantId: string) => Promise<void>;
1624
- };
1616
+ declare const createAuth: typeof createTheAuth;
1617
+ /**
1618
+ * @deprecated Use `TheAuth` instead. Will be removed in a future major version.
1619
+ */
1620
+ type Auth = TheAuth;
1625
1621
 
1626
1622
  interface TrustScore {
1627
1623
  agentId: string;
@@ -1708,4 +1704,4 @@ declare function createWebhookModule(config: WebhookConfig): WebhookModule;
1708
1704
  */
1709
1705
  declare function verifyWebhookSignature(secret: string, rawBody: string, signature: string): Promise<boolean>;
1710
1706
 
1711
- export { type AccessTokenPayload, AdminModule, AgentDid, AgentFilter, AgentIdentity, ApiKeyManagerModule, ApprovalRequest, AuditEntry, AuditExportOptions, AuditFilter, AuthorizeRequest, AuthorizeResult, type BudgetLimits, type BudgetPolicy, type BudgetUsage, CaptchaModule, type ConsumeTokenResult, type ConsumeTokenStatus, type CookieOptions, type CookieSessionConfig, type CookieSessionManager, CreateAgentInput, type CreatePolicyInput, type CreateSessionResult, type CreateTenantInput, type CsrfValidationResult, Database, DatabaseConfig, DelegateInput, DelegationChain, DidDocument, DidKeyPair, type DidModule, DidWebConfig, EmailOtpModule, type EmailTemplate, type EmailTemplateConfig, type EmailTemplateName, type EmailTemplates, EmailVerificationModule, EndpointContext, type I18nConfig, type I18nModule, type Kavach, KavachConfig, KavachPlugin, MagicLinkModule, McpServer, McpServerInput, type MultiSessionConfig, MultiSessionLimitError, type MultiSessionModule, OneTimeTokenModule, OrgModule, PasskeyModule, PasswordResetModule, Permission, PhoneAuthModule, PluginEndpoint, type PluginRegistry, type PolicyFilters, type PrivilegeAnalysis, type PrivilegeAnalyzer, type PrivilegeFinding, type PrivilegeSummary, RedirectChainManager, type RefreshError, type RefreshHandleResult, type RefreshResult, type RefreshSessionConfig, RefreshTokenError, ResolvedUser, type SameSite, Session, SessionConfig, SessionFreshnessModule, type SessionInfo, SessionManager, type SessionRefresher, type SessionRefresherConfig, SignedPayload, SsoModule, type Tenant, type TenantSettings, type TokenFamily, type TokenFamilyStore, TotpModule, type TranslationKeys, type TrustConfig, type TrustModule, type TrustScore, UpdateAgentInput, UsernameAuthModule, type ValidateSessionResult, VerificationResult, type WebhookConfig, type WebhookEvent, type WebhookModule, type WebhookSubscription, buildDidDocument, buildSessionMetadata, createCookieSessionManager, createDelegationModule, createDidModule, createEmailTemplates, createI18n, createKavach, createMultiSessionModule, createPluginRouter, createPolicyModule, createPresentation, createPrivilegeAnalyzer, createSessionRefresher, createTables, createTenantModule, createTokenFamilyStore, createTrustModule, createWebhookModule, de, en, es, fr, generateCsrfToken, generateDidKey, generateDidWeb, generateOpenAPISpec, getCookie, getDidWebUrl, initializePlugins, ja, parseCookies, parseCookiesFromRequest, resolveDidKey, resolveDidWeb, serializeCookie, serializeCookieDeletion, signPayload, validateCsrfToken, validateOrigin, verifyPayload, verifyPresentation, verifyWebhookSignature, zh };
1707
+ export { type AccessTokenPayload, AdminModule, AgentDid, AgentFilter, AgentIdentity, ApiKeyManagerModule, ApprovalRequest, AuditEntry, AuditExportOptions, AuditFilter, type Auth, AuthorizeRequest, AuthorizeResult, type BudgetLimits, type BudgetPolicy, type BudgetUsage, CaptchaModule, type ConsumeTokenResult, type ConsumeTokenStatus, type CookieOptions, type CookieSessionConfig, type CookieSessionManager, CreateAgentInput, type CreatePolicyInput, type CreateSessionResult, type CreateTenantInput, type CsrfValidationResult, Database, DatabaseConfig, DelegateInput, DelegationChain, DelegationError, type DelegationErrorCode, DidDocument, DidKeyPair, type DidModule, DidWebConfig, EmailOtpModule, type EmailTemplate, type EmailTemplateConfig, type EmailTemplateName, type EmailTemplates, EmailVerificationModule, EndpointContext, type I18nConfig, type I18nModule, MagicLinkModule, McpServer, McpServerInput, type MultiSessionConfig, MultiSessionLimitError, type MultiSessionModule, OneTimeTokenModule, OrgModule, PasskeyModule, PasswordResetModule, Permission, PhoneAuthModule, PluginEndpoint, type PluginRegistry, type PolicyFilters, type PrivilegeAnalysis, type PrivilegeAnalyzer, type PrivilegeFinding, type PrivilegeSummary, RedirectChainManager, type RefreshError, type RefreshHandleResult, type RefreshResult, type RefreshSessionConfig, RefreshTokenError, ResolvedUser, type SameSite, Session, SessionConfig, SessionFreshnessModule, type SessionInfo, SessionManager, type SessionRefresher, type SessionRefresherConfig, SignedPayload, SsoModule, type Tenant, type TenantSettings, type TheAuth, TheAuthConfig, TheAuthPlugin, type TokenFamily, type TokenFamilyStore, TotpModule, type TranslationKeys, type TrustConfig, type TrustModule, type TrustScore, UpdateAgentInput, UsernameAuthModule, type ValidateSessionResult, VerificationResult, type WebhookConfig, type WebhookEvent, type WebhookModule, type WebhookSubscription, buildDidDocument, buildSessionMetadata, createAuth, createCookieSessionManager, createDelegationModule, createDidModule, createEmailTemplates, createI18n, createMultiSessionModule, createPluginRouter, createPolicyModule, createPresentation, createPrivilegeAnalyzer, createSessionRefresher, createTables, createTenantModule, createTheAuth, createTokenFamilyStore, createTrustModule, createWebhookModule, de, en, es, fr, generateCsrfToken, generateDidKey, generateDidWeb, generateOpenAPISpec, getCookie, getDidWebUrl, initializePlugins, ja, parseCookies, parseCookiesFromRequest, resolveDidKey, resolveDidWeb, serializeCookie, serializeCookieDeletion, signPayload, validateCsrfToken, validateOrigin, verifyPayload, verifyPresentation, verifyWebhookSignature, zh };