@adonis-agora/authkit-server 1.0.0-rc.1 → 1.0.0-rc.10

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.
Files changed (163) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +4 -5
  3. package/build/commands/agora_doctor.d.ts +22 -0
  4. package/build/commands/agora_doctor.js +109 -0
  5. package/build/commands/clients_create.d.ts +4 -0
  6. package/build/commands/clients_create.js +97 -0
  7. package/build/commands/commands.json +78 -0
  8. package/build/commands/doctor.js +8 -74
  9. package/build/host/views/account/apps.edge +1 -5
  10. package/build/host/views/account/extension.edge +77 -0
  11. package/build/host/views/account/mfa.edge +2 -0
  12. package/build/host/views/account/partials/extension_actions.edge +14 -0
  13. package/build/host/views/account/partials/extension_block.edge +197 -0
  14. package/build/host/views/account/partials/extension_value.edge +8 -0
  15. package/build/host/views/account/partials/nav.edge +14 -0
  16. package/build/host/views/account/security.edge +1 -5
  17. package/build/host/views/account/tokens.edge +2 -2
  18. package/build/host/views/agents/consent.edge +11 -2
  19. package/build/host/views/agents/done.edge +1 -1
  20. package/build/host/views/partials/styles.edge +1 -1
  21. package/build/index.d.ts +12 -12
  22. package/build/index.js +7 -9
  23. package/build/providers/authkit_server_provider.js +28 -8
  24. package/build/src/account/extension.d.ts +10 -0
  25. package/build/src/account/extension.js +9 -0
  26. package/build/src/account/http.d.ts +77 -0
  27. package/build/src/account/http.js +381 -0
  28. package/build/src/account/mount.d.ts +40 -0
  29. package/build/src/account/mount.js +171 -0
  30. package/build/src/account/registry.d.ts +41 -0
  31. package/build/src/account/registry.js +81 -0
  32. package/build/src/account/remote.d.ts +72 -0
  33. package/build/src/account/remote.js +406 -0
  34. package/build/src/account/runtime.d.ts +289 -0
  35. package/build/src/account/runtime.js +641 -0
  36. package/build/src/accounts/account_store.d.ts +6 -0
  37. package/build/src/accounts/lucid_store/organizations.js +6 -0
  38. package/build/src/agents/config.d.ts +9 -13
  39. package/build/src/agents/config.js +17 -11
  40. package/build/src/agents/delegation_service.js +3 -3
  41. package/build/src/agents/delegation_store.d.ts +3 -2
  42. package/build/src/agents/delegation_store.js +6 -5
  43. package/build/src/agents/extension.d.ts +261 -0
  44. package/build/src/agents/extension.js +40 -0
  45. package/build/src/agents/middleware.js +1 -1
  46. package/build/src/agents/protocol.d.ts +4 -4
  47. package/build/src/agents/registry_store.d.ts +3 -2
  48. package/build/src/agents/registry_store.js +1 -1
  49. package/build/src/agents/runtime.d.ts +26 -7
  50. package/build/src/agents/runtime.js +110 -75
  51. package/build/src/audit/audit_sink.d.ts +1 -1
  52. package/build/src/audit/audit_sink.js +10 -1
  53. package/build/src/console_switcher.d.ts +132 -0
  54. package/build/src/console_switcher.js +206 -0
  55. package/build/src/define_config.d.ts +34 -12
  56. package/build/src/define_config.js +15 -7
  57. package/build/src/dev_tools/contract.d.ts +72 -0
  58. package/build/src/dev_tools/contract.js +10 -0
  59. package/build/src/dev_tools/gate.d.ts +17 -0
  60. package/build/src/dev_tools/gate.js +69 -0
  61. package/build/src/dev_tools/register.d.ts +11 -0
  62. package/build/src/dev_tools/register.js +25 -0
  63. package/build/src/dev_tools/tools.d.ts +24 -0
  64. package/build/src/dev_tools/tools.js +384 -0
  65. package/build/src/doctor/agora_checks.d.ts +15 -0
  66. package/build/src/doctor/agora_checks.js +150 -0
  67. package/build/src/doctor/agora_doctor.d.ts +115 -0
  68. package/build/src/doctor/agora_doctor.js +692 -0
  69. package/build/src/doctor/doctor_input.d.ts +27 -0
  70. package/build/src/doctor/doctor_input.js +86 -0
  71. package/build/src/doctor/index.d.ts +5 -0
  72. package/build/src/doctor/index.js +4 -0
  73. package/build/src/host/access_token_verifier.js +7 -0
  74. package/build/src/host/account_api/account_api_controller.js +8 -6
  75. package/build/src/host/account_session_sign_in.d.ts +12 -0
  76. package/build/src/host/account_session_sign_in.js +19 -0
  77. package/build/src/host/admin_api/admin_users_service.d.ts +5 -2
  78. package/build/src/host/admin_api/api_clients_controller.d.ts +37 -0
  79. package/build/src/host/admin_api/api_clients_controller.js +31 -1
  80. package/build/src/host/admin_api/dto.d.ts +3 -1
  81. package/build/src/host/admin_api/dto.js +2 -0
  82. package/build/src/host/admin_authorize.d.ts +8 -0
  83. package/build/src/host/admin_authorize.js +25 -0
  84. package/build/src/host/admin_clients_service.d.ts +20 -0
  85. package/build/src/host/admin_clients_service.js +55 -0
  86. package/build/src/host/admin_console/admin_console_entry.d.ts +14 -0
  87. package/build/src/host/admin_console/admin_console_entry.js +80 -0
  88. package/build/src/host/admin_console/admin_shell_controller.js +8 -0
  89. package/build/src/host/admin_console/console_clients_controller.d.ts +41 -0
  90. package/build/src/host/admin_console/console_clients_controller.js +34 -1
  91. package/build/src/host/admin_console/console_personal_agents_controller.d.ts +1 -6
  92. package/build/src/host/admin_console/console_personal_agents_controller.js +50 -30
  93. package/build/src/host/admin_console/console_switcher_controller.d.ts +11 -0
  94. package/build/src/host/admin_console/console_switcher_controller.js +23 -0
  95. package/build/src/host/admin_sessions_service.js +8 -5
  96. package/build/src/host/admin_validators.d.ts +29 -0
  97. package/build/src/host/admin_validators.js +30 -0
  98. package/build/src/host/auth_host_config.d.ts +9 -2
  99. package/build/src/host/controllers/account_apps_controller.js +15 -11
  100. package/build/src/host/csrf.d.ts +3 -3
  101. package/build/src/host/csrf.js +3 -13
  102. package/build/src/host/default_mailer.d.ts +11 -6
  103. package/build/src/host/default_mailer.js +16 -12
  104. package/build/src/host/i18n.d.ts +41 -14
  105. package/build/src/host/i18n.js +55 -13
  106. package/build/src/host/rate_limit.d.ts +8 -0
  107. package/build/src/host/rate_limit.js +9 -0
  108. package/build/src/host/register_auth_host.d.ts +14 -0
  109. package/build/src/host/register_auth_host.js +167 -106
  110. package/build/src/host/renderers/edge_renderer.js +5 -0
  111. package/build/src/host/renderers/inertia_renderer.js +7 -1
  112. package/build/src/host/screen_props.d.ts +39 -8
  113. package/build/src/host/ui-dist/assets/index-Dq3dJVBv.js +67 -0
  114. package/build/src/host/ui-dist/assets/{index-DTSmD4RU.css → index-WNIyCEPA.css} +1 -1
  115. package/build/src/host/ui-dist/index.html +2 -2
  116. package/build/src/provider/build_provider.js +37 -6
  117. package/build/src/provider/oidc_service.d.ts +1 -1
  118. package/build/src/provider/oidc_service.js +1 -1
  119. package/build/src/schema/ensure.d.ts +14 -0
  120. package/build/src/schema/ensure.js +43 -150
  121. package/build/src/service_tenants/client_metadata.d.ts +39 -0
  122. package/build/src/service_tenants/client_metadata.js +80 -0
  123. package/build/src/service_tenants/config.d.ts +44 -0
  124. package/build/src/service_tenants/config.js +44 -0
  125. package/build/src/service_tenants/provider_hooks.d.ts +52 -0
  126. package/build/src/service_tenants/provider_hooks.js +124 -0
  127. package/build/src/service_tenants/tenant_verifier.d.ts +73 -0
  128. package/build/src/service_tenants/tenant_verifier.js +104 -0
  129. package/build/src/tenancy/tenant_labels.d.ts +30 -0
  130. package/build/src/tenancy/tenant_labels.js +64 -0
  131. package/build/types.d.ts +3 -1
  132. package/package.json +9 -6
  133. package/build/src/agents/poppy/client_registry.d.ts +0 -50
  134. package/build/src/agents/poppy/client_registry.js +0 -260
  135. package/build/src/agents/poppy/config.d.ts +0 -396
  136. package/build/src/agents/poppy/config.js +0 -228
  137. package/build/src/agents/poppy/dpop.d.ts +0 -61
  138. package/build/src/agents/poppy/dpop.js +0 -158
  139. package/build/src/agents/poppy/email_code_sign_in.d.ts +0 -27
  140. package/build/src/agents/poppy/email_code_sign_in.js +0 -140
  141. package/build/src/agents/poppy/errors.d.ts +0 -25
  142. package/build/src/agents/poppy/errors.js +0 -25
  143. package/build/src/agents/poppy/replay.d.ts +0 -25
  144. package/build/src/agents/poppy/replay.js +0 -106
  145. package/build/src/agents/poppy/resource.d.ts +0 -100
  146. package/build/src/agents/poppy/resource.js +0 -129
  147. package/build/src/agents/poppy/safe_fetch.d.ts +0 -48
  148. package/build/src/agents/poppy/safe_fetch.js +0 -262
  149. package/build/src/agents/poppy/service.d.ts +0 -293
  150. package/build/src/agents/poppy/service.js +0 -1458
  151. package/build/src/agents/poppy/session_jwt.d.ts +0 -30
  152. package/build/src/agents/poppy/session_jwt.js +0 -133
  153. package/build/src/agents/poppy/store.d.ts +0 -106
  154. package/build/src/agents/poppy/store.js +0 -261
  155. package/build/src/agents/poppy/web_session.d.ts +0 -39
  156. package/build/src/agents/poppy/web_session.js +0 -122
  157. package/build/src/host/controllers/poppy_consent_controller.d.ts +0 -19
  158. package/build/src/host/controllers/poppy_consent_controller.js +0 -199
  159. package/build/src/host/controllers/poppy_controller.d.ts +0 -33
  160. package/build/src/host/controllers/poppy_controller.js +0 -219
  161. package/build/src/host/poppy_session_key.d.ts +0 -9
  162. package/build/src/host/poppy_session_key.js +0 -9
  163. package/build/src/host/ui-dist/assets/index-D0EIeyKK.js +0 -67
