@glinr/theauth 0.5.0 → 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/README.md +54 -20
- package/dist/a2a/index.d.ts +3 -3
- package/dist/a2a/index.js.map +1 -1
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +48 -48
- package/dist/agent/index.js.map +1 -1
- package/dist/audit/index.d.ts +2 -2
- package/dist/audit/index.js +48 -48
- package/dist/audit/index.js.map +1 -1
- package/dist/auth/index.d.ts +71 -51
- package/dist/auth/index.js +1156 -241
- package/dist/auth/index.js.map +1 -1
- package/dist/index.d.ts +1204 -1224
- package/dist/index.js +4467 -3520
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/permission/index.d.ts +3 -3
- package/dist/permission/index.js +51 -50
- package/dist/permission/index.js.map +1 -1
- package/dist/redirect/index.d.ts +1 -1
- package/dist/redirect/index.js +1 -1
- package/dist/redirect/index.js.map +1 -1
- package/dist/standards/index.d.ts +1 -1
- package/dist/standards/index.js.map +1 -1
- package/dist/{types-D1dTo8-m.d.ts → types-JOx1R8-Q.d.ts} +494 -499
- package/dist/{types-IkWVkOVv.d.ts → types-XoCxTUZj.d.ts} +2 -6
- package/dist/vc/index.d.ts +6 -12
- package/dist/vc/index.js +4 -7
- package/dist/vc/index.js.map +1 -1
- package/package.json +10 -4
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,
|
|
4
|
-
export {
|
|
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 {
|
|
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, KAVACH_AGENT_CREDENTIAL, KAVACH_DELEGATION_CREDENTIAL, KAVACH_PERMISSION_CREDENTIAL, 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';
|
|
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-
|
|
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,1350 +282,1342 @@ declare const ja: TranslationKeys;
|
|
|
294
282
|
declare const zh: TranslationKeys;
|
|
295
283
|
|
|
296
284
|
/**
|
|
297
|
-
*
|
|
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 { createTheAuth } from '@glinr/theauth';
|
|
306
|
-
*
|
|
307
|
-
* const auth = await createTheAuth({
|
|
308
|
-
* database: { provider: 'sqlite', url: 'theauth.db' },
|
|
309
|
-
* });
|
|
310
|
-
* ```
|
|
311
|
-
*
|
|
312
|
-
* @example Postgres
|
|
313
|
-
* ```typescript
|
|
314
|
-
* const auth = await createTheAuth({
|
|
315
|
-
* database: { provider: 'postgres', url: process.env.DATABASE_URL },
|
|
316
|
-
* });
|
|
317
|
-
* ```
|
|
285
|
+
* OpenAPI 3.1 specification generator for TheAuth REST API.
|
|
318
286
|
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
* const auth = await createTheAuth({
|
|
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
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
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;
|
|
317
|
+
}>;
|
|
318
|
+
};
|
|
319
|
+
responses: Record<string, {
|
|
320
|
+
description: string;
|
|
321
|
+
content?: Record<string, {
|
|
322
|
+
schema: SchemaRef;
|
|
359
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"]>;
|
|
360
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;
|
|
361
459
|
/**
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
* Register and look up MCP tool servers. Uses the `kavach_mcp_servers`
|
|
365
|
-
* database table — no separate in-memory store needed.
|
|
460
|
+
* Restricts transmission to HTTPS. Default: true in production
|
|
461
|
+
* (when `NODE_ENV === 'production'`), false otherwise.
|
|
366
462
|
*/
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
*/
|
|
382
|
-
get(id: string): Promise<McpServer | null>;
|
|
383
|
-
};
|
|
384
|
-
/**
|
|
385
|
-
* Least-privilege analyzer.
|
|
386
|
-
*
|
|
387
|
-
* Compare agent permissions against actual audit log usage to surface
|
|
388
|
-
* wildcards, unused grants, and over-permissioned identities.
|
|
389
|
-
*/
|
|
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 `createTheAuth()`.
|
|
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 TheAuth = Awaited<ReturnType<typeof createTheAuth>>;
|
|
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
|
+
}
|
|
845
477
|
/**
|
|
846
|
-
*
|
|
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=/`.
|
|
847
484
|
*/
|
|
848
|
-
declare
|
|
485
|
+
declare function serializeCookie(name: string, value: string, options?: CookieOptions): string;
|
|
849
486
|
/**
|
|
850
|
-
*
|
|
487
|
+
* Serialize a deletion cookie (zero Max-Age, past Expires) that will
|
|
488
|
+
* instruct browsers to remove the named cookie.
|
|
851
489
|
*/
|
|
852
|
-
declare
|
|
490
|
+
declare function serializeCookieDeletion(name: string, options?: Omit<CookieOptions, "maxAge" | "expires">): string;
|
|
853
491
|
/**
|
|
854
|
-
*
|
|
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"`).
|
|
855
498
|
*/
|
|
856
|
-
|
|
499
|
+
declare function parseCookies(header: string): Record<string, string>;
|
|
857
500
|
/**
|
|
858
|
-
*
|
|
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.
|
|
859
508
|
*/
|
|
860
|
-
|
|
509
|
+
declare function parseCookiesFromRequest(request: Request): Record<string, string>;
|
|
861
510
|
|
|
862
511
|
/**
|
|
863
|
-
*
|
|
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).
|
|
527
|
+
*
|
|
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
|
+
* ```
|
|
540
|
+
*/
|
|
541
|
+
interface CsrfValidationResult {
|
|
542
|
+
valid: boolean;
|
|
543
|
+
reason?: string;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Generate a cryptographically random CSRF token.
|
|
864
547
|
*
|
|
865
|
-
*
|
|
866
|
-
*
|
|
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).
|
|
867
552
|
*/
|
|
868
|
-
|
|
869
|
-
openapi: string;
|
|
870
|
-
info: {
|
|
871
|
-
title: string;
|
|
872
|
-
version: string;
|
|
873
|
-
description: string;
|
|
874
|
-
};
|
|
875
|
-
servers: Array<{
|
|
876
|
-
url: string;
|
|
877
|
-
description: string;
|
|
878
|
-
}>;
|
|
879
|
-
paths: Record<string, Record<string, PathOperation>>;
|
|
880
|
-
components: {
|
|
881
|
-
schemas: Record<string, SchemaObject>;
|
|
882
|
-
securitySchemes: Record<string, SecurityScheme>;
|
|
883
|
-
};
|
|
884
|
-
}
|
|
885
|
-
interface PathOperation {
|
|
886
|
-
summary: string;
|
|
887
|
-
operationId: string;
|
|
888
|
-
tags: string[];
|
|
889
|
-
security?: Array<Record<string, string[]>>;
|
|
890
|
-
parameters?: ParameterObject[];
|
|
891
|
-
requestBody?: {
|
|
892
|
-
required: boolean;
|
|
893
|
-
content: Record<string, {
|
|
894
|
-
schema: SchemaRef;
|
|
895
|
-
}>;
|
|
896
|
-
};
|
|
897
|
-
responses: Record<string, {
|
|
898
|
-
description: string;
|
|
899
|
-
content?: Record<string, {
|
|
900
|
-
schema: SchemaRef;
|
|
901
|
-
}>;
|
|
902
|
-
}>;
|
|
903
|
-
}
|
|
904
|
-
interface ParameterObject {
|
|
905
|
-
name: string;
|
|
906
|
-
in: "query" | "path" | "header";
|
|
907
|
-
required: boolean;
|
|
908
|
-
schema: SchemaRef;
|
|
909
|
-
}
|
|
910
|
-
interface SecurityScheme {
|
|
911
|
-
type: string;
|
|
912
|
-
scheme?: string;
|
|
913
|
-
bearerFormat?: string;
|
|
914
|
-
}
|
|
915
|
-
type SchemaRef = {
|
|
916
|
-
$ref: string;
|
|
917
|
-
} | SchemaObject;
|
|
918
|
-
interface SchemaObject {
|
|
919
|
-
type?: string;
|
|
920
|
-
properties?: Record<string, SchemaRef>;
|
|
921
|
-
required?: string[];
|
|
922
|
-
items?: SchemaRef;
|
|
923
|
-
enum?: string[];
|
|
924
|
-
description?: string;
|
|
925
|
-
format?: string;
|
|
926
|
-
nullable?: boolean;
|
|
927
|
-
}
|
|
553
|
+
declare function generateCsrfToken(): string;
|
|
928
554
|
/**
|
|
929
|
-
*
|
|
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.
|
|
557
|
+
*
|
|
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.
|
|
930
563
|
*/
|
|
931
|
-
declare function
|
|
932
|
-
baseUrl?: string;
|
|
933
|
-
version?: string;
|
|
934
|
-
}): OpenAPISpec;
|
|
935
|
-
|
|
564
|
+
declare function validateCsrfToken(requestToken: string, cookieToken: string): CsrfValidationResult;
|
|
936
565
|
/**
|
|
937
|
-
*
|
|
566
|
+
* Validate the `Origin` (or `Referer` fallback) header of an incoming
|
|
567
|
+
* request against a list of trusted origins.
|
|
938
568
|
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
941
|
-
*
|
|
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`.
|
|
942
581
|
*/
|
|
943
|
-
declare function
|
|
944
|
-
/** Try to handle a request. Returns Response if matched, null if not. */
|
|
945
|
-
handle: (request: Request, basePath: string, endpointCtx: EndpointContext) => Promise<Response | null>;
|
|
946
|
-
/** Get all registered endpoints (for adapter mounting) */
|
|
947
|
-
getEndpoints: () => PluginEndpoint[];
|
|
948
|
-
};
|
|
582
|
+
declare function validateOrigin(request: Request, trustedOrigins: string[], allowMissingOrigin?: boolean): CsrfValidationResult;
|
|
949
583
|
|
|
950
|
-
interface PluginRegistry {
|
|
951
|
-
endpoints: PluginEndpoint[];
|
|
952
|
-
migrations: string[];
|
|
953
|
-
hooks: {
|
|
954
|
-
onRequest: Array<NonNullable<TheAuthPlugin["hooks"]>["onRequest"]>;
|
|
955
|
-
onAuthenticate: Array<NonNullable<TheAuthPlugin["hooks"]>["onAuthenticate"]>;
|
|
956
|
-
onSessionCreate: Array<NonNullable<TheAuthPlugin["hooks"]>["onSessionCreate"]>;
|
|
957
|
-
onSessionRevoke: Array<NonNullable<TheAuthPlugin["hooks"]>["onSessionRevoke"]>;
|
|
958
|
-
};
|
|
959
|
-
pluginContext: Record<string, unknown>;
|
|
960
|
-
}
|
|
961
584
|
/**
|
|
962
|
-
*
|
|
963
|
-
* into a single registry.
|
|
585
|
+
* Cookie-aware session manager for TheAuth.
|
|
964
586
|
*
|
|
965
|
-
*
|
|
966
|
-
*
|
|
967
|
-
*
|
|
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
|
+
* ```
|
|
968
618
|
*/
|
|
969
|
-
declare function initializePlugins(plugins: TheAuthPlugin[], db: Database, config: TheAuthConfig, sessionManager: SessionManager | null): Promise<PluginRegistry>;
|
|
970
619
|
|
|
971
|
-
interface
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
}
|
|
988
|
-
interface BudgetUsage {
|
|
989
|
-
tokensCostToday: number;
|
|
990
|
-
tokensCostThisMonth: number;
|
|
991
|
-
callsToday: number;
|
|
992
|
-
callsThisMonth: number;
|
|
993
|
-
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;
|
|
994
636
|
}
|
|
995
|
-
interface
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
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;
|
|
1001
642
|
}
|
|
1002
|
-
interface
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
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;
|
|
1006
651
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
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;
|
|
1021
684
|
}>;
|
|
1022
|
-
|
|
1023
|
-
|
|
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;
|
|
1024
692
|
}>;
|
|
1025
|
-
};
|
|
1026
|
-
|
|
1027
|
-
/**
|
|
1028
|
-
* Cookie serialization and parsing utilities for TheAuth.
|
|
1029
|
-
*
|
|
1030
|
-
* Pure functions that work with Web API `Request`/`Response` objects and
|
|
1031
|
-
* raw header strings. No framework dependencies.
|
|
1032
|
-
*/
|
|
1033
|
-
type SameSite = "strict" | "lax" | "none";
|
|
1034
|
-
interface CookieOptions {
|
|
1035
|
-
/** Prevents JavaScript access to the cookie. Default: true. */
|
|
1036
|
-
httpOnly?: boolean;
|
|
1037
693
|
/**
|
|
1038
|
-
*
|
|
1039
|
-
* (when `NODE_ENV === 'production'`), false otherwise.
|
|
694
|
+
* List all non-expired sessions for a user, newest first.
|
|
1040
695
|
*/
|
|
1041
|
-
|
|
1042
|
-
/**
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
maxAge?: number;
|
|
1050
|
-
/** Absolute expiry date (overridden by maxAge when both are set). */
|
|
1051
|
-
expires?: Date;
|
|
1052
|
-
/** Partitioned attribute (CHIPS). */
|
|
1053
|
-
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;
|
|
1054
704
|
}
|
|
1055
705
|
/**
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1058
|
-
* @param name Cookie name. Must be a valid cookie-name token.
|
|
1059
|
-
* @param value Cookie value. Will be percent-encoded.
|
|
1060
|
-
* @param options Cookie attributes. Defaults to `httpOnly=true`, `secure`
|
|
1061
|
-
* based on `NODE_ENV`, `sameSite=lax`, `path=/`.
|
|
1062
|
-
*/
|
|
1063
|
-
declare function serializeCookie(name: string, value: string, options?: CookieOptions): string;
|
|
1064
|
-
/**
|
|
1065
|
-
* Serialize a deletion cookie (zero Max-Age, past Expires) that will
|
|
1066
|
-
* instruct browsers to remove the named cookie.
|
|
1067
|
-
*/
|
|
1068
|
-
declare function serializeCookieDeletion(name: string, options?: Omit<CookieOptions, "maxAge" | "expires">): string;
|
|
1069
|
-
/**
|
|
1070
|
-
* Parse a `Cookie` request header string into a name → value map.
|
|
1071
|
-
*
|
|
1072
|
-
* Values are percent-decoded. Unknown or malformed pairs are skipped
|
|
1073
|
-
* silently so that a single bad cookie does not break the entire request.
|
|
706
|
+
* Create a cookie-aware session manager.
|
|
1074
707
|
*
|
|
1075
|
-
*
|
|
1076
|
-
*/
|
|
1077
|
-
declare function parseCookies(header: string): Record<string, string>;
|
|
1078
|
-
/**
|
|
1079
|
-
* Extract a single cookie value from a `Cookie` header string.
|
|
708
|
+
* Internally delegates all DB operations to `createSessionManager`.
|
|
1080
709
|
*
|
|
1081
|
-
*
|
|
1082
|
-
|
|
1083
|
-
declare function getCookie(header: string, name: string): string | undefined;
|
|
1084
|
-
/**
|
|
1085
|
-
* Extract cookies from a Web API `Request` object.
|
|
710
|
+
* @param config Cookie-aware session configuration.
|
|
711
|
+
* @param db Drizzle database instance from `createDatabase()`.
|
|
1086
712
|
*/
|
|
1087
|
-
declare function
|
|
713
|
+
declare function createCookieSessionManager(config: CookieSessionConfig, db: Database): CookieSessionManager;
|
|
1088
714
|
|
|
1089
715
|
/**
|
|
1090
|
-
*
|
|
1091
|
-
*
|
|
1092
|
-
* Implements two complementary defences:
|
|
1093
|
-
*
|
|
1094
|
-
* 1. **Origin/Referer validation** — checks the inbound request's `Origin`
|
|
1095
|
-
* (or `Referer` as fallback) against a caller-supplied allowlist. This
|
|
1096
|
-
* alone blocks the vast majority of CSRF attacks from browser clients.
|
|
716
|
+
* Multi-session support for TheAuth.
|
|
1097
717
|
*
|
|
1098
|
-
*
|
|
1099
|
-
*
|
|
1100
|
-
*
|
|
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).
|
|
1101
721
|
*
|
|
1102
|
-
*
|
|
1103
|
-
* header is absent (e.g. same-origin requests on some browsers, server-side
|
|
1104
|
-
* fetch).
|
|
722
|
+
* Uses the existing `theauth_sessions` table — no additional schema required.
|
|
1105
723
|
*
|
|
1106
724
|
* @example
|
|
1107
725
|
* ```typescript
|
|
1108
|
-
*
|
|
726
|
+
* const multiSession = createMultiSessionModule(
|
|
727
|
+
* { maxSessions: 5, overflowStrategy: 'evict-oldest' },
|
|
728
|
+
* db,
|
|
729
|
+
* sessionManager,
|
|
730
|
+
* );
|
|
1109
731
|
*
|
|
1110
|
-
* //
|
|
1111
|
-
* const
|
|
732
|
+
* // List all active sessions for a user
|
|
733
|
+
* const sessionList = await multiSession.listSessions(userId);
|
|
1112
734
|
*
|
|
1113
|
-
* //
|
|
1114
|
-
* const
|
|
1115
|
-
* const tokenOk = validateCsrfToken(submittedToken, cookieToken);
|
|
1116
|
-
* if (!originOk && !tokenOk) throw new Error('CSRF check failed');
|
|
735
|
+
* // Sign out everywhere except here
|
|
736
|
+
* const count = await multiSession.revokeOtherSessions(userId, currentSessionId);
|
|
1117
737
|
* ```
|
|
1118
738
|
*/
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
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>;
|
|
773
|
+
}
|
|
774
|
+
declare class MultiSessionLimitError extends Error {
|
|
775
|
+
readonly code = "SESSION_LIMIT_REACHED";
|
|
776
|
+
constructor(userId: string, max: number);
|
|
1122
777
|
}
|
|
778
|
+
declare function createMultiSessionModule(config: MultiSessionConfig, db: Database, sessionManager: SessionManager): MultiSessionModule;
|
|
1123
779
|
/**
|
|
1124
|
-
*
|
|
1125
|
-
*
|
|
1126
|
-
* Uses `crypto.getRandomValues` (Web Crypto API) so it works in both
|
|
1127
|
-
* 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.
|
|
1128
782
|
*
|
|
1129
|
-
*
|
|
783
|
+
* @example
|
|
784
|
+
* ```typescript
|
|
785
|
+
* const meta = buildSessionMetadata(request, { role: 'admin' });
|
|
786
|
+
* const { token } = await sessionManager.create(userId, meta);
|
|
787
|
+
* ```
|
|
1130
788
|
*/
|
|
1131
|
-
declare function
|
|
789
|
+
declare function buildSessionMetadata(request: Request, extra?: Record<string, unknown>): Record<string, unknown>;
|
|
790
|
+
|
|
1132
791
|
/**
|
|
1133
|
-
*
|
|
1134
|
-
* cookie using a constant-time comparison to prevent timing attacks.
|
|
792
|
+
* Token family tracking for refresh token reuse detection.
|
|
1135
793
|
*
|
|
1136
|
-
*
|
|
1137
|
-
*
|
|
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.
|
|
1138
798
|
*
|
|
1139
|
-
*
|
|
1140
|
-
*
|
|
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
|
+
* ```
|
|
1141
819
|
*/
|
|
1142
|
-
|
|
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
|
+
}
|
|
1143
876
|
/**
|
|
1144
|
-
*
|
|
1145
|
-
* request against a list of trusted origins.
|
|
1146
|
-
*
|
|
1147
|
-
* Rules:
|
|
1148
|
-
* - If `Origin` is present and matches a trusted origin → valid.
|
|
1149
|
-
* - If `Origin` is `"null"` (opaque origin) → invalid.
|
|
1150
|
-
* - If `Origin` is absent, falls back to the `Referer` header.
|
|
1151
|
-
* - If neither header is present → result depends on `allowMissingOrigin`.
|
|
1152
|
-
*
|
|
1153
|
-
* @param request Incoming Web API `Request`.
|
|
1154
|
-
* @param trustedOrigins Array of allowed origins, e.g. `['https://app.example.com']`.
|
|
1155
|
-
* Trailing slashes are stripped before comparison.
|
|
1156
|
-
* @param allowMissingOrigin When `true`, requests without an `Origin` or
|
|
1157
|
-
* `Referer` header are considered valid (useful for
|
|
1158
|
-
* server-to-server calls). Defaults to `false`.
|
|
877
|
+
* Create a `TokenFamilyStore` backed by the TheAuth database.
|
|
1159
878
|
*/
|
|
1160
|
-
declare function
|
|
879
|
+
declare function createTokenFamilyStore(db: Database): TokenFamilyStore;
|
|
1161
880
|
|
|
1162
881
|
/**
|
|
1163
|
-
*
|
|
882
|
+
* Session refresh endpoint handler for TheAuth.
|
|
1164
883
|
*
|
|
1165
|
-
*
|
|
1166
|
-
*
|
|
1167
|
-
*
|
|
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.
|
|
1168
895
|
*
|
|
1169
896
|
* @example
|
|
1170
897
|
* ```typescript
|
|
1171
|
-
*
|
|
1172
|
-
*
|
|
1173
|
-
*
|
|
1174
|
-
*
|
|
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
|
+
* },
|
|
1175
907
|
* db,
|
|
1176
|
-
* );
|
|
1177
|
-
*
|
|
1178
|
-
* // On login
|
|
1179
|
-
* const { session, setCookieHeader } = await sessions.createSession(user.id);
|
|
1180
|
-
* return new Response(null, {
|
|
1181
|
-
* status: 302,
|
|
1182
|
-
* headers: { Location: '/dashboard', 'Set-Cookie': setCookieHeader },
|
|
1183
908
|
* });
|
|
1184
909
|
*
|
|
1185
|
-
* //
|
|
1186
|
-
*
|
|
1187
|
-
*
|
|
1188
|
-
*
|
|
1189
|
-
* // On logout
|
|
1190
|
-
* const deleteCookie = sessions.buildLogoutCookie();
|
|
1191
|
-
* return new Response(null, {
|
|
1192
|
-
* status: 302,
|
|
1193
|
-
* 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;
|
|
1194
914
|
* });
|
|
1195
915
|
* ```
|
|
1196
916
|
*/
|
|
1197
917
|
|
|
1198
|
-
interface
|
|
918
|
+
interface RefreshSessionConfig {
|
|
1199
919
|
/**
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
920
|
+
* Short-lived access token lifetime.
|
|
921
|
+
* Parsed duration string, e.g. `"15m"`.
|
|
922
|
+
* Defaults to `"15m"`.
|
|
1202
923
|
*/
|
|
1203
|
-
|
|
924
|
+
accessTokenTTL?: string;
|
|
1204
925
|
/**
|
|
1205
|
-
*
|
|
1206
|
-
*
|
|
926
|
+
* Long-lived refresh token lifetime.
|
|
927
|
+
* Parsed duration string, e.g. `"30d"`.
|
|
928
|
+
* Defaults to `"30d"`.
|
|
1207
929
|
*/
|
|
1208
|
-
|
|
930
|
+
refreshTokenTTL?: string;
|
|
1209
931
|
/**
|
|
1210
|
-
* When `true
|
|
1211
|
-
*
|
|
932
|
+
* When `true` (default), each use of a refresh token rotates it: the old
|
|
933
|
+
* token is invalidated and a new one is issued.
|
|
1212
934
|
*/
|
|
1213
|
-
|
|
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;
|
|
1214
958
|
}
|
|
1215
|
-
interface
|
|
1216
|
-
/**
|
|
1217
|
-
|
|
1218
|
-
/**
|
|
1219
|
-
|
|
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;
|
|
1220
966
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
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
|
+
};
|
|
1224
1129
|
/**
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
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.
|
|
1227
1134
|
*/
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
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
|
+
};
|
|
1231
1152
|
/**
|
|
1232
|
-
*
|
|
1233
|
-
*
|
|
1153
|
+
* Least-privilege analyzer.
|
|
1154
|
+
*
|
|
1155
|
+
* Compare agent permissions against actual audit log usage to surface
|
|
1156
|
+
* wildcards, unused grants, and over-permissioned identities.
|
|
1234
1157
|
*/
|
|
1235
|
-
|
|
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
|
+
};
|
|
1236
1167
|
/**
|
|
1237
|
-
*
|
|
1238
|
-
* verify it has not expired.
|
|
1168
|
+
* Human auth integration.
|
|
1239
1169
|
*
|
|
1240
|
-
*
|
|
1241
|
-
* request
|
|
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()`.
|
|
1242
1174
|
*
|
|
1243
|
-
* @
|
|
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
|
+
* ```
|
|
1244
1184
|
*/
|
|
1245
|
-
|
|
1185
|
+
auth: {
|
|
1186
|
+
resolveUser(request: Request): Promise<ResolvedUser | null>;
|
|
1187
|
+
session: SessionManager | null;
|
|
1188
|
+
};
|
|
1246
1189
|
/**
|
|
1247
|
-
*
|
|
1190
|
+
* Resolve a human user from an incoming HTTP request.
|
|
1248
1191
|
*
|
|
1249
|
-
*
|
|
1250
|
-
* Returns `null` when the session does not exist.
|
|
1192
|
+
* @deprecated Use `theauth.auth.resolveUser(request)` instead.
|
|
1251
1193
|
*/
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
} | null>;
|
|
1194
|
+
resolveUser(request: Request): Promise<ResolvedUser | null>;
|
|
1195
|
+
/** Direct database access for advanced usage */
|
|
1196
|
+
db: Database;
|
|
1256
1197
|
/**
|
|
1257
|
-
*
|
|
1258
|
-
*
|
|
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`.
|
|
1259
1203
|
*/
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
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
|
+
};
|
|
1263
1213
|
/**
|
|
1264
|
-
*
|
|
1214
|
+
* Agent execution budget policies.
|
|
1265
1215
|
*
|
|
1266
|
-
*
|
|
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.
|
|
1267
1219
|
*/
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
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
|
+
};
|
|
1271
1239
|
/**
|
|
1272
|
-
*
|
|
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.
|
|
1273
1244
|
*/
|
|
1274
|
-
|
|
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
|
+
};
|
|
1275
1261
|
/**
|
|
1276
|
-
*
|
|
1277
|
-
*
|
|
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.
|
|
1278
1266
|
*/
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
createdAt: Date;
|
|
1327
|
-
expiresAt: Date;
|
|
1328
|
-
metadata?: Record<string, unknown>;
|
|
1329
|
-
/** Human-readable device string extracted from User-Agent, e.g. "Chrome on macOS" */
|
|
1330
|
-
device?: string;
|
|
1331
|
-
/** IP address recorded at session creation */
|
|
1332
|
-
ip?: string;
|
|
1333
|
-
}
|
|
1334
|
-
interface MultiSessionModule {
|
|
1335
|
-
/** List all non-expired sessions for a user, newest first. */
|
|
1336
|
-
listSessions(userId: string): Promise<SessionInfo[]>;
|
|
1337
|
-
/** Revoke a single session by ID. */
|
|
1338
|
-
revokeSession(sessionId: string): Promise<void>;
|
|
1339
|
-
/** Revoke every session except the given one. Returns the count revoked. */
|
|
1340
|
-
revokeOtherSessions(userId: string, currentSessionId: string): Promise<number>;
|
|
1341
|
-
/** Return the count of active (non-expired) sessions for a user. */
|
|
1342
|
-
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
|
+
};
|
|
1276
|
+
/**
|
|
1277
|
+
* W3C Decentralized Identifiers (DID) for agents.
|
|
1278
|
+
*
|
|
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
|
+
* ```
|
|
1289
|
+
*/
|
|
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
|
+
};
|
|
1343
1314
|
/**
|
|
1344
|
-
*
|
|
1315
|
+
* Magic link (passwordless email) authentication.
|
|
1345
1316
|
*
|
|
1346
|
-
*
|
|
1347
|
-
*
|
|
1348
|
-
*
|
|
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
|
+
* ```
|
|
1349
1326
|
*/
|
|
1350
|
-
|
|
1351
|
-
}
|
|
1352
|
-
declare class MultiSessionLimitError extends Error {
|
|
1353
|
-
readonly code = "SESSION_LIMIT_REACHED";
|
|
1354
|
-
constructor(userId: string, max: number);
|
|
1355
|
-
}
|
|
1356
|
-
declare function createMultiSessionModule(config: MultiSessionConfig, db: Database, sessionManager: SessionManager): MultiSessionModule;
|
|
1357
|
-
/**
|
|
1358
|
-
* Build metadata to pass to `sessionManager.create()` that includes
|
|
1359
|
-
* device info extracted from the incoming request.
|
|
1360
|
-
*
|
|
1361
|
-
* @example
|
|
1362
|
-
* ```typescript
|
|
1363
|
-
* const meta = buildSessionMetadata(request, { role: 'admin' });
|
|
1364
|
-
* const { token } = await sessionManager.create(userId, meta);
|
|
1365
|
-
* ```
|
|
1366
|
-
*/
|
|
1367
|
-
declare function buildSessionMetadata(request: Request, extra?: Record<string, unknown>): Record<string, unknown>;
|
|
1368
|
-
|
|
1369
|
-
/**
|
|
1370
|
-
* Token family tracking for refresh token reuse detection.
|
|
1371
|
-
*
|
|
1372
|
-
* Each refresh token belongs to a "family" — a chain of rotations that all
|
|
1373
|
-
* originate from the same initial login. When `reuseDetection` is enabled,
|
|
1374
|
-
* presenting an already-used token from a family immediately revokes every
|
|
1375
|
-
* token in that family, because reuse indicates the token was stolen.
|
|
1376
|
-
*
|
|
1377
|
-
* The database table `kavach_refresh_token_families` stores:
|
|
1378
|
-
* - family-level metadata (userId, absolute expiry, revocation status)
|
|
1379
|
-
*
|
|
1380
|
-
* Each individual refresh token row in `kavach_refresh_tokens` links back to
|
|
1381
|
-
* its family via `familyId`.
|
|
1382
|
-
*
|
|
1383
|
-
* @example
|
|
1384
|
-
* ```typescript
|
|
1385
|
-
* const families = createTokenFamilyStore(db);
|
|
1386
|
-
*
|
|
1387
|
-
* // On login — create a new family and issue the first token
|
|
1388
|
-
* const family = await families.createFamily(userId, absoluteExpiresAt);
|
|
1389
|
-
* const token = await families.issueToken(family.id, refreshTokenTTL);
|
|
1390
|
-
*
|
|
1391
|
-
* // On refresh — consume the token (marks it used, issues a new one)
|
|
1392
|
-
* const result = await families.consumeToken(rawToken);
|
|
1393
|
-
* if (result.status === 'reuse') {
|
|
1394
|
-
* // Entire family revoked — force re-login
|
|
1395
|
-
* }
|
|
1396
|
-
* ```
|
|
1397
|
-
*/
|
|
1398
|
-
|
|
1399
|
-
interface TokenFamily {
|
|
1400
|
-
id: string;
|
|
1401
|
-
userId: string;
|
|
1402
|
-
/** Absolute expiry — no refresh can extend beyond this date. */
|
|
1403
|
-
absoluteExpiresAt: Date;
|
|
1404
|
-
revoked: boolean;
|
|
1405
|
-
createdAt: Date;
|
|
1406
|
-
}
|
|
1407
|
-
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. */
|
|
1408
|
-
interface ConsumeTokenResult {
|
|
1409
|
-
status: ConsumeTokenStatus;
|
|
1410
|
-
/** Populated when status is `"ok"`. */
|
|
1411
|
-
family?: TokenFamily;
|
|
1412
|
-
}
|
|
1413
|
-
interface TokenFamilyStore {
|
|
1327
|
+
magicLink: MagicLinkModule | null;
|
|
1414
1328
|
/**
|
|
1415
|
-
*
|
|
1416
|
-
*
|
|
1329
|
+
* Email OTP (one-time password) authentication.
|
|
1330
|
+
*
|
|
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
|
+
* ```
|
|
1417
1339
|
*/
|
|
1418
|
-
|
|
1340
|
+
emailOtp: EmailOtpModule | null;
|
|
1419
1341
|
/**
|
|
1420
|
-
*
|
|
1342
|
+
* TOTP two-factor authentication.
|
|
1421
1343
|
*
|
|
1422
|
-
*
|
|
1423
|
-
*
|
|
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
|
+
* ```
|
|
1424
1357
|
*/
|
|
1425
|
-
|
|
1426
|
-
rawToken: string;
|
|
1427
|
-
expiresAt: Date;
|
|
1428
|
-
}>;
|
|
1358
|
+
totp: TotpModule | null;
|
|
1429
1359
|
/**
|
|
1430
|
-
*
|
|
1360
|
+
* Passkey / WebAuthn authentication.
|
|
1431
1361
|
*
|
|
1432
|
-
*
|
|
1433
|
-
*
|
|
1434
|
-
*
|
|
1435
|
-
*
|
|
1436
|
-
*
|
|
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
|
+
* ```
|
|
1437
1379
|
*/
|
|
1438
|
-
|
|
1380
|
+
passkey: PasskeyModule | null;
|
|
1439
1381
|
/**
|
|
1440
|
-
*
|
|
1441
|
-
*
|
|
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
|
+
* ```
|
|
1442
1391
|
*/
|
|
1443
|
-
|
|
1392
|
+
org: OrgModule | null;
|
|
1444
1393
|
/**
|
|
1445
|
-
*
|
|
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
|
+
* ```
|
|
1446
1403
|
*/
|
|
1447
|
-
|
|
1404
|
+
sso: SsoModule | null;
|
|
1448
1405
|
/**
|
|
1449
|
-
*
|
|
1450
|
-
*
|
|
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
|
+
* ```
|
|
1451
1415
|
*/
|
|
1452
|
-
|
|
1453
|
-
}
|
|
1454
|
-
/**
|
|
1455
|
-
* Create a `TokenFamilyStore` backed by the TheAuth database.
|
|
1456
|
-
*/
|
|
1457
|
-
declare function createTokenFamilyStore(db: Database): TokenFamilyStore;
|
|
1458
|
-
|
|
1459
|
-
/**
|
|
1460
|
-
* Session refresh endpoint handler for TheAuth.
|
|
1461
|
-
*
|
|
1462
|
-
* Implements `POST /auth/refresh`:
|
|
1463
|
-
* 1. Extracts the refresh token from an httpOnly cookie or the request body.
|
|
1464
|
-
* 2. Validates the token (TTL, reuse detection, absolute timeout).
|
|
1465
|
-
* 3. Issues a new short-lived access token (signed JWT).
|
|
1466
|
-
* 4. Rotates the refresh token (one-time use — the old one is consumed).
|
|
1467
|
-
* 5. Records the rotation in the audit log.
|
|
1468
|
-
*
|
|
1469
|
-
* Token family tracking (via `createTokenFamilyStore`) provides reuse
|
|
1470
|
-
* detection: if an attacker uses a stolen refresh token after the legitimate
|
|
1471
|
-
* user has already rotated it, the entire family is revoked and both parties
|
|
1472
|
-
* are forced to re-authenticate.
|
|
1473
|
-
*
|
|
1474
|
-
* @example
|
|
1475
|
-
* ```typescript
|
|
1476
|
-
* const refresher = createSessionRefresher({
|
|
1477
|
-
* secret: process.env.SESSION_SECRET,
|
|
1478
|
-
* session: {
|
|
1479
|
-
* accessTokenTTL: "15m",
|
|
1480
|
-
* refreshTokenTTL: "30d",
|
|
1481
|
-
* absoluteTimeout: "90d",
|
|
1482
|
-
* rotateRefreshTokens: true,
|
|
1483
|
-
* reuseDetection: true,
|
|
1484
|
-
* },
|
|
1485
|
-
* db,
|
|
1486
|
-
* });
|
|
1487
|
-
*
|
|
1488
|
-
* // In your Hono / Express router:
|
|
1489
|
-
* app.post('/auth/refresh', async (ctx) => {
|
|
1490
|
-
* const result = await refresher.handleRequest(ctx.req.raw);
|
|
1491
|
-
* return result.response;
|
|
1492
|
-
* });
|
|
1493
|
-
* ```
|
|
1494
|
-
*/
|
|
1495
|
-
|
|
1496
|
-
interface RefreshSessionConfig {
|
|
1416
|
+
admin: AdminModule | null;
|
|
1497
1417
|
/**
|
|
1498
|
-
*
|
|
1499
|
-
*
|
|
1500
|
-
*
|
|
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
|
+
* ```
|
|
1501
1440
|
*/
|
|
1502
|
-
|
|
1441
|
+
username: UsernameAuthModule | null;
|
|
1503
1442
|
/**
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
1506
|
-
*
|
|
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
|
+
* ```
|
|
1507
1458
|
*/
|
|
1508
|
-
|
|
1459
|
+
passwordReset: PasswordResetModule | null;
|
|
1509
1460
|
/**
|
|
1510
|
-
*
|
|
1511
|
-
*
|
|
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
|
+
* ```
|
|
1512
1476
|
*/
|
|
1513
|
-
|
|
1477
|
+
emailVerification: EmailVerificationModule | null;
|
|
1514
1478
|
/**
|
|
1515
|
-
*
|
|
1516
|
-
*
|
|
1517
|
-
*
|
|
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.).
|
|
1518
1483
|
*/
|
|
1519
|
-
|
|
1484
|
+
oneTimeTokens: OneTimeTokenModule;
|
|
1520
1485
|
/**
|
|
1521
|
-
*
|
|
1522
|
-
*
|
|
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
|
+
* ```
|
|
1523
1497
|
*/
|
|
1524
|
-
|
|
1498
|
+
sessionFreshness: SessionFreshnessModule;
|
|
1525
1499
|
/**
|
|
1526
|
-
*
|
|
1527
|
-
*
|
|
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
|
+
* ```
|
|
1528
1510
|
*/
|
|
1529
|
-
|
|
1511
|
+
phone: PhoneAuthModule | null;
|
|
1530
1512
|
/**
|
|
1531
|
-
*
|
|
1532
|
-
*
|
|
1533
|
-
*
|
|
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
|
+
* ```
|
|
1534
1522
|
*/
|
|
1535
|
-
|
|
1536
|
-
}
|
|
1537
|
-
interface SessionRefresherConfig {
|
|
1538
|
-
/** Signing secret — at least 32 characters. */
|
|
1539
|
-
secret: string;
|
|
1540
|
-
/** Refresh / rotation settings. */
|
|
1541
|
-
session?: RefreshSessionConfig;
|
|
1542
|
-
/** Drizzle database instance. */
|
|
1543
|
-
db: Database;
|
|
1544
|
-
}
|
|
1545
|
-
/** The payload embedded in the short-lived access token JWT. */
|
|
1546
|
-
interface AccessTokenPayload {
|
|
1547
|
-
/** User ID. */
|
|
1548
|
-
sub: string;
|
|
1549
|
-
/** Token family ID — used for server-side token binding. */
|
|
1550
|
-
familyId: string;
|
|
1551
|
-
/** Token type discriminator. */
|
|
1552
|
-
type: "access";
|
|
1553
|
-
}
|
|
1554
|
-
interface RefreshResult {
|
|
1555
|
-
/** Signed access token JWT. */
|
|
1556
|
-
accessToken: string;
|
|
1557
|
-
/** Raw opaque refresh token (only returned once — store in httpOnly cookie). */
|
|
1558
|
-
refreshToken: string;
|
|
1559
|
-
/** Expiry date of the new access token. */
|
|
1560
|
-
accessTokenExpiresAt: Date;
|
|
1561
|
-
/** Expiry date of the new refresh token. */
|
|
1562
|
-
refreshTokenExpiresAt: Date;
|
|
1563
|
-
/** The token family these tokens belong to. */
|
|
1564
|
-
family: TokenFamily;
|
|
1565
|
-
}
|
|
1566
|
-
type RefreshError = "token_missing" | "token_not_found" | "token_expired" | "token_reuse" | "family_revoked" | "absolute_timeout";
|
|
1567
|
-
interface RefreshHandleResult {
|
|
1568
|
-
/** HTTP Response ready to return to the caller. */
|
|
1569
|
-
response: Response;
|
|
1570
|
-
/** Populated on success. */
|
|
1571
|
-
result?: RefreshResult;
|
|
1572
|
-
/** Populated on failure. */
|
|
1573
|
-
error?: RefreshError;
|
|
1574
|
-
}
|
|
1575
|
-
interface SessionRefresher {
|
|
1523
|
+
captcha: CaptchaModule | null;
|
|
1576
1524
|
/**
|
|
1577
|
-
*
|
|
1525
|
+
* Webhook system.
|
|
1578
1526
|
*
|
|
1579
|
-
*
|
|
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
|
+
* ```
|
|
1580
1533
|
*/
|
|
1581
|
-
|
|
1534
|
+
webhooks: WebhookModule$1 | null;
|
|
1582
1535
|
/**
|
|
1583
|
-
*
|
|
1536
|
+
* Redirect chain manager.
|
|
1584
1537
|
*
|
|
1585
|
-
*
|
|
1586
|
-
*
|
|
1587
|
-
*
|
|
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
|
+
* ```
|
|
1588
1554
|
*/
|
|
1589
|
-
|
|
1555
|
+
redirects: RedirectChainManager;
|
|
1590
1556
|
/**
|
|
1591
|
-
*
|
|
1557
|
+
* Unified policy engine.
|
|
1592
1558
|
*
|
|
1593
|
-
*
|
|
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
|
+
* ```
|
|
1594
1578
|
*/
|
|
1595
|
-
|
|
1579
|
+
policy: {
|
|
1580
|
+
evaluate: (input: EvaluateInput) => Promise<PolicyDecision>;
|
|
1581
|
+
invalidate: (scope: InvalidateScope) => void;
|
|
1582
|
+
stats: () => PolicyCacheStats;
|
|
1583
|
+
};
|
|
1596
1584
|
/**
|
|
1597
|
-
*
|
|
1598
|
-
*
|
|
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
|
+
* ```
|
|
1599
1600
|
*/
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
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>>;
|
|
1607
1613
|
/**
|
|
1608
|
-
*
|
|
1614
|
+
* @deprecated Use `createTheAuth` instead. Will be removed in a future major version.
|
|
1609
1615
|
*/
|
|
1610
|
-
declare
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
slug: string;
|
|
1616
|
-
settings: TenantSettings;
|
|
1617
|
-
status: "active" | "suspended";
|
|
1618
|
-
createdAt: Date;
|
|
1619
|
-
updatedAt: Date;
|
|
1620
|
-
}
|
|
1621
|
-
interface TenantSettings {
|
|
1622
|
-
maxAgents?: number;
|
|
1623
|
-
maxDelegationDepth?: number;
|
|
1624
|
-
auditRetentionDays?: number;
|
|
1625
|
-
allowedAgentTypes?: string[];
|
|
1626
|
-
}
|
|
1627
|
-
interface CreateTenantInput {
|
|
1628
|
-
name: string;
|
|
1629
|
-
slug: string;
|
|
1630
|
-
settings?: Partial<TenantSettings>;
|
|
1631
|
-
}
|
|
1632
|
-
declare function createTenantModule(db: Database): {
|
|
1633
|
-
create: (input: CreateTenantInput) => Promise<Tenant>;
|
|
1634
|
-
get: (tenantId: string) => Promise<Tenant | null>;
|
|
1635
|
-
getBySlug: (slug: string) => Promise<Tenant | null>;
|
|
1636
|
-
list: () => Promise<Tenant[]>;
|
|
1637
|
-
update: (tenantId: string, updates: Partial<CreateTenantInput>) => Promise<Tenant>;
|
|
1638
|
-
suspend: (tenantId: string) => Promise<void>;
|
|
1639
|
-
activate: (tenantId: string) => Promise<void>;
|
|
1640
|
-
};
|
|
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;
|
|
1641
1621
|
|
|
1642
1622
|
interface TrustScore {
|
|
1643
1623
|
agentId: string;
|
|
@@ -1724,4 +1704,4 @@ declare function createWebhookModule(config: WebhookConfig): WebhookModule;
|
|
|
1724
1704
|
*/
|
|
1725
1705
|
declare function verifyWebhookSignature(secret: string, rawBody: string, signature: string): Promise<boolean>;
|
|
1726
1706
|
|
|
1727
|
-
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, DidDocument, DidKeyPair, type DidModule, DidWebConfig, EmailOtpModule, type EmailTemplate, type EmailTemplateConfig, type EmailTemplateName, type EmailTemplates, EmailVerificationModule, EndpointContext, type I18nConfig, type I18nModule,
|
|
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 };
|