@adonis-agora/authkit-server 0.46.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/commands/clients_create.js +4 -4
- package/build/commands/configure.js +3 -2
- package/build/commands/doctor.js +8 -5
- package/build/commands/eject.js +1 -1
- package/build/commands/expire_scan.js +7 -5
- package/build/commands/import_users.js +1 -1
- package/build/commands/keys_rotate.js +7 -4
- package/build/host/views/account/apps.edge +5 -5
- package/build/host/views/account/login.edge +1 -1
- package/build/host/views/account/mfa.edge +7 -7
- package/build/host/views/account/orgs.edge +5 -5
- package/build/host/views/account/security.edge +10 -10
- package/build/host/views/account/tokens.edge +5 -5
- package/build/host/views/otp-unlock.edge +2 -2
- package/build/index.d.ts +7 -7
- package/build/index.js +5 -5
- package/build/providers/authkit_server_provider.d.ts +2 -2
- package/build/providers/authkit_server_provider.js +26 -10
- package/build/services/booted_app.d.ts +8 -0
- package/build/services/booted_app.js +27 -0
- package/build/services/main.d.ts +8 -1
- package/build/services/main.js +10 -2
- package/build/src/accounts/lucid_account_store.d.ts +3 -3
- package/build/src/accounts/lucid_account_store.js +6 -8
- package/build/src/accounts/lucid_store/core.js +1 -1
- package/build/src/accounts/lucid_store/mfa.js +1 -1
- package/build/src/accounts/lucid_store/organizations.js +2 -4
- package/build/src/accounts/lucid_store/password_hygiene.js +1 -4
- package/build/src/accounts/lucid_store/shared.d.ts +1 -1
- package/build/src/accounts/lucid_stores.d.ts +3 -3
- package/build/src/accounts/lucid_stores.js +2 -2
- package/build/src/adapters/database_adapter.js +3 -1
- package/build/src/adapters/factory.js +1 -1
- package/build/src/adapters/redis_adapter.js +2 -1
- package/build/src/commands/expire_scan_command.js +19 -5
- package/build/src/commands/settings_commands.js +22 -5
- package/build/src/define_config.d.ts +20 -20
- package/build/src/define_config.js +62 -67
- package/build/src/doctor/checks.js +45 -20
- package/build/src/events/dispatcher.d.ts +1 -1
- package/build/src/events/dispatcher.js +10 -10
- package/build/src/host/account_api/account_api_controller.js +95 -39
- package/build/src/host/account_deletion_ops.d.ts +4 -4
- package/build/src/host/account_deletion_ops.js +5 -5
- package/build/src/host/account_deletion_service.d.ts +2 -2
- package/build/src/host/account_deletion_service.js +2 -2
- package/build/src/host/account_export_service.d.ts +1 -1
- package/build/src/host/account_export_service.js +4 -6
- package/build/src/host/account_home.d.ts +0 -8
- package/build/src/host/account_home.js +6 -4
- package/build/src/host/account_login_url.d.ts +44 -0
- package/build/src/host/account_login_url.js +58 -0
- package/build/src/host/account_paths.d.ts +120 -0
- package/build/src/host/account_paths.js +161 -0
- package/build/src/host/admin_api/admin_orgs_service.d.ts +2 -2
- package/build/src/host/admin_api/admin_orgs_service.js +3 -2
- package/build/src/host/admin_api/admin_users_service.d.ts +12 -12
- package/build/src/host/admin_api/admin_users_service.js +20 -20
- package/build/src/host/admin_api/api_clients_controller.js +2 -2
- package/build/src/host/admin_api/api_misc_controller.js +2 -2
- package/build/src/host/admin_api/api_orgs_controller.js +3 -3
- package/build/src/host/admin_api/api_settings_controller.js +11 -5
- package/build/src/host/admin_api/api_users_controller.d.ts +2 -2
- package/build/src/host/admin_api/api_users_controller.js +37 -38
- package/build/src/host/admin_api/dto.d.ts +4 -4
- package/build/src/host/admin_clients_service.js +5 -4
- package/build/src/host/admin_console/admin_shell_controller.js +4 -2
- package/build/src/host/admin_console/console_audit_controller.js +1 -1
- package/build/src/host/admin_console/console_clients_controller.js +5 -3
- package/build/src/host/admin_console/console_impersonation_controller.js +1 -1
- package/build/src/host/admin_console/console_keys_controller.js +2 -4
- package/build/src/host/admin_console/console_orgs_controller.js +3 -3
- package/build/src/host/admin_console/console_roles_controller.js +30 -12
- package/build/src/host/admin_console/console_sessions_controller.js +3 -3
- package/build/src/host/admin_console/console_settings_controller.js +11 -5
- package/build/src/host/admin_console/console_users_controller.d.ts +2 -2
- package/build/src/host/admin_console/console_users_controller.js +46 -47
- package/build/src/host/admin_prefix.js +2 -2
- package/build/src/host/admin_sessions_service.d.ts +3 -1
- package/build/src/host/admin_sessions_service.js +36 -6
- package/build/src/host/adonis_auth_sync.d.ts +1 -1
- package/build/src/host/adonis_auth_user_provider.d.ts +1 -1
- package/build/src/host/app_key.js +1 -1
- package/build/src/host/avatar_storage.js +1 -3
- package/build/src/host/config_locks.js +1 -3
- package/build/src/host/console_session.d.ts +4 -0
- package/build/src/host/console_session.js +9 -2
- package/build/src/host/controllers/account_apps_controller.js +3 -2
- package/build/src/host/controllers/account_confirm_controller.js +2 -6
- package/build/src/host/controllers/account_mfa_controller.js +63 -12
- package/build/src/host/controllers/account_orgs_controller.js +53 -30
- package/build/src/host/controllers/account_security_controller.d.ts +2 -2
- package/build/src/host/controllers/account_security_controller.js +116 -116
- package/build/src/host/controllers/account_session_controller.js +7 -5
- package/build/src/host/controllers/account_tokens_controller.js +14 -2
- package/build/src/host/controllers/interaction_controller.js +59 -22
- package/build/src/host/controllers/pat_introspection_controller.js +10 -0
- package/build/src/host/controllers/registration_controller.js +28 -13
- package/build/src/host/default_mailer.js +11 -7
- package/build/src/host/durable/account_deletion_workflow.d.ts +2 -2
- package/build/src/host/durable/account_deletion_workflow.js +14 -14
- package/build/src/host/durable/account_export_workflow.d.ts +2 -2
- package/build/src/host/durable/account_export_workflow.js +12 -12
- package/build/src/host/durable/index.d.ts +5 -5
- package/build/src/host/durable/index.js +6 -6
- package/build/src/host/i18n.d.ts +1376 -1376
- package/build/src/host/i18n.js +1380 -1380
- package/build/src/host/impersonation.js +1 -7
- package/build/src/host/key_rotation_actions.d.ts +1 -1
- package/build/src/host/login_attempt.js +35 -6
- package/build/src/host/login_notify.js +1 -1
- package/build/src/host/middleware/account_auth.js +3 -1
- package/build/src/host/otp_lockout.js +1 -3
- package/build/src/host/rate_limit.js +1 -1
- package/build/src/host/register_auth_host.d.ts +96 -2
- package/build/src/host/register_auth_host.js +196 -91
- package/build/src/host/renderers/edge_renderer.js +19 -1
- package/build/src/host/renderers/inertia_renderer.d.ts +63 -0
- package/build/src/host/renderers/inertia_renderer.js +63 -0
- package/build/src/host/runtime_settings.js +1 -1
- package/build/src/host/runtime_toggles.d.ts +3 -3
- package/build/src/host/runtime_toggles.js +69 -24
- package/build/src/host/security_notice_service.d.ts +1 -1
- package/build/src/host/security_notice_service.js +1 -1
- package/build/src/host/session_context.js +1 -1
- package/build/src/host/sudo/index.d.ts +3 -3
- package/build/src/host/sudo/index.js +3 -3
- package/build/src/host/sudo/methods/magic_link.js +6 -5
- package/build/src/host/sudo/methods/passkey.js +7 -4
- package/build/src/host/sudo/methods/password.js +8 -3
- package/build/src/host/sudo/runtime.js +6 -13
- package/build/src/host/sudo_mode.js +3 -2
- package/build/src/host/ui-dist/assets/index-BQoTDiLV.js +137 -0
- package/build/src/host/ui-dist/index.html +1 -1
- package/build/src/keys/jwks_manager.js +1 -1
- package/build/src/keys/keystore.js +1 -1
- package/build/src/keys/keystore_manager.d.ts +2 -2
- package/build/src/keys/keystore_manager.js +2 -2
- package/build/src/keys/keystore_vault.js +8 -4
- package/build/src/mixins/with_audit_log.d.ts +1 -1
- package/build/src/mixins/with_auth_user.d.ts +1 -1
- package/build/src/mixins/with_auth_user.js +1 -1
- package/build/src/mixins/with_credentials.d.ts +1 -1
- package/build/src/mixins/with_mfa.d.ts +1 -1
- package/build/src/mixins/with_personal_access_token.d.ts +1 -1
- package/build/src/mixins/with_provider_identity.d.ts +1 -1
- package/build/src/mixins/with_webauthn_credential.d.ts +1 -1
- package/build/src/observability/diagnostics_bridge.js +2 -2
- package/build/src/observability/metrics_service.js +1 -1
- package/build/src/observability/telescope/data_providers.d.ts +1 -1
- package/build/src/observability/telescope/data_providers.js +29 -43
- package/build/src/observability/telescope/extension.d.ts +1 -1
- package/build/src/observability/telescope/extension.js +58 -58
- package/build/src/observability/telescope/index.d.ts +2 -2
- package/build/src/observability/telescope/index.js +2 -2
- package/build/src/observability/wire_provider_events.d.ts +1 -1
- package/build/src/observability/wire_provider_events.js +11 -11
- package/build/src/password/common_passwords.js +1 -1
- package/build/src/password/password_manager.d.ts +1 -1
- package/build/src/password/password_manager.js +4 -4
- package/build/src/pat/lucid_pat_store.js +2 -6
- package/build/src/pat/pat_tokens.js +1 -1
- package/build/src/provider/interaction_actions.js +1 -1
- package/build/src/provider/key_rotation_scheduler.js +3 -1
- package/build/src/provider/logout_sources.js +2 -8
- package/build/src/provider/oidc_service.d.ts +2 -2
- package/build/src/provider/oidc_service.js +22 -14
- package/build/src/provider/single_flight_lock.js +1 -3
- package/build/src/provider/token_exchange.d.ts +1 -1
- package/build/src/schema/ensure.js +3 -1
- package/build/stubs/ui/react/components/auth_shell.tsx +19 -19
- package/build/stubs/ui/react/pages/account/login.tsx +6 -7
- package/build/stubs/ui/react/pages/account/mfa.tsx +16 -15
- package/build/stubs/ui/react/pages/account/tokens.tsx +27 -17
- package/build/stubs/ui/react/pages/consent.tsx +12 -12
- package/build/stubs/ui/react/pages/forgot.tsx +7 -7
- package/build/stubs/ui/react/pages/login.tsx +22 -24
- package/build/stubs/ui/react/pages/mfa-challenge.tsx +9 -10
- package/build/stubs/ui/react/pages/reset.tsx +10 -10
- package/build/stubs/ui/react/pages/signup.tsx +30 -16
- package/build/stubs/ui/react/pages/verify-email.tsx +6 -6
- package/package.json +1 -1
- package/stubs/main.ts +2 -2
- package/stubs/ui/react/components/auth_shell.tsx +19 -19
- package/stubs/ui/react/pages/account/login.tsx +6 -7
- package/stubs/ui/react/pages/account/mfa.tsx +16 -15
- package/stubs/ui/react/pages/account/tokens.tsx +27 -17
- package/stubs/ui/react/pages/consent.tsx +12 -12
- package/stubs/ui/react/pages/forgot.tsx +7 -7
- package/stubs/ui/react/pages/login.tsx +22 -24
- package/stubs/ui/react/pages/mfa-challenge.tsx +9 -10
- package/stubs/ui/react/pages/reset.tsx +10 -10
- package/stubs/ui/react/pages/signup.tsx +30 -16
- package/stubs/ui/react/pages/verify-email.tsx +6 -6
- package/build/src/host/ui-dist/assets/index-BmI_J87g.js +0 -137
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { configProvider } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
1
|
+
import { configProvider } from '@adonisjs/core';
|
|
2
|
+
import { adapters } from './adapters/factory.js';
|
|
3
|
+
import { composeAuditSink, resolveEvents } from './events/dispatcher.js';
|
|
4
|
+
import { resolveBotProtection, } from './host/bot_protection.js';
|
|
5
|
+
import { deriveLockedSettingKeys } from './host/config_locks.js';
|
|
6
|
+
import { resolveMessages } from './host/i18n.js';
|
|
7
|
+
import { edgeRenderer } from './host/renderers/edge_renderer.js';
|
|
8
|
+
import { resolveTrustedDevices, } from './host/trusted_device.js';
|
|
9
|
+
import { generateJwks } from './keys/jwks_manager.js';
|
|
10
|
+
import { KeystoreCodec } from './keys/keystore_codec.js';
|
|
11
|
+
import { loadEncryptionService } from './keys/keystore_crypto.js';
|
|
12
|
+
import { KeystoreManager, resolveKeystoreVault } from './keys/keystore_manager.js';
|
|
13
13
|
export { adapters };
|
|
14
14
|
const RATE_LIMIT_DEFAULTS = {
|
|
15
|
-
login: { points: 10, duration:
|
|
16
|
-
introspection: { points: 60, duration:
|
|
17
|
-
adminIp: { points: 30, duration:
|
|
15
|
+
login: { points: 10, duration: '1 min' },
|
|
16
|
+
introspection: { points: 60, duration: '1 min' },
|
|
17
|
+
adminIp: { points: 30, duration: '1 min' },
|
|
18
18
|
// Mesmos limites do login, bucket separado — ver `ResolvedRateLimitConfig.sudo`.
|
|
19
|
-
sudo: { points: 10, duration:
|
|
19
|
+
sudo: { points: 10, duration: '1 min' },
|
|
20
20
|
};
|
|
21
21
|
export function resolveRateLimit(input) {
|
|
22
22
|
const enabled = input?.enabled ?? true;
|
|
@@ -54,9 +54,9 @@ export function resolveDynamicRegistration(input) {
|
|
|
54
54
|
const enabled = input?.enabled ?? false;
|
|
55
55
|
const management = input?.management ?? false;
|
|
56
56
|
if (management && !enabled) {
|
|
57
|
-
throw new Error(
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
throw new Error('authkit: dynamicRegistration.management (RFC 7592) requer ' +
|
|
58
|
+
'dynamicRegistration.enabled: true (RFC 7591). Habilite o registro dinâmico ' +
|
|
59
|
+
'ou desligue o management.');
|
|
60
60
|
}
|
|
61
61
|
return {
|
|
62
62
|
enabled,
|
|
@@ -70,11 +70,11 @@ export function resolveDeviceFlow(input) {
|
|
|
70
70
|
export function resolveUploads(input) {
|
|
71
71
|
return {
|
|
72
72
|
avatars: {
|
|
73
|
-
storage: input?.avatars?.storage ??
|
|
73
|
+
storage: input?.avatars?.storage ?? 'auto',
|
|
74
74
|
disk: input?.avatars?.disk,
|
|
75
|
-
directory: input?.avatars?.directory ??
|
|
76
|
-
collection: input?.avatars?.collection ??
|
|
77
|
-
ownerType: input?.avatars?.ownerType ??
|
|
75
|
+
directory: input?.avatars?.directory ?? 'authkit/avatars',
|
|
76
|
+
collection: input?.avatars?.collection ?? 'avatar',
|
|
77
|
+
ownerType: input?.avatars?.ownerType ?? 'AuthAccount',
|
|
78
78
|
maxSizeMb: input?.avatars?.maxSizeMb ?? 5,
|
|
79
79
|
},
|
|
80
80
|
};
|
|
@@ -89,7 +89,7 @@ export function resolvePar(input) {
|
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
export function resolveStepUp(input) {
|
|
92
|
-
const mfaAcr = input?.mfaAcr ??
|
|
92
|
+
const mfaAcr = input?.mfaAcr ?? 'urn:authkit:mfa';
|
|
93
93
|
// Garante que o mfaAcr esteja sempre na lista anunciada como suportada.
|
|
94
94
|
const acrValues = Array.from(new Set([...(input?.acrValues ?? []), mfaAcr]));
|
|
95
95
|
return { acrValues, mfaAcr };
|
|
@@ -106,13 +106,13 @@ export function resolveAuthMethodsConfig(input) {
|
|
|
106
106
|
if (!input)
|
|
107
107
|
return {};
|
|
108
108
|
const out = {};
|
|
109
|
-
if (typeof input.password ===
|
|
109
|
+
if (typeof input.password === 'boolean')
|
|
110
110
|
out.password = input.password;
|
|
111
|
-
if (typeof input.magicLink ===
|
|
111
|
+
if (typeof input.magicLink === 'boolean')
|
|
112
112
|
out.magicLink = input.magicLink;
|
|
113
|
-
if (typeof input.passkey ===
|
|
113
|
+
if (typeof input.passkey === 'boolean')
|
|
114
114
|
out.passkey = input.passkey;
|
|
115
|
-
if (typeof input.forgotPassword ===
|
|
115
|
+
if (typeof input.forgotPassword === 'boolean')
|
|
116
116
|
out.forgotPassword = input.forgotPassword;
|
|
117
117
|
return out;
|
|
118
118
|
}
|
|
@@ -134,7 +134,7 @@ export function resolveRegistration(input) {
|
|
|
134
134
|
* herda o `format` raiz quando não especifica o seu.
|
|
135
135
|
*/
|
|
136
136
|
export function resolveAccessTokens(issuer, input) {
|
|
137
|
-
const format = input?.format ??
|
|
137
|
+
const format = input?.format ?? 'opaque';
|
|
138
138
|
const audience = input?.audience ?? issuer;
|
|
139
139
|
const resources = {};
|
|
140
140
|
for (const [indicator, rc] of Object.entries(input?.resources ?? {})) {
|
|
@@ -145,26 +145,26 @@ export function resolveAccessTokens(issuer, input) {
|
|
|
145
145
|
expiresIn: rc.expiresIn,
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
|
-
const anyResourceJwt = Object.values(resources).some((r) => r.format ===
|
|
149
|
-
const anyJwt = format ===
|
|
148
|
+
const anyResourceJwt = Object.values(resources).some((r) => r.format === 'jwt');
|
|
149
|
+
const anyJwt = format === 'jwt' || anyResourceJwt;
|
|
150
150
|
return { format, audience, anyJwt, resources };
|
|
151
151
|
}
|
|
152
152
|
export function resolveAdmin(input) {
|
|
153
153
|
return {
|
|
154
154
|
enabled: input?.enabled ?? false,
|
|
155
|
-
roles: input?.roles && input.roles.length > 0 ? input.roles : [
|
|
155
|
+
roles: input?.roles && input.roles.length > 0 ? input.roles : ['ADMIN'],
|
|
156
156
|
impersonation: false,
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
159
|
/** Lê API keys de `AUTHKIT_ADMIN_API_KEY` (uma ou várias, separadas por vírgula). */
|
|
160
160
|
function adminApiKeysFromEnv() {
|
|
161
|
-
return (process.env.AUTHKIT_ADMIN_API_KEY ??
|
|
162
|
-
.split(
|
|
161
|
+
return (process.env.AUTHKIT_ADMIN_API_KEY ?? '')
|
|
162
|
+
.split(',')
|
|
163
163
|
.map((key) => key.trim())
|
|
164
164
|
.filter(Boolean);
|
|
165
165
|
}
|
|
166
166
|
export function resolveAdminApi(input) {
|
|
167
|
-
const apiKeys = input?.apiKeys ===
|
|
167
|
+
const apiKeys = input?.apiKeys === 'env' ? adminApiKeysFromEnv() : (input?.apiKeys ?? []);
|
|
168
168
|
return {
|
|
169
169
|
// Default inteligente: liga quando há key resolvida (a menos que enabled:false explícito).
|
|
170
170
|
enabled: input?.enabled ?? apiKeys.length > 0,
|
|
@@ -174,10 +174,10 @@ export function resolveAdminApi(input) {
|
|
|
174
174
|
export function resolveOrganizations(input) {
|
|
175
175
|
return {
|
|
176
176
|
enabled: input?.enabled,
|
|
177
|
-
roles: [
|
|
177
|
+
roles: ['owner', 'admin', 'member'],
|
|
178
178
|
allowSelfCreate: false,
|
|
179
179
|
invitationTtlHours: 168,
|
|
180
|
-
claimStrategy: input?.claimStrategy ??
|
|
180
|
+
claimStrategy: input?.claimStrategy ?? 'active',
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
/**
|
|
@@ -185,8 +185,8 @@ export function resolveOrganizations(input) {
|
|
|
185
185
|
* `rpName` cai no `fallbackName` (branding/mfaIssuer) quando ausente.
|
|
186
186
|
*/
|
|
187
187
|
export function resolveWebauthn(issuer, fallbackName, input) {
|
|
188
|
-
let host =
|
|
189
|
-
let origin =
|
|
188
|
+
let host = 'localhost';
|
|
189
|
+
let origin = 'http://localhost';
|
|
190
190
|
try {
|
|
191
191
|
const url = new URL(issuer);
|
|
192
192
|
host = url.hostname;
|
|
@@ -205,7 +205,7 @@ const UNITS = { s: 1, m: 60, h: 3600, d: 86400 };
|
|
|
205
205
|
export function toSeconds(value, fallback) {
|
|
206
206
|
if (value === undefined)
|
|
207
207
|
return fallback;
|
|
208
|
-
if (typeof value ===
|
|
208
|
+
if (typeof value === 'number')
|
|
209
209
|
return value;
|
|
210
210
|
const m = /^(\d+)\s*([smhd])$/.exec(value.trim());
|
|
211
211
|
if (!m)
|
|
@@ -219,9 +219,9 @@ export function toSeconds(value, fallback) {
|
|
|
219
219
|
* internamente — encrypt OFF para não duplo-encriptar.
|
|
220
220
|
*/
|
|
221
221
|
export function defaultEncryptForStore(store) {
|
|
222
|
-
if (typeof store ===
|
|
222
|
+
if (typeof store === 'string')
|
|
223
223
|
return true;
|
|
224
|
-
return [
|
|
224
|
+
return ['file', 'drive', 'lucid', 'redis'].includes(store.driver);
|
|
225
225
|
}
|
|
226
226
|
/**
|
|
227
227
|
* Mensagem de aviso quando `jwks: 'auto'` cai no fallback de disco (sem
|
|
@@ -230,55 +230,52 @@ export function defaultEncryptForStore(store) {
|
|
|
230
230
|
export function jwksAutoFallbackWarning(storePath) {
|
|
231
231
|
if (!storePath)
|
|
232
232
|
return null;
|
|
233
|
-
return
|
|
234
|
-
`assinatura será persistida em arquivo. Para produção, defina AUTHKIT_JWKS ` +
|
|
235
|
-
`(secret manager) ou configure jwks.store explicitamente.`);
|
|
233
|
+
return `AuthKit: jwks 'auto' caiu no fallback de disco (${storePath}) — a chave privada de assinatura será persistida em arquivo. Para produção, defina AUTHKIT_JWKS (secret manager) ou configure jwks.store explicitamente.`;
|
|
236
234
|
}
|
|
237
235
|
export function defineConfig(config) {
|
|
238
236
|
return configProvider.create(async (app) => {
|
|
239
237
|
const AdapterClass = await config.adapter.resolver(app);
|
|
240
238
|
// `jwks: 'auto'` → resolve env-aware: AUTHKIT_JWKS inline, senão managed em arquivo.
|
|
241
|
-
const jwksConfig = config.jwks ===
|
|
239
|
+
const jwksConfig = config.jwks === 'auto'
|
|
242
240
|
? process.env.AUTHKIT_JWKS
|
|
243
241
|
? {
|
|
244
|
-
source:
|
|
242
|
+
source: 'jwks',
|
|
245
243
|
keys: JSON.parse(process.env.AUTHKIT_JWKS).keys,
|
|
246
244
|
}
|
|
247
245
|
: {
|
|
248
|
-
source:
|
|
249
|
-
algorithm:
|
|
250
|
-
store:
|
|
246
|
+
source: 'managed',
|
|
247
|
+
algorithm: 'RS256',
|
|
248
|
+
store: 'tmp/authkit_jwks.json',
|
|
251
249
|
}
|
|
252
250
|
: config.jwks;
|
|
253
|
-
if (config.jwks ===
|
|
251
|
+
if (config.jwks === 'auto' && !process.env.AUTHKIT_JWKS) {
|
|
254
252
|
const warning = jwksAutoFallbackWarning(jwksConfig.store ?? null);
|
|
255
253
|
if (warning) {
|
|
256
254
|
await app.container
|
|
257
|
-
.make(
|
|
255
|
+
.make('logger')
|
|
258
256
|
.then((l) => l?.warn(warning))
|
|
259
257
|
.catch(() => { });
|
|
260
258
|
}
|
|
261
259
|
}
|
|
262
260
|
const storeCfg = jwksConfig.store;
|
|
263
|
-
if (jwksConfig.source ===
|
|
261
|
+
if (jwksConfig.source === 'managed' &&
|
|
264
262
|
storeCfg &&
|
|
265
|
-
typeof storeCfg ===
|
|
266
|
-
storeCfg.driver ===
|
|
263
|
+
typeof storeCfg === 'object' &&
|
|
264
|
+
storeCfg.driver === 'redis') {
|
|
267
265
|
await app.container
|
|
268
|
-
.make(
|
|
266
|
+
.make('logger')
|
|
269
267
|
.then((l) => l?.warn('AuthKit: keystore no driver "redis" — garanta PERSISTÊNCIA (RDB/AOF). Num Redis cache-only, um flush apaga o keystore e invalida todos os tokens.'))
|
|
270
268
|
.catch(() => { });
|
|
271
269
|
}
|
|
272
270
|
let jwks;
|
|
273
|
-
if (jwksConfig.source ===
|
|
274
|
-
const alg = jwksConfig.algorithm ??
|
|
271
|
+
if (jwksConfig.source === 'managed') {
|
|
272
|
+
const alg = jwksConfig.algorithm ?? 'RS256';
|
|
275
273
|
if (jwksConfig.store) {
|
|
276
274
|
const vault = resolveKeystoreVault(jwksConfig.store, {
|
|
277
275
|
makePath: (p) => app.makePath(p),
|
|
278
276
|
container: app.container,
|
|
279
277
|
});
|
|
280
|
-
const encrypt = jwksConfig.encrypt ??
|
|
281
|
-
defaultEncryptForStore(jwksConfig.store);
|
|
278
|
+
const encrypt = jwksConfig.encrypt ?? defaultEncryptForStore(jwksConfig.store);
|
|
282
279
|
const enc = encrypt ? await loadEncryptionService() : undefined;
|
|
283
280
|
const manager = new KeystoreManager(vault, new KeystoreCodec({ encrypt, enc }), alg);
|
|
284
281
|
const store = await manager.ensure();
|
|
@@ -295,7 +292,7 @@ export function defineConfig(config) {
|
|
|
295
292
|
// #9: mfaIssuer efetivo — top-level do defineConfig vence; senão o do lucidAccountStore; senão default.
|
|
296
293
|
const effectiveMfaIssuer = config.mfaIssuer ??
|
|
297
294
|
config.accountStore?.__mfaIssuer ??
|
|
298
|
-
|
|
295
|
+
'AuthKit';
|
|
299
296
|
return {
|
|
300
297
|
issuer: config.issuer,
|
|
301
298
|
AdapterClass,
|
|
@@ -308,7 +305,7 @@ export function defineConfig(config) {
|
|
|
308
305
|
idToken: toSeconds(config.ttl?.idToken, 900),
|
|
309
306
|
session: toSeconds(config.ttl?.session, 604800),
|
|
310
307
|
},
|
|
311
|
-
globalRolesClaim: config.globalRolesClaim ??
|
|
308
|
+
globalRolesClaim: config.globalRolesClaim ?? 'roles',
|
|
312
309
|
resolveTokenRoles: config.resolveTokenRoles,
|
|
313
310
|
cookieKeys: config.cookieKeys ?? [],
|
|
314
311
|
observability: config.observability ?? {},
|
|
@@ -319,7 +316,7 @@ export function defineConfig(config) {
|
|
|
319
316
|
},
|
|
320
317
|
accountStore: config.accountStore,
|
|
321
318
|
patStore: config.patStore,
|
|
322
|
-
mountPath: config.mountPath ??
|
|
319
|
+
mountPath: config.mountPath ?? '/oidc',
|
|
323
320
|
accountHome: config.accountHome,
|
|
324
321
|
// Default de runtime: sem isso, `render` ficava `undefined` e TODA
|
|
325
322
|
// request a `/account/*`/`/auth/interaction/*` estourava um 500 sem
|
|
@@ -350,9 +347,7 @@ export function defineConfig(config) {
|
|
|
350
347
|
// #9: reusa mfaIssuer/webauthn declarados no lucidAccountStore quando o
|
|
351
348
|
// top-level não os fornece — consumidor declara UMA vez. Top-level ainda vence.
|
|
352
349
|
mfaIssuer: effectiveMfaIssuer,
|
|
353
|
-
webauthn: resolveWebauthn(config.issuer, effectiveMfaIssuer, config.webauthn ??
|
|
354
|
-
config.accountStore
|
|
355
|
-
?.__webauthn),
|
|
350
|
+
webauthn: resolveWebauthn(config.issuer, effectiveMfaIssuer, config.webauthn ?? config.accountStore?.__webauthn),
|
|
356
351
|
dynamicRegistration: resolveDynamicRegistration(config.dynamicRegistration),
|
|
357
352
|
deviceFlow: resolveDeviceFlow(config.deviceFlow),
|
|
358
353
|
uploads: resolveUploads(config.uploads),
|
|
@@ -371,7 +366,7 @@ export function defineConfig(config) {
|
|
|
371
366
|
organizations: resolveOrganizations(config.organizations),
|
|
372
367
|
resolveGeo: config.resolveGeo,
|
|
373
368
|
messages: resolveMessages(config.i18n),
|
|
374
|
-
locale: config.i18n?.locale ??
|
|
369
|
+
locale: config.i18n?.locale ?? 'pt-BR',
|
|
375
370
|
schema: {
|
|
376
371
|
autoManage: config.schema?.autoManage !== false,
|
|
377
372
|
connection: config.schema?.connection,
|
|
@@ -35,7 +35,9 @@ export function checkIssuer(input) {
|
|
|
35
35
|
catch {
|
|
36
36
|
return [{ level: 'error', message: `issuer is not a valid URL: "${issuer}".` }];
|
|
37
37
|
}
|
|
38
|
-
const findings = [
|
|
38
|
+
const findings = [
|
|
39
|
+
{ level: 'ok', message: `valid issuer: ${url.origin}${url.pathname}` },
|
|
40
|
+
];
|
|
39
41
|
const normalize = (p) => (p.endsWith('/') ? p.slice(0, -1) : p) || '/';
|
|
40
42
|
if (normalize(url.pathname) !== normalize(mountPath)) {
|
|
41
43
|
findings.push({
|
|
@@ -143,7 +145,12 @@ export function checkSession(input) {
|
|
|
143
145
|
];
|
|
144
146
|
}
|
|
145
147
|
if (!input.sessionConfig) {
|
|
146
|
-
return [
|
|
148
|
+
return [
|
|
149
|
+
{
|
|
150
|
+
level: 'warn',
|
|
151
|
+
message: "config('session') missing — the session provider may not be configured.",
|
|
152
|
+
},
|
|
153
|
+
];
|
|
147
154
|
}
|
|
148
155
|
const findings = [{ level: 'ok', message: 'session provider configured.' }];
|
|
149
156
|
const driver = input.sessionConfig.store ?? input.sessionConfig.driver;
|
|
@@ -158,7 +165,10 @@ export function checkSession(input) {
|
|
|
158
165
|
/** Hint de exceções de CSRF do shield para o mountPath. */
|
|
159
166
|
export function checkShield(input) {
|
|
160
167
|
if (!input.peers.shield) {
|
|
161
|
-
return {
|
|
168
|
+
return {
|
|
169
|
+
level: 'error',
|
|
170
|
+
message: '@adonisjs/shield is not importable — install it (required peer).',
|
|
171
|
+
};
|
|
162
172
|
}
|
|
163
173
|
const mountPath = input.authkitConfig?.mountPath ?? '/oidc';
|
|
164
174
|
return {
|
|
@@ -169,12 +179,18 @@ export function checkShield(input) {
|
|
|
169
179
|
/** ally só é necessário quando social está configurado. */
|
|
170
180
|
export function checkAlly(input) {
|
|
171
181
|
const social = input.authkitConfig?.social;
|
|
172
|
-
const usesSocial = !!social &&
|
|
182
|
+
const usesSocial = !!social &&
|
|
183
|
+
(Array.isArray(social.providers)
|
|
184
|
+
? social.providers.length > 0
|
|
185
|
+
: Object.keys(social).length > 0);
|
|
173
186
|
if (!usesSocial) {
|
|
174
187
|
return { level: 'ok', message: 'social login not configured — @adonisjs/ally is optional.' };
|
|
175
188
|
}
|
|
176
189
|
if (!input.peers.ally) {
|
|
177
|
-
return {
|
|
190
|
+
return {
|
|
191
|
+
level: 'error',
|
|
192
|
+
message: 'social login configured, but @adonisjs/ally is not importable.',
|
|
193
|
+
};
|
|
178
194
|
}
|
|
179
195
|
return { level: 'ok', message: 'social login configured and @adonisjs/ally available.' };
|
|
180
196
|
}
|
|
@@ -198,7 +214,10 @@ export function checkOtpLockout(input) {
|
|
|
198
214
|
* no console de conta). Apenas informa o estado.
|
|
199
215
|
*/
|
|
200
216
|
export function checkSudoMode(_input) {
|
|
201
|
-
return {
|
|
217
|
+
return {
|
|
218
|
+
level: 'ok',
|
|
219
|
+
message: 'sudo_mode: enabled by default (15 min grace). Configure via admin settings or sudo_mode runtime setting.',
|
|
220
|
+
};
|
|
202
221
|
}
|
|
203
222
|
/** rateLimit ligado mas @adonisjs/limiter ausente → warn. */
|
|
204
223
|
export function checkRateLimit(input) {
|
|
@@ -246,7 +265,10 @@ export function checkRequireVerifiedEmail(input) {
|
|
|
246
265
|
message: 'login.requireVerifiedEmail is on, but the accountStore has no `isEmailVerified` capability — the check is a no-op (nobody is blocked). Add an `email_verified_at` column (or a store that tracks it).',
|
|
247
266
|
};
|
|
248
267
|
}
|
|
249
|
-
return {
|
|
268
|
+
return {
|
|
269
|
+
level: 'ok',
|
|
270
|
+
message: 'login.requireVerifiedEmail on and the accountStore can check it.',
|
|
271
|
+
};
|
|
250
272
|
}
|
|
251
273
|
/**
|
|
252
274
|
* Bot protection (informativo): ativo quando `botProtection.verify` é uma função.
|
|
@@ -362,9 +384,13 @@ export function checkAccessTokens(input) {
|
|
|
362
384
|
return null;
|
|
363
385
|
const resources = at.resources ?? {};
|
|
364
386
|
const resourceCount = Object.keys(resources).length;
|
|
365
|
-
const anyJwt = at.anyJwt ??
|
|
387
|
+
const anyJwt = at.anyJwt ??
|
|
388
|
+
(at.format === 'jwt' || Object.values(resources).some((r) => r?.format === 'jwt'));
|
|
366
389
|
if (!anyJwt) {
|
|
367
|
-
return {
|
|
390
|
+
return {
|
|
391
|
+
level: 'ok',
|
|
392
|
+
message: 'access tokens are opaque (default) — introspect them at the introspection endpoint.',
|
|
393
|
+
};
|
|
368
394
|
}
|
|
369
395
|
const detail = resourceCount
|
|
370
396
|
? `format=${at.format}, ${resourceCount} resource(s) configured`
|
|
@@ -474,7 +500,8 @@ export function checkAuthMethodsSetting(input) {
|
|
|
474
500
|
const allOff = s.password === false &&
|
|
475
501
|
s.magicLink === false &&
|
|
476
502
|
s.passkey === false &&
|
|
477
|
-
Array.isArray(s.social) &&
|
|
503
|
+
Array.isArray(s.social) &&
|
|
504
|
+
s.social.length === 0;
|
|
478
505
|
if (allOff) {
|
|
479
506
|
return {
|
|
480
507
|
level: 'warn',
|
|
@@ -489,9 +516,7 @@ export function checkAuthMethodsSetting(input) {
|
|
|
489
516
|
if (unknown.length > 0) {
|
|
490
517
|
return {
|
|
491
518
|
level: 'warn',
|
|
492
|
-
message: `auth_methods setting references social provider(s) not in config.social.providers: [${unknown.join(', ')}].
|
|
493
|
-
'These providers will be silently filtered out (intersection rule). ' +
|
|
494
|
-
'Remove them from the setting or add them to config.social.providers.',
|
|
519
|
+
message: `auth_methods setting references social provider(s) not in config.social.providers: [${unknown.join(', ')}]. These providers will be silently filtered out (intersection rule). Remove them from the setting or add them to config.social.providers.`,
|
|
495
520
|
};
|
|
496
521
|
}
|
|
497
522
|
}
|
|
@@ -567,8 +592,7 @@ export function checkPasswordPepper(input) {
|
|
|
567
592
|
if (Array.isArray(pepper)) {
|
|
568
593
|
return {
|
|
569
594
|
level: 'ok',
|
|
570
|
-
message: `password.pepper rotation configured (${pepper.length} pepper(s)).
|
|
571
|
-
'First pepper is current; subsequent peppers are tried on verify (lazy re-hash).',
|
|
595
|
+
message: `password.pepper rotation configured (${pepper.length} pepper(s)). First pepper is current; subsequent peppers are tried on verify (lazy re-hash).`,
|
|
572
596
|
};
|
|
573
597
|
}
|
|
574
598
|
return null;
|
|
@@ -654,8 +678,7 @@ export function checkSessionPolicy(input) {
|
|
|
654
678
|
if (idleMin > 0 && defaultHours > 0 && idleMin > defaultHours * 60) {
|
|
655
679
|
return {
|
|
656
680
|
level: 'warn',
|
|
657
|
-
message: `session_policy: idleTimeoutMinutes (${idleMin}) exceeds defaultSessionHours*60 (${defaultHours * 60}).
|
|
658
|
-
'The idle timeout will never trigger — increase defaultSessionHours or reduce idleTimeoutMinutes.',
|
|
681
|
+
message: `session_policy: idleTimeoutMinutes (${idleMin}) exceeds defaultSessionHours*60 (${defaultHours * 60}). The idle timeout will never trigger — increase defaultSessionHours or reduce idleTimeoutMinutes.`,
|
|
659
682
|
};
|
|
660
683
|
}
|
|
661
684
|
if (rememberDays > 365) {
|
|
@@ -701,8 +724,7 @@ export function checkRolesCatalog(input) {
|
|
|
701
724
|
if (outOfCatalog.length > 0) {
|
|
702
725
|
return {
|
|
703
726
|
level: 'warn',
|
|
704
|
-
message: `roles_catalog: ${catalogRoles.length} role(s) in catalog, but cfg.admin.roles references [${outOfCatalog.join(', ')}] which are not in the catalog.
|
|
705
|
-
'Admin access depends on these roles — add them to the catalog at /admin/roles.',
|
|
727
|
+
message: `roles_catalog: ${catalogRoles.length} role(s) in catalog, but cfg.admin.roles references [${outOfCatalog.join(', ')}] which are not in the catalog. Admin access depends on these roles — add them to the catalog at /admin/roles.`,
|
|
706
728
|
};
|
|
707
729
|
}
|
|
708
730
|
return {
|
|
@@ -764,7 +786,10 @@ export function checkPasskeyAutofill(input) {
|
|
|
764
786
|
*/
|
|
765
787
|
export function signingKeyAgeFinding(ageDays, maxAgeDays) {
|
|
766
788
|
if (ageDays === null)
|
|
767
|
-
return {
|
|
789
|
+
return {
|
|
790
|
+
level: 'ok',
|
|
791
|
+
message: 'jwks: idade da chave não aplicável (sem keystore persistido).',
|
|
792
|
+
};
|
|
768
793
|
if (ageDays > maxAgeDays) {
|
|
769
794
|
return {
|
|
770
795
|
level: 'warn',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createHmac } from
|
|
2
|
-
import { emitDiagnostic } from
|
|
1
|
+
import { createHmac } from 'node:crypto';
|
|
2
|
+
import { emitDiagnostic } from '../observability/diagnostics_bridge.js';
|
|
3
3
|
export function resolveEvents(input) {
|
|
4
4
|
if (!input || (!input.onEvent && !input.webhook))
|
|
5
5
|
return undefined;
|
|
@@ -27,7 +27,7 @@ export function buildWebhookBody(event) {
|
|
|
27
27
|
}
|
|
28
28
|
/** Calcula o header de assinatura `sha256=<hmac>` para um corpo + segredo. */
|
|
29
29
|
export function signWebhookBody(body, secret) {
|
|
30
|
-
return
|
|
30
|
+
return `sha256=${createHmac('sha256', secret).update(body).digest('hex')}`;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Projeta um {@link AuditEvent} para o barramento `@agora/diagnostics` SEM PII
|
|
@@ -75,13 +75,13 @@ async function dispatchWebhook(webhook, event) {
|
|
|
75
75
|
try {
|
|
76
76
|
const body = buildWebhookBody(event);
|
|
77
77
|
const headers = {
|
|
78
|
-
|
|
78
|
+
'content-type': 'application/json',
|
|
79
79
|
};
|
|
80
80
|
if (webhook.secret) {
|
|
81
|
-
headers[
|
|
81
|
+
headers['x-authkit-signature'] = signWebhookBody(body, webhook.secret);
|
|
82
82
|
}
|
|
83
83
|
await fetch(webhook.url, {
|
|
84
|
-
method:
|
|
84
|
+
method: 'POST',
|
|
85
85
|
headers,
|
|
86
86
|
body,
|
|
87
87
|
signal: AbortSignal.timeout(WEBHOOK_TIMEOUT_MS),
|
|
@@ -131,11 +131,11 @@ export function composeAuditSink(original, events = {}) {
|
|
|
131
131
|
},
|
|
132
132
|
};
|
|
133
133
|
// Preserva a capacidade de consulta do sink original (console admin).
|
|
134
|
-
if (original && typeof original.list ===
|
|
134
|
+
if (original && typeof original.list === 'function') {
|
|
135
135
|
composed.list = original.list.bind(original);
|
|
136
136
|
}
|
|
137
137
|
// Preserva a anonimização (LGPD) do sink original (deleção de conta).
|
|
138
|
-
if (original && typeof original.anonymizeAccount ===
|
|
138
|
+
if (original && typeof original.anonymizeAccount === 'function') {
|
|
139
139
|
composed.anonymizeAccount = original.anonymizeAccount.bind(original);
|
|
140
140
|
}
|
|
141
141
|
// Preserva quaisquer propriedades extras do sink original (ex.: campos de
|
|
@@ -147,10 +147,10 @@ export function composeAuditSink(original, events = {}) {
|
|
|
147
147
|
const src = original;
|
|
148
148
|
const dst = composed;
|
|
149
149
|
for (const key of Object.keys(src)) {
|
|
150
|
-
if (key ===
|
|
150
|
+
if (key === 'record' || key === 'list' || key === 'anonymizeAccount')
|
|
151
151
|
continue;
|
|
152
152
|
const value = src[key];
|
|
153
|
-
dst[key] = typeof value ===
|
|
153
|
+
dst[key] = typeof value === 'function' ? value.bind(original) : value;
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
return composed;
|