@@ -1,5 +1,6 @@
1
1
  import type { AccessTokenFormat, AccessTokensConfig, JwksConfig, KeystoreStoreConfig, ObservabilityConfig, TtlConfig } from '@adonis-agora/authkit-core';
2
2
  import type { HttpContext } from '@adonisjs/core/http';
3
+ import type { AccountConsoleConfig } from './account/runtime.js';
3
4
  import type { AccountStore, AuthAccount } from './accounts/account_store.js';
4
5
  import { type AdapterFactory, adapters, type OidcAdapterClass } from './adapters/factory.js';
5
6
  import { type PersonalAgentsConfigInput, type ResolvedPersonalAgentsConfig } from './agents/config.js';
@@ -22,6 +23,7 @@ import type { WhatsappCodeSenderBinding } from './host/whatsapp_code_sender.js';
22
23
  import { type McpOAuthConfigInput, type ResolvedMcpOAuthConfig } from './mcp/mcp_oauth.js';
23
24
  import type { PatStore } from './pat/pat_store.js';
24
25
  import { type RedirectUriPolicy, type ResolvedRedirectUriPolicy, type ValidateRegistrationHook } from './provider/registration_policy.js';
26
+ import { type ResolvedServiceTenantsConfig, type ServiceTenantsConfigInput } from './service_tenants/config.js';
25
27
  export type { AuthAccount };
