@adonis-agora/authkit-server 1.0.0-rc.0 → 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 +111 -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 +14 -12
- package/build/index.js +8 -9
- package/build/providers/authkit_server_provider.js +36 -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_authorize.d.ts +56 -0
- package/build/src/console_authorize.js +85 -0
- package/build/src/console_switcher.d.ts +132 -0
- package/build/src/console_switcher.js +206 -0
- package/build/src/define_config.d.ts +54 -14
- package/build/src/define_config.js +17 -8
- 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/checks.d.ts +7 -1
- package/build/src/doctor/checks.js +47 -1
- 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 +65 -1
- 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_console_warning.d.ts +8 -0
- package/build/src/host/admin_console_warning.js +18 -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 +14 -2
- package/build/src/host/console_denied_page.d.ts +6 -0
- package/build/src/host/console_denied_page.js +18 -0
- package/build/src/host/console_sso.d.ts +24 -0
- package/build/src/host/console_sso.js +70 -0
- package/build/src/host/controllers/account_apps_controller.js +15 -11
- package/build/src/host/controllers/account_session_controller.js +10 -1
- package/build/src/host/controllers/console_sso_controller.d.ts +12 -0
- package/build/src/host/controllers/console_sso_controller.js +61 -0
- package/build/src/host/controllers/interaction_controller.js +3 -1
- 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 +16 -0
- package/build/src/host/register_auth_host.js +230 -88
- 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 +43 -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 +12 -9
- 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
|
@@ -87,7 +87,7 @@ export declare function checkOtpLockout(input: DoctorInput): Finding | null;
|
|
|
87
87
|
export declare function checkSudoMode(_input: DoctorInput): Finding | null;
|
|
88
88
|
/** rateLimit ligado mas @adonisjs/limiter ausente → warn. */
|
|
89
89
|
export declare function checkRateLimit(input: DoctorInput): Finding;
|
|
90
|
-
/** admin.enabled mas sem roles → warn. Reporta o modo de UI ativo. */
|
|
90
|
+
/** admin.enabled mas sem roles, ou sem `admin.authorize` → warn. Reporta o modo de UI ativo. */
|
|
91
91
|
export declare function checkAdmin(input: DoctorInput): Finding | null;
|
|
92
92
|
/** requireVerifiedEmail ligado mas o store não sabe checar verificação → warn. */
|
|
93
93
|
export declare function checkRequireVerifiedEmail(input: DoctorInput): Finding | null;
|
|
@@ -214,6 +214,12 @@ export declare function checkPasskeyAutofill(input: DoctorInput): Finding | null
|
|
|
214
214
|
* de TERCEIROS precisa saber que existe uma lista para fechar.
|
|
215
215
|
*/
|
|
216
216
|
export declare function checkFirstPartyClients(input: DoctorInput): Finding | null;
|
|
217
|
+
/**
|
|
218
|
+
* Como se entra no console de conta e no console admin. O default é o login do
|
|
219
|
+
* IdP (SSO, `accountSession.acceptIdpSession`); desligado, o console só tem o
|
|
220
|
+
* login próprio por senha.
|
|
221
|
+
*/
|
|
222
|
+
export declare function checkConsoleSignIn(input: DoctorInput): Finding | null;
|
|
217
223
|
/**
|
|
218
224
|
* Finding da idade da chave de assinatura managed. `ageDays === null` (sem
|
|
219
225
|
* keystore em arquivo/cofre) → no-op `ok`. Acima de `maxAgeDays` → `warn`.
|
|
@@ -311,7 +311,7 @@ export function checkRateLimit(input) {
|
|
|
311
311
|
}
|
|
312
312
|
return { level: 'ok', message: 'rate-limiting on and @adonisjs/limiter available.' };
|
|
313
313
|
}
|
|
314
|
-
/** admin.enabled mas sem roles → warn. Reporta o modo de UI ativo. */
|
|
314
|
+
/** admin.enabled mas sem roles, ou sem `admin.authorize` → warn. Reporta o modo de UI ativo. */
|
|
315
315
|
export function checkAdmin(input) {
|
|
316
316
|
const admin = input.authkitConfig?.admin;
|
|
317
317
|
if (!admin || admin.enabled !== true)
|
|
@@ -323,6 +323,12 @@ export function checkAdmin(input) {
|
|
|
323
323
|
message: 'admin console on, but no `admin.roles` — nobody will have access (the default ["ADMIN"] was not resolved here).',
|
|
324
324
|
};
|
|
325
325
|
}
|
|
326
|
+
if (!admin.authorize) {
|
|
327
|
+
return {
|
|
328
|
+
level: 'warn',
|
|
329
|
+
message: `admin console on for roles: ${roles.join(', ')}, but no \`admin.authorize\` — it is open outside production and denies every request in production. Set \`admin.authorize\` in config/authkit.ts.`,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
326
332
|
return {
|
|
327
333
|
level: 'ok',
|
|
328
334
|
message: `admin console on for roles: ${roles.join(', ')} (React SPA self-contained — JSON API under {prefix}/api/*).`,
|
|
@@ -908,6 +914,43 @@ export function checkFirstPartyClients(input) {
|
|
|
908
914
|
message: `firstPartyClients: ${allowlist.length} client(s) receive the roles/organization claims (${allowlist.join(', ')}).`,
|
|
909
915
|
};
|
|
910
916
|
}
|
|
917
|
+
/**
|
|
918
|
+
* Como se entra no console de conta e no console admin. O default é o login do
|
|
919
|
+
* IdP (SSO, `accountSession.acceptIdpSession`); desligado, o console só tem o
|
|
920
|
+
* login próprio por senha.
|
|
921
|
+
*/
|
|
922
|
+
export function checkConsoleSignIn(input) {
|
|
923
|
+
const cfg = input.authkitConfig;
|
|
924
|
+
if (!cfg)
|
|
925
|
+
return null;
|
|
926
|
+
const sso = cfg.accountSession?.acceptIdpSession !== false;
|
|
927
|
+
const passwordOff = cfg.authMethods?.password === false;
|
|
928
|
+
const routes = typeof cfg.routes === 'object' && cfg.routes ? cfg.routes : undefined;
|
|
929
|
+
if (!sso && passwordOff && !routes?.accountLoginUrl) {
|
|
930
|
+
return {
|
|
931
|
+
level: 'warn',
|
|
932
|
+
message: 'The account and admin consoles have no way to sign in unless `registerAuthHost` gets an ' +
|
|
933
|
+
'`accountLoginUrl`: `accountSession.acceptIdpSession` is false and password login is off ' +
|
|
934
|
+
'(`authMethods: { password: false }`), and route registration refuses to start without ' +
|
|
935
|
+
'one. Remove `acceptIdpSession: false` so the consoles sign in through the IdP, or point ' +
|
|
936
|
+
'`accountLoginUrl` at a login route of your app.',
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
if (!sso) {
|
|
940
|
+
return {
|
|
941
|
+
level: 'warn',
|
|
942
|
+
message: 'The consoles use their own password login (`accountSession.acceptIdpSession: false`): ' +
|
|
943
|
+
'users sign in twice, and passwordless accounts cannot open them. The default (SSO through ' +
|
|
944
|
+
'the IdP login) is recommended; sensitive operations still ask for sudo.',
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
return {
|
|
948
|
+
level: 'ok',
|
|
949
|
+
message: 'The consoles sign in through the IdP login (SSO). Sensitive operations ask for sudo. ' +
|
|
950
|
+
'Make sure admin accounts have MFA enrolled (or require it for everyone with ' +
|
|
951
|
+
'`mfa.requiredFactors`).',
|
|
952
|
+
};
|
|
953
|
+
}
|
|
911
954
|
/**
|
|
912
955
|
* Finding da idade da chave de assinatura managed. `ageDays === null` (sem
|
|
913
956
|
* keystore em arquivo/cofre) → no-op `ok`. Acima de `maxAgeDays` → `warn`.
|
|
@@ -1007,6 +1050,9 @@ export function runAllChecks(input) {
|
|
|
1007
1050
|
const firstPartyClients = checkFirstPartyClients(input);
|
|
1008
1051
|
if (firstPartyClients)
|
|
1009
1052
|
findings.push(firstPartyClients);
|
|
1053
|
+
const consoleSignIn = checkConsoleSignIn(input);
|
|
1054
|
+
if (consoleSignIn)
|
|
1055
|
+
findings.push(consoleSignIn);
|
|
1010
1056
|
return findings;
|
|
1011
1057
|
}
|
|
1012
1058
|
/** Há algum finding de nível 'error'? (define o exit code). */
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
2
|
+
import { type DoctorInput, type Finding } from './checks.js';
|
|
3
|
+
/** Logger mínimo para reportar peers instalados-mas-quebrados. */
|
|
4
|
+
export interface CanImportLogger {
|
|
5
|
+
warning(msg: string): void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Tenta importar um peer; `true` se importável.
|
|
9
|
+
*
|
|
10
|
+
* Distingue "não instalado" de "instalado mas quebrado": só um erro de
|
|
11
|
+
* módulo-não-encontrado (`ERR_MODULE_NOT_FOUND`/`MODULE_NOT_FOUND`) é tratado como
|
|
12
|
+
* peer ausente (silencioso — é o caso esperado). Qualquer outro erro significa que
|
|
13
|
+
* o peer ESTÁ presente mas falhou ao carregar (import circular, erro de sintaxe,
|
|
14
|
+
* config inválida) — isso o doctor precisa gritar, senão um peer quebrado aparece
|
|
15
|
+
* como "ausente" e o diagnóstico mente.
|
|
16
|
+
*/
|
|
17
|
+
export declare function canImport(specifier: string, logger?: CanImportLogger): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* Monta o `DoctorInput` a partir do app (config `authkit` resolvida, `session`, peers). Usado por
|
|
20
|
+
* `authkit:doctor` e pelos checks do `agora:doctor`. Lança se `config/authkit.ts` não resolver.
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildDoctorInput(app: ApplicationService, logger?: CanImportLogger): Promise<DoctorInput>;
|
|
23
|
+
/**
|
|
24
|
+
* O finding de idade da chave de assinatura managed (best-effort): `null` quando o jwks não é
|
|
25
|
+
* `managed` com store, ou quando o keystore não pôde ser lido.
|
|
26
|
+
*/
|
|
27
|
+
export declare function managedSigningKeyAgeFinding(app: ApplicationService, authkitConfig: Record<string, any> | null): Promise<Finding | null>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { DatabaseAdapter } from '../adapters/database_adapter.js';
|
|
10
|
+
import { resolveAuthkitConfig } from '../commands/resolve_config.js';
|
|
11
|
+
import { defaultEncryptForStore } from '../define_config.js';
|
|
12
|
+
import { signingKeyAgeDays } from '../keys/keystore.js';
|
|
13
|
+
import { KeystoreCodec } from '../keys/keystore_codec.js';
|
|
14
|
+
import { loadEncryptionService } from '../keys/keystore_crypto.js';
|
|
15
|
+
import { KeystoreManager, resolveKeystoreVault } from '../keys/keystore_manager.js';
|
|
16
|
+
import { signingKeyAgeFinding } from './checks.js';
|
|
17
|
+
/**
|
|
18
|
+
* Tenta importar um peer; `true` se importável.
|
|
19
|
+
*
|
|
20
|
+
* Distingue "não instalado" de "instalado mas quebrado": só um erro de
|
|
21
|
+
* módulo-não-encontrado (`ERR_MODULE_NOT_FOUND`/`MODULE_NOT_FOUND`) é tratado como
|
|
22
|
+
* peer ausente (silencioso — é o caso esperado). Qualquer outro erro significa que
|
|
23
|
+
* o peer ESTÁ presente mas falhou ao carregar (import circular, erro de sintaxe,
|
|
24
|
+
* config inválida) — isso o doctor precisa gritar, senão um peer quebrado aparece
|
|
25
|
+
* como "ausente" e o diagnóstico mente.
|
|
26
|
+
*/
|
|
27
|
+
export async function canImport(specifier, logger) {
|
|
28
|
+
try {
|
|
29
|
+
await import(__rewriteRelativeImportExtension(specifier));
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const code = err?.code;
|
|
34
|
+
if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND') {
|
|
35
|
+
logger?.warning(`⚠️ ${specifier} está instalado mas falhou ao carregar: ${err.message}`);
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Monta o `DoctorInput` a partir do app (config `authkit` resolvida, `session`, peers). Usado por
|
|
42
|
+
* `authkit:doctor` e pelos checks do `agora:doctor`. Lança se `config/authkit.ts` não resolver.
|
|
43
|
+
*/
|
|
44
|
+
export async function buildDoctorInput(app, logger) {
|
|
45
|
+
const config = await app.container.make('config');
|
|
46
|
+
// `defineConfig` exporta um config provider — resolve antes de inspecionar,
|
|
47
|
+
// senão todo campo aparece como "ausente" (provider cru não tem issuer etc.).
|
|
48
|
+
const authkitConfig = await resolveAuthkitConfig(app, config.get('authkit', null));
|
|
49
|
+
const sessionConfig = config.get('session', null) ?? null;
|
|
50
|
+
return {
|
|
51
|
+
authkitConfig,
|
|
52
|
+
sessionConfig,
|
|
53
|
+
peers: {
|
|
54
|
+
session: await canImport('@adonisjs/session', logger),
|
|
55
|
+
shield: await canImport('@adonisjs/shield', logger),
|
|
56
|
+
ally: await canImport('@adonisjs/ally', logger),
|
|
57
|
+
limiter: await canImport('@adonisjs/limiter', logger),
|
|
58
|
+
},
|
|
59
|
+
__adapterClasses: { DatabaseAdapter },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* O finding de idade da chave de assinatura managed (best-effort): `null` quando o jwks não é
|
|
64
|
+
* `managed` com store, ou quando o keystore não pôde ser lido.
|
|
65
|
+
*/
|
|
66
|
+
export async function managedSigningKeyAgeFinding(app, authkitConfig) {
|
|
67
|
+
const jwksInput = (authkitConfig?.jwksConfig ?? authkitConfig?.jwks);
|
|
68
|
+
if (jwksInput?.source !== 'managed' || !jwksInput?.store)
|
|
69
|
+
return null;
|
|
70
|
+
try {
|
|
71
|
+
const vault = resolveKeystoreVault(jwksInput.store, {
|
|
72
|
+
makePath: (p) => app.makePath(p),
|
|
73
|
+
container: app.container,
|
|
74
|
+
});
|
|
75
|
+
const encrypt = jwksInput.encrypt ?? defaultEncryptForStore(jwksInput.store);
|
|
76
|
+
const enc = encrypt ? await loadEncryptionService().catch(() => undefined) : undefined;
|
|
77
|
+
const mgr = new KeystoreManager(vault, new KeystoreCodec({ encrypt, enc }), jwksInput.algorithm ?? 'RS256');
|
|
78
|
+
const store = await mgr.read().catch(() => null);
|
|
79
|
+
const maxAge = jwksInput.rotationDays ?? 90;
|
|
80
|
+
return signingKeyAgeFinding(signingKeyAgeDays(store), maxAge);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* idade é best-effort no doctor */
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AgoraDoctorCheck } from './agora_doctor.js';
|
|
2
|
+
export type { AgoraDoctorCheck, AgoraDoctorRegistry, AgoraDoctorReport, AgoraDoctorResult, AgoraDoctorStatus, } from './agora_doctor.js';
|
|
3
|
+
export { AGORA_DOCTOR_BINDING, registerDoctorChecks } from './agora_doctor.js';
|
|
4
|
+
/** authkit's checks, for `node ace agora:doctor --no-boot` (which imports this entry instead of booting). */
|
|
5
|
+
export declare const agoraDoctorChecks: AgoraDoctorCheck[];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { authkitDoctorChecks } from './agora_checks.js';
|
|
2
|
+
export { AGORA_DOCTOR_BINDING, registerDoctorChecks } from './agora_doctor.js';
|
|
3
|
+
/** authkit's checks, for `node ace agora:doctor --no-boot` (which imports this entry instead of booting). */
|
|
4
|
+
export const agoraDoctorChecks = authkitDoctorChecks();
|
|
@@ -41,6 +41,10 @@ function fromJwtPayload(payload) {
|
|
|
41
41
|
if (typeof payload.sub !== 'string' || !payload.sub)
|
|
42
42
|
return null;
|
|
43
43
|
const clientId = payload.client_id;
|
|
44
|
+
// No user behind it: a `client_credentials` token (a service tenant's, for one) has
|
|
45
|
+
// `sub` = the client id (RFC 9068 §2.2) and never authenticates an account.
|
|
46
|
+
if (payload.sub === clientId)
|
|
47
|
+
return null;
|
|
44
48
|
return {
|
|
45
49
|
format: 'jwt',
|
|
46
50
|
sub: payload.sub,
|
|
@@ -209,6 +213,9 @@ export function remoteAccessTokenVerifier(options) {
|
|
|
209
213
|
return null;
|
|
210
214
|
if (typeof body.sub !== 'string' || !body.sub)
|
|
211
215
|
return null;
|
|
216
|
+
// `client_credentials` token: no account behind it.
|
|
217
|
+
if (body.sub === body.client_id)
|
|
218
|
+
return null;
|
|
212
219
|
if (typeof body.exp === 'number' && body.exp <= Math.floor(Date.now() / 1000))
|
|
213
220
|
return null;
|
|
214
221
|
return {
|
|
@@ -611,7 +611,7 @@ export default class AccountApiController {
|
|
|
611
611
|
/** Personal agents com delegação ativa na conta (scopes aprovados). */
|
|
612
612
|
async listAgents(ctx) {
|
|
613
613
|
const runtime = await personalAgentsFor(ctx);
|
|
614
|
-
if (!runtime
|
|
614
|
+
if (!runtime || (!runtime.delegation && runtime.extensions.size === 0)) {
|
|
615
615
|
return ctx.response
|
|
616
616
|
.status(404)
|
|
617
617
|
.send(apiErr('capability_unsupported', 'Personal agent delegation is not enabled.'));
|
|
@@ -620,16 +620,18 @@ export default class AccountApiController {
|
|
|
620
620
|
const pact = runtime.delegation
|
|
621
621
|
? (await runtime.delegation.listGrants(userId)).map((g) => ({ ...g, protocol: 'pact' }))
|
|
622
622
|
: [];
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
623
|
+
const others = [];
|
|
624
|
+
for (const [protocol, { runtime: extension }] of runtime.extensions) {
|
|
625
|
+
for (const g of await extension.listAccountGrants(userId))
|
|
626
|
+
others.push({ ...g, protocol });
|
|
627
|
+
}
|
|
628
|
+
return { agents: [...pact, ...others] };
|
|
627
629
|
}
|
|
628
630
|
// ─── DELETE /account/api/agents/:id ──────────────────────────────────────
|
|
629
631
|
/** Revoga a delegação de um personal agent (efeito imediato nos tokens). */
|
|
630
632
|
async revokeAgent(ctx) {
|
|
631
633
|
const runtime = await personalAgentsFor(ctx);
|
|
632
|
-
if (!runtime
|
|
634
|
+
if (!runtime || (!runtime.delegation && runtime.extensions.size === 0)) {
|
|
633
635
|
return ctx.response
|
|
634
636
|
.status(404)
|
|
635
637
|
.send(apiErr('capability_unsupported', 'Personal agent delegation is not enabled.'));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abrir e fechar a sessão de CONTA do authkit (o cookie do console, `ACCOUNT_SESSION_KEY`) a partir
|
|
3
|
+
* de código de fora do host-kit — o navegador de um personal agent que entrou na conta, por
|
|
4
|
+
* exemplo. Sincroniza `ctx.auth` (`adonisAuth.guard`) como o login do próprio console.
|
|
5
|
+
*
|
|
6
|
+
* Estável no 1.x (usado pelas `personalAgents.extensions`).
|
|
7
|
+
*/
|
|
8
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
9
|
+
/** Liga a sessão de conta a `accountId` e sincroniza `ctx.auth`. Não regenera a sessão. */
|
|
10
|
+
export declare function signInAccountSession(ctx: HttpContext, accountId: string): Promise<void>;
|
|
11
|
+
/** Desliga a sessão de conta e sincroniza `ctx.auth`. Não regenera a sessão. */
|
|
12
|
+
export declare function signOutAccountSession(ctx: HttpContext): Promise<void>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ACCOUNT_SESSION_KEY } from './account_session_key.js';
|
|
2
|
+
import { syncAdonisAuthLogin, syncAdonisAuthLogout } from './adonis_auth_sync.js';
|
|
3
|
+
/** Liga a sessão de conta a `accountId` e sincroniza `ctx.auth`. Não regenera a sessão. */
|
|
4
|
+
export async function signInAccountSession(ctx, accountId) {
|
|
5
|
+
// Sem augmentation no barrel (ver `augmentation_isolation.spec.ts`): a sessão é lida sem tipo.
|
|
6
|
+
const session = ctx.session;
|
|
7
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
8
|
+
session.put(ACCOUNT_SESSION_KEY, accountId);
|
|
9
|
+
const account = await service.config.accountStore.findById(accountId);
|
|
10
|
+
if (account)
|
|
11
|
+
await syncAdonisAuthLogin(ctx, service.config, account);
|
|
12
|
+
}
|
|
13
|
+
/** Desliga a sessão de conta e sincroniza `ctx.auth`. Não regenera a sessão. */
|
|
14
|
+
export async function signOutAccountSession(ctx) {
|
|
15
|
+
const session = ctx.session;
|
|
16
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
17
|
+
session.forget(ACCOUNT_SESSION_KEY);
|
|
18
|
+
await syncAdonisAuthLogout(ctx, service.config);
|
|
19
|
+
}
|
|
@@ -8,8 +8,11 @@ import type { SettingsCapability } from '../runtime_settings.js';
|
|
|
8
8
|
export interface AdminActor {
|
|
9
9
|
actorId: string | null;
|
|
10
10
|
ip: string | null;
|
|
11
|
-
/**
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Marca metadata da auditoria — 'admin-api' nas escritas via REST, 'admin' no console HTML,
|
|
13
|
+
* 'mcp' nas ações dos dev tools (endpoint MCP do Agora).
|
|
14
|
+
*/
|
|
15
|
+
source?: 'admin-api' | 'admin' | 'mcp';
|
|
13
16
|
}
|
|
14
17
|
/** Resultado da deleção via admin: false quando o store não suporta hard delete. */
|
|
15
18
|
export type DeleteUserResult = {
|
|
@@ -6,6 +6,7 @@ import type { HttpContext } from '@adonisjs/core/http';
|
|
|
6
6
|
* em create/regenerate. Audita create/update/delete.
|
|
7
7
|
*/
|
|
8
8
|
export default class ApiClientsController {
|
|
9
|
+
#private;
|
|
9
10
|
index(ctx: HttpContext): Promise<{
|
|
10
11
|
data: {
|
|
11
12
|
clientId: string;
|
|
@@ -19,6 +20,8 @@ export default class ApiClientsController {
|
|
|
19
20
|
backchannelLogoutSessionRequired: boolean;
|
|
20
21
|
clientName: string | null;
|
|
21
22
|
logoUri: string | null;
|
|
23
|
+
disabled: boolean;
|
|
24
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
22
25
|
}[];
|
|
23
26
|
canList: boolean;
|
|
24
27
|
}>;
|
|
@@ -34,6 +37,8 @@ export default class ApiClientsController {
|
|
|
34
37
|
backchannelLogoutSessionRequired: boolean;
|
|
35
38
|
clientName: string | null;
|
|
36
39
|
logoUri: string | null;
|
|
40
|
+
disabled: boolean;
|
|
41
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
37
42
|
}>;
|
|
38
43
|
store(ctx: HttpContext): Promise<void | {
|
|
39
44
|
clientId: string;
|
|
@@ -51,11 +56,43 @@ export default class ApiClientsController {
|
|
|
51
56
|
backchannelLogoutSessionRequired: boolean;
|
|
52
57
|
clientName: string | null;
|
|
53
58
|
logoUri: string | null;
|
|
59
|
+
disabled: boolean;
|
|
60
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
54
61
|
}>;
|
|
55
62
|
regenerateSecret(ctx: HttpContext): Promise<void | {
|
|
56
63
|
clientId: any;
|
|
57
64
|
clientSecret: string;
|
|
58
65
|
}>;
|
|
66
|
+
disable(ctx: HttpContext): Promise<void | {
|
|
67
|
+
clientId: string;
|
|
68
|
+
confidential: boolean;
|
|
69
|
+
grantTypes: string[];
|
|
70
|
+
redirectUris: string[];
|
|
71
|
+
postLogoutRedirectUris: string[];
|
|
72
|
+
tokenEndpointAuthMethod: string;
|
|
73
|
+
applicationType: import("../client_metadata.js").ApplicationType;
|
|
74
|
+
backchannelLogoutUri: string | null;
|
|
75
|
+
backchannelLogoutSessionRequired: boolean;
|
|
76
|
+
clientName: string | null;
|
|
77
|
+
logoUri: string | null;
|
|
78
|
+
disabled: boolean;
|
|
79
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
80
|
+
}>;
|
|
81
|
+
enable(ctx: HttpContext): Promise<void | {
|
|
82
|
+
clientId: string;
|
|
83
|
+
confidential: boolean;
|
|
84
|
+
grantTypes: string[];
|
|
85
|
+
redirectUris: string[];
|
|
86
|
+
postLogoutRedirectUris: string[];
|
|
87
|
+
tokenEndpointAuthMethod: string;
|
|
88
|
+
applicationType: import("../client_metadata.js").ApplicationType;
|
|
89
|
+
backchannelLogoutUri: string | null;
|
|
90
|
+
backchannelLogoutSessionRequired: boolean;
|
|
91
|
+
clientName: string | null;
|
|
92
|
+
logoUri: string | null;
|
|
93
|
+
disabled: boolean;
|
|
94
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
95
|
+
}>;
|
|
59
96
|
destroy(ctx: HttpContext): Promise<{
|
|
60
97
|
clientId: any;
|
|
61
98
|
deleted: boolean;
|
|
@@ -85,11 +85,16 @@ export default class ApiClientsController {
|
|
|
85
85
|
const id = ctx.request.param('id');
|
|
86
86
|
try {
|
|
87
87
|
const secret = await svc.regenerateSecret(id);
|
|
88
|
+
const tenant = (await svc.find(id))?.serviceTenant;
|
|
88
89
|
await service.config.audit?.record({
|
|
89
90
|
type: 'client.updated',
|
|
90
91
|
clientId: id,
|
|
91
92
|
ip: ctx.request.ip?.() ?? null,
|
|
92
|
-
metadata: {
|
|
93
|
+
metadata: {
|
|
94
|
+
actor: 'admin-api',
|
|
95
|
+
action: 'regenerate_secret',
|
|
96
|
+
...(tenant ? { partition: tenant.partition } : {}),
|
|
97
|
+
},
|
|
93
98
|
});
|
|
94
99
|
return { clientId: id, clientSecret: secret };
|
|
95
100
|
}
|
|
@@ -97,6 +102,31 @@ export default class ApiClientsController {
|
|
|
97
102
|
return ctx.response.conflict(apiError('cannot_regenerate', e.message));
|
|
98
103
|
}
|
|
99
104
|
}
|
|
105
|
+
async disable(ctx) {
|
|
106
|
+
return this.#setDisabled(ctx, true);
|
|
107
|
+
}
|
|
108
|
+
async enable(ctx) {
|
|
109
|
+
return this.#setDisabled(ctx, false);
|
|
110
|
+
}
|
|
111
|
+
/** Disabled clients get `invalid_client` from the next request on. */
|
|
112
|
+
async #setDisabled(ctx, disabled) {
|
|
113
|
+
const { service, svc } = await clientsService(ctx);
|
|
114
|
+
const id = ctx.request.param('id');
|
|
115
|
+
if (!(await svc.setDisabled(id, disabled))) {
|
|
116
|
+
return ctx.response.notFound(apiError('not_found', 'Client não encontrado.'));
|
|
117
|
+
}
|
|
118
|
+
const client = await svc.find(id);
|
|
119
|
+
await service.config.audit?.record({
|
|
120
|
+
type: disabled ? 'client.disabled' : 'client.enabled',
|
|
121
|
+
clientId: id,
|
|
122
|
+
ip: ctx.request.ip?.() ?? null,
|
|
123
|
+
metadata: {
|
|
124
|
+
actor: 'admin-api',
|
|
125
|
+
...(client?.serviceTenant ? { partition: client.serviceTenant.partition } : {}),
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
return clientDto(client);
|
|
129
|
+
}
|
|
100
130
|
async destroy(ctx) {
|
|
101
131
|
const { service, svc } = await clientsService(ctx);
|
|
102
132
|
const id = ctx.request.param('id');
|
|
@@ -40,6 +40,8 @@ export declare function clientDto(client: AdminClient): {
|
|
|
40
40
|
backchannelLogoutSessionRequired: boolean;
|
|
41
41
|
clientName: string | null;
|
|
42
42
|
logoUri: string | null;
|
|
43
|
+
disabled: boolean;
|
|
44
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
43
45
|
};
|
|
44
46
|
/** Inclui o secret (mostrado UMA vez) em create/regenerate. */
|
|
45
47
|
export declare function createdClientDto(created: CreatedClient): {
|
|
@@ -67,7 +69,7 @@ export declare function grantDto(grant: AdminGrant): {
|
|
|
67
69
|
};
|
|
68
70
|
export declare function auditDto(event: StoredAuditEvent): {
|
|
69
71
|
id: string;
|
|
70
|
-
type: "account.deleted" | "account.expiration_warned" | "account.expired_login_blocked" | "account.exported" | "account.locked" | "account.signed_out_all" | "agent.allowed" | "agent.blocked" | "agent.delegation_approved" | "agent.delegation_denied" | "agent.grant_revoked" | "agent.grant_revoked_by_admin" | "agent.registry_removed" | "bot_protection.rejected" | "client.created" | "client.deleted" | "client.secret_regenerated" | "client.updated" | "email.change_requested" | "email.changed" | "email_change.cancelled" | "email_change.confirmed" | "email_change.requested" | "email_verification.consumed" | "email_verification.issued" | "grant.revoked_by_user" | "impersonation" | "impersonation.panel_viewed" | "impersonation.stopped" | "keys.rotated" | "login.failure" | "login.magic_link_sent" | "login.new_device" | "login.new_ip_notified" | "login.otp_failed" | "login.otp_invalidated" | "login.otp_sent" | "login.otp_verified" | "login.success" | "maintenance.disabled" | "maintenance.enabled" | "mfa.disabled" | "mfa.enabled" | "mfa.recovery_codes_regenerated" | "organization.created" | "organization.deactivated" | "organization.deleted" | "organization.invitation_accepted" | "organization.invitation_revoked" | "organization.invitation_sent" | "organization.member_added" | "organization.member_removed" | "organization.member_role_changed" | "organization.member_role_updated" | "organization.switched" | "organization.updated" | "otp.locked" | "otp.unlock_failed" | "otp.unlocked" | "passkey.registered" | "passkey.removed" | "password.changed" | "password.expired_change_forced" | "password.rehashed" | "password_reset.consumed" | "password_reset.issued" | "pat.issued" | "pat.revoked" | "pat.used" | "profile.updated" | "roles_catalog.updated" | "security_notice.sent" | "session.revoked" | "session.revoked_all" | "session.single_enforced" | "settings.updated" | "signup" | "sudo.confirmed" | "trusted_device.revoked" | "user.created" | "user.deleted" | "user.disabled" | "user.enabled" | "user.password_reset_sent";
|
|
72
|
+
type: "account.deleted" | "account.expiration_warned" | "account.expired_login_blocked" | "account.exported" | "account.extension.action" | "account.extension.redirect" | "account.locked" | "account.signed_out_all" | "agent.allowed" | "agent.blocked" | "agent.delegation_approved" | "agent.delegation_denied" | "agent.grant_revoked" | "agent.grant_revoked_by_admin" | "agent.registry_removed" | "bot_protection.rejected" | "client.created" | "client.deleted" | "client.disabled" | "client.enabled" | "client.secret_regenerated" | "client.updated" | "email.change_requested" | "email.changed" | "email_change.cancelled" | "email_change.confirmed" | "email_change.requested" | "email_verification.consumed" | "email_verification.issued" | "grant.revoked_by_user" | "impersonation" | "impersonation.panel_viewed" | "impersonation.stopped" | "keys.rotated" | "login.failure" | "login.magic_link_sent" | "login.new_device" | "login.new_ip_notified" | "login.otp_failed" | "login.otp_invalidated" | "login.otp_sent" | "login.otp_verified" | "login.success" | "maintenance.disabled" | "maintenance.enabled" | "mfa.disabled" | "mfa.enabled" | "mfa.recovery_codes_regenerated" | "organization.created" | "organization.deactivated" | "organization.deleted" | "organization.invitation_accepted" | "organization.invitation_revoked" | "organization.invitation_sent" | "organization.member_added" | "organization.member_removed" | "organization.member_role_changed" | "organization.member_role_updated" | "organization.switched" | "organization.updated" | "otp.locked" | "otp.unlock_failed" | "otp.unlocked" | "passkey.registered" | "passkey.removed" | "password.changed" | "password.expired_change_forced" | "password.rehashed" | "password_reset.consumed" | "password_reset.issued" | "pat.issued" | "pat.revoked" | "pat.used" | "profile.updated" | "roles_catalog.updated" | "security_notice.sent" | "service_tenant.token_issued" | "session.revoked" | "session.revoked_all" | "session.single_enforced" | "settings.updated" | "signup" | "sudo.confirmed" | "trusted_device.revoked" | "user.created" | "user.deleted" | "user.disabled" | "user.enabled" | "user.password_reset_sent";
|
|
71
73
|
accountId: string | null;
|
|
72
74
|
email: string | null;
|
|
73
75
|
clientId: string | null;
|
|
@@ -32,6 +32,8 @@ export function clientDto(client) {
|
|
|
32
32
|
backchannelLogoutSessionRequired: client.backchannelLogoutSessionRequired ?? false,
|
|
33
33
|
clientName: client.clientName,
|
|
34
34
|
logoUri: client.logoUri,
|
|
35
|
+
disabled: client.disabled,
|
|
36
|
+
serviceTenant: client.serviceTenant,
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
/** Inclui o secret (mostrado UMA vez) em create/regenerate. */
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ConsoleAuthorize, type ConsoleAuthorizeDecision } from '../console_authorize.js';
|
|
2
|
+
/**
|
|
3
|
+
* Whether the app runs in production. Unknown (the provider did not register the
|
|
4
|
+
* app) counts as production, so an omitted `admin.authorize` fails closed.
|
|
5
|
+
*/
|
|
6
|
+
export declare function appInProduction(): boolean;
|
|
7
|
+
/** The resolved `admin.authorize` checker (memoized per configured value). Never throws. */
|
|
8
|
+
export declare function adminAuthorizeChecker(authorize: ConsoleAuthorize): (ctx: any) => Promise<ConsoleAuthorizeDecision>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getBootedApp } from '../../services/booted_app.js';
|
|
2
|
+
import { resolveConsoleAuthorize, } from '../console_authorize.js';
|
|
3
|
+
/**
|
|
4
|
+
* Whether the app runs in production. Unknown (the provider did not register the
|
|
5
|
+
* app) counts as production, so an omitted `admin.authorize` fails closed.
|
|
6
|
+
*/
|
|
7
|
+
export function appInProduction() {
|
|
8
|
+
try {
|
|
9
|
+
return getBootedApp().inProduction !== false;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** One checker per configured `admin.authorize`, so a lazy import runs once. */
|
|
16
|
+
const adminAuthorizeCheckers = new WeakMap();
|
|
17
|
+
/** The resolved `admin.authorize` checker (memoized per configured value). Never throws. */
|
|
18
|
+
export function adminAuthorizeChecker(authorize) {
|
|
19
|
+
let checker = adminAuthorizeCheckers.get(authorize);
|
|
20
|
+
if (!checker) {
|
|
21
|
+
checker = resolveConsoleAuthorize(authorize);
|
|
22
|
+
adminAuthorizeCheckers.set(authorize, checker);
|
|
23
|
+
}
|
|
24
|
+
return checker;
|
|
25
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { OidcService } from '../provider/oidc_service.js';
|
|
2
|
+
import { type ServiceTenantInfo } from '../service_tenants/client_metadata.js';
|
|
2
3
|
import { type ApplicationType } from './client_metadata.js';
|
|
3
4
|
/** Métodos de autenticação no token endpoint suportados pelo formulário admin. */
|
|
4
5
|
export type TokenEndpointAuthMethod = 'client_secret_basic' | 'client_secret_post' | 'none';
|
|
@@ -30,6 +31,15 @@ export interface ClientInput {
|
|
|
30
31
|
* `backchannelLogoutUri` não está definido.
|
|
31
32
|
*/
|
|
32
33
|
backchannelLogoutSessionRequired?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Makes the client a service tenant: confidential, `client_credentials` only, no
|
|
36
|
+
* redirect URIs; its tokens carry `partition` and `capabilities`. On update, `null`
|
|
37
|
+
* turns it back into a regular client; absent keeps the current value.
|
|
38
|
+
*/
|
|
39
|
+
serviceTenant?: {
|
|
40
|
+
partition: string;
|
|
41
|
+
capabilities?: string[];
|
|
42
|
+
} | null;
|
|
33
43
|
}
|
|
34
44
|
/** Client persistido, apresentado ao console admin. */
|
|
35
45
|
export interface AdminClient {
|
|
@@ -49,6 +59,10 @@ export interface AdminClient {
|
|
|
49
59
|
clientName: string | null;
|
|
50
60
|
/** `logo_uri` registrado, ou `null`. */
|
|
51
61
|
logoUri: string | null;
|
|
62
|
+
/** Disabled clients get no tokens (`invalid_client`) until enabled again. */
|
|
63
|
+
disabled: boolean;
|
|
64
|
+
/** Service-tenant settings, or `null` for a regular client. */
|
|
65
|
+
serviceTenant: ServiceTenantInfo | null;
|
|
52
66
|
}
|
|
53
67
|
/** Resultado de uma criação: o client + o secret em claro (mostrado UMA vez). */
|
|
54
68
|
export interface CreatedClient {
|
|
@@ -94,6 +108,12 @@ export declare class AdminClientsService {
|
|
|
94
108
|
* PRESERVANDO o client_secret existente. Lança se o client não existe.
|
|
95
109
|
*/
|
|
96
110
|
update(clientId: string, input: Partial<ClientInput>): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Disables or re-enables a client. A disabled client gets `invalid_client` on every
|
|
113
|
+
* endpoint from the next request on (tokens already issued stay valid until they
|
|
114
|
+
* expire). Returns `false` when the client does not exist.
|
|
115
|
+
*/
|
|
116
|
+
setDisabled(clientId: string, disabled: boolean): Promise<boolean>;
|
|
97
117
|
/**
|
|
98
118
|
* Regenera o client_secret de um client confidencial, preservando o resto da
|
|
99
119
|
* metadata. Retorna o novo secret em claro (mostrado UMA vez). Lança se o
|