@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.
- package/CHANGELOG.md +94 -0
- package/README.md +4 -5
- package/build/commands/agora_doctor.d.ts +22 -0
- package/build/commands/agora_doctor.js +109 -0
- package/build/commands/clients_create.d.ts +4 -0
- package/build/commands/clients_create.js +97 -0
- package/build/commands/commands.json +78 -0
- package/build/commands/doctor.js +8 -74
- package/build/host/views/account/apps.edge +1 -5
- package/build/host/views/account/extension.edge +77 -0
- package/build/host/views/account/mfa.edge +2 -0
- package/build/host/views/account/partials/extension_actions.edge +14 -0
- package/build/host/views/account/partials/extension_block.edge +197 -0
- package/build/host/views/account/partials/extension_value.edge +8 -0
- package/build/host/views/account/partials/nav.edge +14 -0
- package/build/host/views/account/security.edge +1 -5
- package/build/host/views/account/tokens.edge +2 -2
- package/build/host/views/agents/consent.edge +11 -2
- package/build/host/views/agents/done.edge +1 -1
- package/build/host/views/partials/styles.edge +1 -1
- package/build/index.d.ts +12 -12
- package/build/index.js +7 -9
- package/build/providers/authkit_server_provider.js +28 -8
- package/build/src/account/extension.d.ts +10 -0
- package/build/src/account/extension.js +9 -0
- package/build/src/account/http.d.ts +77 -0
- package/build/src/account/http.js +381 -0
- package/build/src/account/mount.d.ts +40 -0
- package/build/src/account/mount.js +171 -0
- package/build/src/account/registry.d.ts +41 -0
- package/build/src/account/registry.js +81 -0
- package/build/src/account/remote.d.ts +72 -0
- package/build/src/account/remote.js +406 -0
- package/build/src/account/runtime.d.ts +289 -0
- package/build/src/account/runtime.js +641 -0
- package/build/src/accounts/account_store.d.ts +6 -0
- package/build/src/accounts/lucid_store/organizations.js +6 -0
- package/build/src/agents/config.d.ts +9 -13
- package/build/src/agents/config.js +17 -11
- package/build/src/agents/delegation_service.js +3 -3
- package/build/src/agents/delegation_store.d.ts +3 -2
- package/build/src/agents/delegation_store.js +6 -5
- package/build/src/agents/extension.d.ts +261 -0
- package/build/src/agents/extension.js +40 -0
- package/build/src/agents/middleware.js +1 -1
- package/build/src/agents/protocol.d.ts +4 -4
- package/build/src/agents/registry_store.d.ts +3 -2
- package/build/src/agents/registry_store.js +1 -1
- package/build/src/agents/runtime.d.ts +26 -7
- package/build/src/agents/runtime.js +110 -75
- package/build/src/audit/audit_sink.d.ts +1 -1
- package/build/src/audit/audit_sink.js +10 -1
- package/build/src/console_switcher.d.ts +132 -0
- package/build/src/console_switcher.js +206 -0
- package/build/src/define_config.d.ts +34 -12
- package/build/src/define_config.js +15 -7
- package/build/src/dev_tools/contract.d.ts +72 -0
- package/build/src/dev_tools/contract.js +10 -0
- package/build/src/dev_tools/gate.d.ts +17 -0
- package/build/src/dev_tools/gate.js +69 -0
- package/build/src/dev_tools/register.d.ts +11 -0
- package/build/src/dev_tools/register.js +25 -0
- package/build/src/dev_tools/tools.d.ts +24 -0
- package/build/src/dev_tools/tools.js +384 -0
- package/build/src/doctor/agora_checks.d.ts +15 -0
- package/build/src/doctor/agora_checks.js +150 -0
- package/build/src/doctor/agora_doctor.d.ts +115 -0
- package/build/src/doctor/agora_doctor.js +692 -0
- package/build/src/doctor/doctor_input.d.ts +27 -0
- package/build/src/doctor/doctor_input.js +86 -0
- package/build/src/doctor/index.d.ts +5 -0
- package/build/src/doctor/index.js +4 -0
- package/build/src/host/access_token_verifier.js +7 -0
- package/build/src/host/account_api/account_api_controller.js +8 -6
- package/build/src/host/account_session_sign_in.d.ts +12 -0
- package/build/src/host/account_session_sign_in.js +19 -0
- package/build/src/host/admin_api/admin_users_service.d.ts +5 -2
- package/build/src/host/admin_api/api_clients_controller.d.ts +37 -0
- package/build/src/host/admin_api/api_clients_controller.js +31 -1
- package/build/src/host/admin_api/dto.d.ts +3 -1
- package/build/src/host/admin_api/dto.js +2 -0
- package/build/src/host/admin_authorize.d.ts +8 -0
- package/build/src/host/admin_authorize.js +25 -0
- package/build/src/host/admin_clients_service.d.ts +20 -0
- package/build/src/host/admin_clients_service.js +55 -0
- package/build/src/host/admin_console/admin_console_entry.d.ts +14 -0
- package/build/src/host/admin_console/admin_console_entry.js +80 -0
- package/build/src/host/admin_console/admin_shell_controller.js +8 -0
- package/build/src/host/admin_console/console_clients_controller.d.ts +41 -0
- package/build/src/host/admin_console/console_clients_controller.js +34 -1
- package/build/src/host/admin_console/console_personal_agents_controller.d.ts +1 -6
- package/build/src/host/admin_console/console_personal_agents_controller.js +50 -30
- package/build/src/host/admin_console/console_switcher_controller.d.ts +11 -0
- package/build/src/host/admin_console/console_switcher_controller.js +23 -0
- package/build/src/host/admin_sessions_service.js +8 -5
- package/build/src/host/admin_validators.d.ts +29 -0
- package/build/src/host/admin_validators.js +30 -0
- package/build/src/host/auth_host_config.d.ts +9 -2
- package/build/src/host/controllers/account_apps_controller.js +15 -11
- package/build/src/host/csrf.d.ts +3 -3
- package/build/src/host/csrf.js +3 -13
- package/build/src/host/default_mailer.d.ts +11 -6
- package/build/src/host/default_mailer.js +16 -12
- package/build/src/host/i18n.d.ts +41 -14
- package/build/src/host/i18n.js +55 -13
- package/build/src/host/rate_limit.d.ts +8 -0
- package/build/src/host/rate_limit.js +9 -0
- package/build/src/host/register_auth_host.d.ts +14 -0
- package/build/src/host/register_auth_host.js +167 -106
- package/build/src/host/renderers/edge_renderer.js +5 -0
- package/build/src/host/renderers/inertia_renderer.js +7 -1
- package/build/src/host/screen_props.d.ts +39 -8
- package/build/src/host/ui-dist/assets/index-Dq3dJVBv.js +67 -0
- package/build/src/host/ui-dist/assets/{index-DTSmD4RU.css → index-WNIyCEPA.css} +1 -1
- package/build/src/host/ui-dist/index.html +2 -2
- package/build/src/provider/build_provider.js +37 -6
- package/build/src/provider/oidc_service.d.ts +1 -1
- package/build/src/provider/oidc_service.js +1 -1
- package/build/src/schema/ensure.d.ts +14 -0
- package/build/src/schema/ensure.js +43 -150
- package/build/src/service_tenants/client_metadata.d.ts +39 -0
- package/build/src/service_tenants/client_metadata.js +80 -0
- package/build/src/service_tenants/config.d.ts +44 -0
- package/build/src/service_tenants/config.js +44 -0
- package/build/src/service_tenants/provider_hooks.d.ts +52 -0
- package/build/src/service_tenants/provider_hooks.js +124 -0
- package/build/src/service_tenants/tenant_verifier.d.ts +73 -0
- package/build/src/service_tenants/tenant_verifier.js +104 -0
- package/build/src/tenancy/tenant_labels.d.ts +30 -0
- package/build/src/tenancy/tenant_labels.js +64 -0
- package/build/types.d.ts +3 -1
- package/package.json +9 -6
- package/build/src/agents/poppy/client_registry.d.ts +0 -50
- package/build/src/agents/poppy/client_registry.js +0 -260
- package/build/src/agents/poppy/config.d.ts +0 -396
- package/build/src/agents/poppy/config.js +0 -228
- package/build/src/agents/poppy/dpop.d.ts +0 -61
- package/build/src/agents/poppy/dpop.js +0 -158
- package/build/src/agents/poppy/email_code_sign_in.d.ts +0 -27
- package/build/src/agents/poppy/email_code_sign_in.js +0 -140
- package/build/src/agents/poppy/errors.d.ts +0 -25
- package/build/src/agents/poppy/errors.js +0 -25
- package/build/src/agents/poppy/replay.d.ts +0 -25
- package/build/src/agents/poppy/replay.js +0 -106
- package/build/src/agents/poppy/resource.d.ts +0 -100
- package/build/src/agents/poppy/resource.js +0 -129
- package/build/src/agents/poppy/safe_fetch.d.ts +0 -48
- package/build/src/agents/poppy/safe_fetch.js +0 -262
- package/build/src/agents/poppy/service.d.ts +0 -293
- package/build/src/agents/poppy/service.js +0 -1458
- package/build/src/agents/poppy/session_jwt.d.ts +0 -30
- package/build/src/agents/poppy/session_jwt.js +0 -133
- package/build/src/agents/poppy/store.d.ts +0 -106
- package/build/src/agents/poppy/store.js +0 -261
- package/build/src/agents/poppy/web_session.d.ts +0 -39
- package/build/src/agents/poppy/web_session.js +0 -122
- package/build/src/host/controllers/poppy_consent_controller.d.ts +0 -19
- package/build/src/host/controllers/poppy_consent_controller.js +0 -199
- package/build/src/host/controllers/poppy_controller.d.ts +0 -33
- package/build/src/host/controllers/poppy_controller.js +0 -219
- package/build/src/host/poppy_session_key.d.ts +0 -9
- package/build/src/host/poppy_session_key.js +0 -9
- 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
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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[];
|