26
28
  export { adapters };
27
29
  export type AuthHostRenderer = (ctx: HttpContext, view: string, props: Record<string, unknown>) => unknown;
@@ -112,18 +114,6 @@ export interface MailHooks {
112
114
  email: string;
113
115
  sudoUrl: string;
114
116
  }) => Promise<void>;
115
- /**
116
- * Código do Mediated Sign-In pronto do Poppy (`poppyEmailCodeSignIn`): um personal
117
- * agent quer entrar na conta e a pessoa precisa dar o código a ele. Sem o hook, o
118
- * host-kit envia pelo mailer default, com branding e i18n.
119
- */
120
- onPoppySignInCode?: (data: {
121
- email: string;
122
- code: string;
123
- /** Nome do agente (metadata dele, ou o host do `client_id`). */
124
- agentName: string;
125
- expiresInMinutes: number;
126
- }) => Promise<void>;
127
117
  /**
128
118
  * Disparado num login bem-sucedido a partir de um IP NOVO para a conta (nenhum
129
119
  * `login.success` anterior desse IP no audit sink), quando `notifications.newLoginEmail`
@@ -322,6 +312,11 @@ export interface ResolvedRateLimitConfig {
322
312
  * force ANTES do lockout por interaction (contador persistido no slot do código).
323
313
  */
324
314
  otpLogin: RateLimitBucket;
315
+ /**
316
+ * Bucket das actions das páginas de extension do console de conta
317
+ * (`POST /account/<página>/actions/*`), keyed pela CONTA. Default 30/min.
318
+ */
319
+ accountActions?: RateLimitBucket;
325
320
  store?: string;
326
321
  }
327
322
  export declare function resolveRateLimit(input?: RateLimitConfigInput): ResolvedRateLimitConfig;
@@ -1125,6 +1120,19 @@ export interface AuthServerConfigInput {
1125
1120
  * `resources` mapeia resource indicators (RFC 8707) para audiences/scopes/formato/TTL por API.
1126
1121
  */
1127
1122
  accessTokens?: AccessTokensConfig;
1123
+ /**
1124
+ * Service tenants: confidential `client_credentials` clients that act as a partition of
1125
+ * a resource server (e.g. a durable control plane). `resources` lists the resource
1126
+ * indicators (RFC 8707) that issue their JWT access tokens (RFC 9068), each with an
1127
+ * optional `expiresIn` (seconds, default 600), `audience` and `scopes`:
1128
+ *
1129
+ * ```ts
1130
+ * serviceTenants: { resources: { 'urn:agora:durable': { expiresIn: 600 } } }
1131
+ * ```
1132
+ *
1133
+ * Turns on the `client_credentials` grant. Default: off.
1134
+ */
1135
+ serviceTenants?: ServiceTenantsConfigInput;
1128
1136
  /**
1129
1137
  * Login OAuth de clientes MCP (Claude Code, Claude, ChatGPT, VS Code, Cursor): `true` liga o
1130
1138
  * registro dinâmico restrito aos redirects deles, o refresh token desses clientes e os
@@ -1249,6 +1257,16 @@ export interface AuthServerConfigInput {
1249
1257
  accountSession?: {
1250
1258
  acceptIdpSession?: boolean;
1251
1259
  };
1260
+ /**
1261
+ * Account console extensions: the pages other packages add to `/account/*`.
1262
+ *
1263
+ * - `subject(account, { activeOrg, tenant })`: who the account is in the app (default
1264
+ * `{ type: 'User', id: account.id }`); every extension receives it as `ctx.subject`.
1265
+ * - `extensions`: turn off, rename or reorder pages, by extension id
1266
+ * (`{ payments: { pages: { 'payments.invoices': { segment: 'faturas' } } } }`).
1267
+ * - `loadTimeoutMs`: budget of one page's `load()` (default 5000).
1268
+ */
1269
+ accountConsole?: AccountConsoleConfig;
1252
1270
  }
1253
1271
  export interface ResolvedServerConfig {
1254
1272
  customLoginMethods?: CustomLoginMethods;
@@ -1367,6 +1385,8 @@ export interface ResolvedServerConfig {
1367
1385
  registration: ResolvedRegistrationConfig;
1368
1386
  /** Access Tokens resolvido (RFC 9068; default opaque). */
1369
1387
  accessTokens: ResolvedAccessTokensConfig;
1388
+ /** Service tenants (always present; `enabled: false` when no resource is declared). */
1389
+ serviceTenants: ResolvedServiceTenantsConfig;
1370
1390
  mcp: ResolvedMcpOAuthConfig;
1371
1391
  /** Console admin resolvido (sempre presente; default desligado). */
1372
1392
  admin: ResolvedAdminConfig;
@@ -1409,6 +1429,8 @@ export interface ResolvedServerConfig {
1409
1429
  accountSession: {
1410
1430
  acceptIdpSession: boolean;
1411
1431
  };
1432
+ /** Account console extensions. Ver {@link AuthServerConfigInput.accountConsole}. */
1433
+ accountConsole?: AccountConsoleConfig;
1412
1434
  }
1413
1435
  export declare function toSeconds(value: string | number | undefined, fallback: number): number;
1414
1436
  /**
@@ -6,7 +6,7 @@ import { composeAuditSink, resolveEvents } from './events/dispatcher.js';
6
6
  import { resolveBotProtection, } from './host/bot_protection.js';
7
7
  import { resolveBranding } from './host/branding.js';
8
8
  import { deriveLockedRouteOptions, deriveLockedSettingKeys, } from './host/config_locks.js';
9
- import { resolveMessages } from './host/i18n.js';
9
+ import { registerExtensionMessages, resolveMessages, } from './host/i18n.js';
10
10
  import { resolveOtpLoginConfig, } from './host/otp_login.js';
11
11
  import { edgeRenderer } from './host/renderers/edge_renderer.js';
12
12
  import { warnUnsatisfiableSudoConfig } from './host/sudo/satisfiability.js';
@@ -17,6 +17,7 @@ import { loadEncryptionService } from './keys/keystore_crypto.js';
17
17
  import { KeystoreManager, resolveKeystoreVault } from './keys/keystore_manager.js';
18
18
  import { mcpClientRegistration, resolveMcpOAuth, } from './mcp/mcp_oauth.js';
19
19
  import { OPEN_REGISTRATION_REDIRECT_POLICY, resolveRedirectUriPolicy, } from './provider/registration_policy.js';
20
+ import { resolveServiceTenants, } from './service_tenants/config.js';
20
21
  export { adapters };
21
22
  const RATE_LIMIT_DEFAULTS = {
22
23
  login: { points: 10, duration: '1 min' },
@@ -26,6 +27,8 @@ const RATE_LIMIT_DEFAULTS = {
26
27
  sudo: { points: 10, duration: '1 min' },
27
28
  // Mais apertado que o login — verificação de código adivinhável.
28
29
  otpLogin: { points: 5, duration: '1 min' },
30
+ // Actions das extensions do console de conta, por conta.
31
+ accountActions: { points: 30, duration: '1 min' },
29
32
  };
30
33
  export function resolveRateLimit(input) {
31
34
  const enabled = input?.enabled ?? true;
@@ -36,6 +39,7 @@ export function resolveRateLimit(input) {
36
39
  adminIp: RATE_LIMIT_DEFAULTS.adminIp,
37
40
  sudo: RATE_LIMIT_DEFAULTS.sudo,
38
41
  otpLogin: RATE_LIMIT_DEFAULTS.otpLogin,
42
+ accountActions: RATE_LIMIT_DEFAULTS.accountActions,
39
43
  store: input?.store,
40
44
  };
41
45
  }
@@ -343,7 +347,7 @@ export function defineConfig(config) {
343
347
  }
344
348
  // Personal agents com delegação assinam tokens e recibos com este keystore,
345
349
  // e o PACT só admite ES256/RS256 — falha no boot, não na primeira troca de token.
346
- const personalAgents = resolvePersonalAgentsConfig(config.personalAgents);
350
+ const personalAgents = resolvePersonalAgentsConfig(config.personalAgents, config.issuer);
347
351
  if (personalAgents?.delegation)
348
352
  assertDelegationSigningKey(jwks);
349
353
  // Debaixo do mountPath, a rota curinga do oidc-provider (`${mount}/*`)
@@ -355,11 +359,13 @@ export function defineConfig(config) {
355
359
  (personalAgents.prefix === oidcMount || personalAgents.prefix.startsWith(`${oidcMount}/`))) {
356
360
  throw new Error(`authkit: personalAgents.prefix "${personalAgents.prefix}" não pode ficar debaixo do mountPath do OIDC ("${oidcMount}").`);
357
361
  }
358
- const poppyPrefix = personalAgents?.poppy?.prefix;
359
- if (poppyPrefix &&
360
- oidcMount &&
361
- (poppyPrefix === oidcMount || poppyPrefix.startsWith(`${oidcMount}/`))) {
362
- throw new Error(`authkit: personalAgents.poppy.prefix "${poppyPrefix}" não pode ficar debaixo do mountPath do OIDC ("${oidcMount}").`);
362
+ for (const extension of personalAgents?.extensions ?? []) {
363
+ if (extension.messages)
364
+ registerExtensionMessages(extension.messages);
365
+ if (oidcMount &&
366
+ (extension.prefix === oidcMount || extension.prefix.startsWith(`${oidcMount}/`))) {
367
+ throw new Error(`authkit: o prefixo "${extension.prefix}" de personalAgents.extensions "${extension.id}" não pode ficar debaixo do mountPath do OIDC ("${oidcMount}").`);
368
+ }
363
369
  }
364
370
  // BACKSTOP DE SUDO. Um host cujo `sudo.methods` não tem um único método
365
371
  // satisfazível por conta sem senha fica bricado para TODA operação sob
@@ -473,6 +479,7 @@ export function defineConfig(config) {
473
479
  : undefined,
474
480
  registration: resolveRegistration(config.registration),
475
481
  accessTokens: resolveAccessTokens(config.issuer, config.accessTokens),
482
+ serviceTenants: resolveServiceTenants(config.serviceTenants, config.accessTokens?.resources),
476
483
  mcp: resolveMcpOAuth(config.mcp),
477
484
  admin: resolveAdmin(config.admin),
478
485
  adminApi: resolveAdminApi(config.adminApi),
@@ -498,6 +505,7 @@ export function defineConfig(config) {
498
505
  // Opt-in: ausente = authkit nunca toca `ctx.auth` (comportamento de sempre).
499
506
  adonisAuth: config.adonisAuth,
500
507
  accountSession: { acceptIdpSession: config.accountSession?.acceptIdpSession !== false },
508
+ accountConsole: config.accountConsole,
501
509
  };
502
510
  });
503
511
  }
@@ -0,0 +1,72 @@
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ /**
3
+ * The Agora dev-tools registration contract, version 1, declared here STRUCTURALLY.
4
+ *
5
+ * `@adonis-agora/agent`'s `mcp_provider` binds a hub at `'agora.devTools'` in its `register()`; every
6
+ * lib with a console registers its developer tools into it from its own `boot()`, and the agent
7
+ * serves them all on one MCP endpoint (`/mcp/agora`). authkit never imports the agent: the only
8
+ * coupling is the binding name and these shapes.
9
+ */
10
+ /** The container binding the hub lives at. */
11
+ export declare const DEV_TOOLS_BINDING = "agora.devTools";
12
+ /** The hub a lib registers into. */
13
+ export interface DevToolsHub {
14
+ readonly version: number;
15
+ register(lib: DevToolsLib): void;
16
+ }
17
+ /** One lib's tools and the gate that decides who may use them. */
18
+ export interface DevToolsLib {
19
+ lib: string;
20
+ title: string;
21
+ authorize(ctx: HttpContext): Promise<DevToolsDecision>;
22
+ tools: DevTool[];
23
+ }
24
+ /** What `authorize` answers. */
25
+ export type DevToolsDecision = {
26
+ allowed: true;
27
+ } | {
28
+ allowed: false;
29
+ reason: 'unauthenticated' | 'forbidden';
30
+ redirectTo?: string;
31
+ error?: unknown;
32
+ };
33
+ /** One developer tool. */
34
+ export interface DevTool {
35
+ /** `authkit_<verb>_<noun>`. */
36
+ name: string;
37
+ kind: 'read' | 'action';
38
+ description: string;
39
+ input: DevToolInputSchema;
40
+ destructive?: boolean;
41
+ available?(): boolean | Promise<boolean>;
42
+ run(input: Record<string, unknown>, call: DevToolCall): Promise<unknown>;
43
+ }
44
+ /** What a tool's `run` receives besides its input. */
45
+ export interface DevToolCall {
46
+ ctx: HttpContext;
47
+ caller: {
48
+ id: string;
49
+ via: 'token' | 'session' | 'open';
50
+ };
51
+ limits: {
52
+ maxRows: number;
53
+ maxBytes: number;
54
+ };
55
+ }
56
+ /** One property of a {@link DevToolInputSchema}. */
57
+ export interface DevToolInputProperty {
58
+ type: 'string' | 'number' | 'integer' | 'boolean' | 'array';
59
+ description?: string;
60
+ enum?: readonly string[];
61
+ items?: {
62
+ type: 'string';
63
+ };
64
+ minimum?: number;
65
+ maximum?: number;
66
+ }
67
+ /** An object of scalar / enum / array-of-string properties. */
68
+ export interface DevToolInputSchema {
69
+ type: 'object';
70
+ properties: Record<string, DevToolInputProperty>;
71
+ required?: string[];
72
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The Agora dev-tools registration contract, version 1, declared here STRUCTURALLY.
3
+ *
4
+ * `@adonis-agora/agent`'s `mcp_provider` binds a hub at `'agora.devTools'` in its `register()`; every
5
+ * lib with a console registers its developer tools into it from its own `boot()`, and the agent
6
+ * serves them all on one MCP endpoint (`/mcp/agora`). authkit never imports the agent: the only
7
+ * coupling is the binding name and these shapes.
8
+ */
9
+ /** The container binding the hub lives at. */
10
+ export const DEV_TOOLS_BINDING = 'agora.devTools';
@@ -0,0 +1,17 @@
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ import type { DevToolsDecision } from './contract.js';
3
+ /** Options for {@link authkitDevToolsAuthorize} (tests inject `inProduction`). */
4
+ export interface DevToolsGateOptions {
5
+ inProduction?: () => boolean;
6
+ }
7
+ /**
8
+ * The gate of authkit's dev tools on the Agora dev MCP endpoint. Never throws.
9
+ *
10
+ * - `admin.enabled: false` → forbidden.
11
+ * - `admin.authorize` set → its verdict alone decides: when it allows the MCP request, `admin.roles`
12
+ * is NOT checked (an MCP client has no console session; `authorize` is the app's explicit rule).
13
+ * - `admin.authorize` omitted → forbidden in production. Outside production the caller must be
14
+ * signed in through authkit (MCP OAuth sign-in, or a personal agent granted `agora:dev`) as an
15
+ * active account holding one of `admin.roles`; signed out → unauthenticated.
16
+ */
17
+ export declare function authkitDevToolsAuthorize(options?: DevToolsGateOptions): (ctx: HttpContext) => Promise<DevToolsDecision>;
@@ -0,0 +1,69 @@
1
+ import { supportsAccountStatus } from '../accounts/account_store.js';
2
+ import { resolveAccountRoles } from '../host/account_roles.js';
3
+ import { adminAuthorizeChecker, appInProduction } from '../host/admin_authorize.js';
4
+ function fromConsoleDecision(decision) {
5
+ if (decision.allowed)
6
+ return { allowed: true };
7
+ return {
8
+ allowed: false,
9
+ reason: decision.status === 401 ? 'unauthenticated' : 'forbidden',
10
+ ...(decision.redirectTo !== undefined ? { redirectTo: decision.redirectTo } : {}),
11
+ };
12
+ }
13
+ /** The account signed in on this request through authkit (`ctx.authkit`), or `null`. */
14
+ async function signedInAccountId(ctx) {
15
+ const authenticator = ctx.authkit;
16
+ if (typeof authenticator?.getIdentity !== 'function')
17
+ return null;
18
+ try {
19
+ const identity = await authenticator.getIdentity();
20
+ return typeof identity?.userId === 'string' && identity.userId !== '' ? identity.userId : null;
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ /**
27
+ * The gate of authkit's dev tools on the Agora dev MCP endpoint. Never throws.
28
+ *
29
+ * - `admin.enabled: false` → forbidden.
30
+ * - `admin.authorize` set → its verdict alone decides: when it allows the MCP request, `admin.roles`
31
+ * is NOT checked (an MCP client has no console session; `authorize` is the app's explicit rule).
32
+ * - `admin.authorize` omitted → forbidden in production. Outside production the caller must be
33
+ * signed in through authkit (MCP OAuth sign-in, or a personal agent granted `agora:dev`) as an
34
+ * active account holding one of `admin.roles`; signed out → unauthenticated.
35
+ */
36
+ export function authkitDevToolsAuthorize(options = {}) {
37
+ const inProduction = options.inProduction ?? appInProduction;
38
+ return async (ctx) => {
39
+ try {
40
+ const service = await ctx.containerResolver.make('authkit.server');
41
+ const cfg = service.config;
42
+ if (!cfg.admin?.enabled)
43
+ return { allowed: false, reason: 'forbidden' };
44
+ if (cfg.admin.authorize) {
45
+ return fromConsoleDecision(await adminAuthorizeChecker(cfg.admin.authorize)(ctx));
46
+ }
47
+ if (inProduction())
48
+ return { allowed: false, reason: 'forbidden' };
49
+ const accountId = await signedInAccountId(ctx);
50
+ if (accountId === null)
51
+ return { allowed: false, reason: 'unauthenticated' };
52
+ const account = await cfg.accountStore.findById(accountId);
53
+ if (!account)
54
+ return { allowed: false, reason: 'unauthenticated' };
55
+ const store = cfg.accountStore;
56
+ if (supportsAccountStatus(store) && (await store.isDisabled(accountId))) {
57
+ return { allowed: false, reason: 'forbidden' };
58
+ }
59
+ const allowedRoles = (cfg.admin.roles ?? []);
60
+ const roles = await resolveAccountRoles(cfg, account);
61
+ return roles.some((role) => allowedRoles.includes(role))
62
+ ? { allowed: true }
63
+ : { allowed: false, reason: 'forbidden' };
64
+ }
65
+ catch (error) {
66
+ return { allowed: false, reason: 'forbidden', error };
67
+ }
68
+ };
69
+ }
@@ -0,0 +1,11 @@
1
+ import type { ApplicationService } from '@adonisjs/core/types';
2
+ /**
3
+ * Registers authkit's developer tools into the Agora dev MCP hub (`'agora.devTools'`, bound by
4
+ * `@adonis-agora/agent`'s `mcp_provider`). No-op when the hub is not bound, speaks another contract
5
+ * version, or the admin console is off. Returns whether it registered.
6
+ */
7
+ export declare function registerAuthkitDevTools(app: Pick<ApplicationService, 'container'>, config: {
8
+ admin?: {
9
+ enabled?: boolean;
10
+ } | null;
11
+ }): Promise<boolean>;
@@ -0,0 +1,25 @@
1
+ import { DEV_TOOLS_BINDING } from './contract.js';
2
+ import { authkitDevToolsAuthorize } from './gate.js';
3
+ import { authkitDevTools } from './tools.js';
4
+ /**
5
+ * Registers authkit's developer tools into the Agora dev MCP hub (`'agora.devTools'`, bound by
6
+ * `@adonis-agora/agent`'s `mcp_provider`). No-op when the hub is not bound, speaks another contract
7
+ * version, or the admin console is off. Returns whether it registered.
8
+ */
9
+ export async function registerAuthkitDevTools(app, config) {
10
+ if (!config.admin?.enabled)
11
+ return false;
12
+ const container = app.container;
13
+ if (!container.hasBinding(DEV_TOOLS_BINDING))
14
+ return false;
15
+ const hub = (await container.make(DEV_TOOLS_BINDING));
16
+ if (hub?.version !== 1 || typeof hub.register !== 'function')
17
+ return false;
18
+ hub.register({
19
+ lib: 'authkit',
20
+ title: 'Identity (authkit admin)',
21
+ authorize: authkitDevToolsAuthorize(),
22
+ tools: authkitDevTools({ resolve: () => container.make('authkit.server') }),
23
+ });
24
+ return true;
25
+ }
@@ -0,0 +1,24 @@
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ import { AdminClientsService } from '../host/admin_clients_service.js';
3
+ import { AdminSessionsService } from '../host/admin_sessions_service.js';
4
+ import type { DevTool } from './contract.js';
5
+ /** Rows a list tool returns when `limit` is omitted. */
6
+ export declare const DEV_TOOLS_DEFAULT_LIMIT = 20;
7
+ /** The largest `limit` a list tool accepts. */
8
+ export declare const DEV_TOOLS_MAX_LIMIT = 100;
9
+ /** What the tools need from the app; tests replace any of it. */
10
+ export interface AuthkitDevToolsDeps {
11
+ /** The `authkit.server` service. Default: resolved from the request's container. */
12
+ service?(ctx: HttpContext): Promise<any>;
13
+ sessions?(service: any): Pick<AdminSessionsService, 'canList' | 'countActiveSessions' | 'listSessions' | 'listGrants' | 'revokeAll'>;
14
+ clients?(service: any): Pick<AdminClientsService, 'canList' | 'list' | 'find'>;
15
+ /** The `authkit.server` service outside a request, for `available()`. */
16
+ resolve?(): Promise<any>;
17
+ }
18
+ /**
19
+ * authkit's developer tools for the Agora dev MCP endpoint: the admin console's reads, and two
20
+ * destructive actions (revoke sessions, disable a user) that the app must opt into on the endpoint.
21
+ * Every tool goes through the same services as the console; outputs never carry session ids, client
22
+ * secrets, key material, token values or MFA secrets.
23
+ */
24
+ export declare function authkitDevTools(deps?: AuthkitDevToolsDeps): DevTool[];