@adonis-agora/authkit-server 0.34.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/LICENSE +21 -0
- package/README.md +158 -0
- package/build/assets/grafana/authkit-dashboard.json +118 -0
- package/build/commands/clients_create.d.ts +27 -0
- package/build/commands/clients_create.js +121 -0
- package/build/commands/commands.json +292 -0
- package/build/commands/configure.d.ts +2 -0
- package/build/commands/configure.js +45 -0
- package/build/commands/doctor.d.ts +10 -0
- package/build/commands/doctor.js +113 -0
- package/build/commands/eject.d.ts +11 -0
- package/build/commands/eject.js +96 -0
- package/build/commands/expire_scan.d.ts +28 -0
- package/build/commands/expire_scan.js +92 -0
- package/build/commands/import_users.d.ts +17 -0
- package/build/commands/import_users.js +80 -0
- package/build/commands/keys_rotate.d.ts +21 -0
- package/build/commands/keys_rotate.js +126 -0
- package/build/commands/main.d.ts +12 -0
- package/build/commands/main.js +38 -0
- package/build/commands/settings_get.d.ts +18 -0
- package/build/commands/settings_get.js +43 -0
- package/build/commands/settings_list.d.ts +17 -0
- package/build/commands/settings_list.js +39 -0
- package/build/commands/settings_set.d.ts +20 -0
- package/build/commands/settings_set.js +55 -0
- package/build/commands/settings_unset.d.ts +18 -0
- package/build/commands/settings_unset.js +46 -0
- package/build/commands/ui_preset.d.ts +4 -0
- package/build/commands/ui_preset.js +32 -0
- package/build/database/migrations/make_authkit_oidc_table.d.ts +6 -0
- package/build/database/migrations/make_authkit_oidc_table.js +19 -0
- package/build/host/ui/admin.html +29 -0
- package/build/host/views/account/apps.edge +59 -0
- package/build/host/views/account/confirm.edge +70 -0
- package/build/host/views/account/email-confirmed.edge +16 -0
- package/build/host/views/account/login.edge +33 -0
- package/build/host/views/account/mfa.edge +152 -0
- package/build/host/views/account/orgs.edge +58 -0
- package/build/host/views/account/security.edge +215 -0
- package/build/host/views/account/tokens.edge +75 -0
- package/build/host/views/consent.edge +20 -0
- package/build/host/views/forgot.edge +43 -0
- package/build/host/views/login.edge +251 -0
- package/build/host/views/maintenance.edge +32 -0
- package/build/host/views/mfa-challenge.edge +107 -0
- package/build/host/views/otp-unlock.edge +40 -0
- package/build/host/views/partials/styles.edge +2 -0
- package/build/host/views/reset.edge +30 -0
- package/build/host/views/signup.edge +62 -0
- package/build/host/views/verify-email.edge +17 -0
- package/build/index.d.ts +115 -0
- package/build/index.js +76 -0
- package/build/password/common_passwords.txt +10000 -0
- package/build/providers/authkit_server_provider.d.ts +27 -0
- package/build/providers/authkit_server_provider.js +242 -0
- package/build/src/accounts/account_store.d.ts +578 -0
- package/build/src/accounts/account_store.js +60 -0
- package/build/src/accounts/lucid_account_store.d.ts +156 -0
- package/build/src/accounts/lucid_account_store.js +294 -0
- package/build/src/accounts/lucid_store/core.d.ts +9 -0
- package/build/src/accounts/lucid_store/core.js +306 -0
- package/build/src/accounts/lucid_store/mfa.d.ts +15 -0
- package/build/src/accounts/lucid_store/mfa.js +108 -0
- package/build/src/accounts/lucid_store/organizations.d.ts +13 -0
- package/build/src/accounts/lucid_store/organizations.js +294 -0
- package/build/src/accounts/lucid_store/password_hygiene.d.ts +20 -0
- package/build/src/accounts/lucid_store/password_hygiene.js +130 -0
- package/build/src/accounts/lucid_store/provider_identity.d.ts +8 -0
- package/build/src/accounts/lucid_store/provider_identity.js +59 -0
- package/build/src/accounts/lucid_store/shared.d.ts +113 -0
- package/build/src/accounts/lucid_store/shared.js +130 -0
- package/build/src/accounts/lucid_store/status_profile.d.ts +34 -0
- package/build/src/accounts/lucid_store/status_profile.js +100 -0
- package/build/src/accounts/lucid_store/webauthn.d.ts +8 -0
- package/build/src/accounts/lucid_store/webauthn.js +140 -0
- package/build/src/accounts/lucid_stores.d.ts +45 -0
- package/build/src/accounts/lucid_stores.js +30 -0
- package/build/src/adapters/adapter_contract.d.ts +37 -0
- package/build/src/adapters/adapter_contract.js +1 -0
- package/build/src/adapters/database_adapter.d.ts +21 -0
- package/build/src/adapters/database_adapter.js +79 -0
- package/build/src/adapters/factory.d.ts +30 -0
- package/build/src/adapters/factory.js +43 -0
- package/build/src/adapters/redis_adapter.d.ts +24 -0
- package/build/src/adapters/redis_adapter.js +122 -0
- package/build/src/audit/audit_sink.d.ts +63 -0
- package/build/src/audit/audit_sink.js +1 -0
- package/build/src/audit/lucid_audit_sink.d.ts +10 -0
- package/build/src/audit/lucid_audit_sink.js +99 -0
- package/build/src/commands/expire_scan_command.d.ts +60 -0
- package/build/src/commands/expire_scan_command.js +229 -0
- package/build/src/commands/import_clients.d.ts +40 -0
- package/build/src/commands/import_clients.js +79 -0
- package/build/src/commands/import_users.d.ts +51 -0
- package/build/src/commands/import_users.js +94 -0
- package/build/src/commands/resolve_config.d.ts +13 -0
- package/build/src/commands/resolve_config.js +18 -0
- package/build/src/commands/settings_commands.d.ts +47 -0
- package/build/src/commands/settings_commands.js +270 -0
- package/build/src/controllers/oidc_callback_controller.d.ts +22 -0
- package/build/src/controllers/oidc_callback_controller.js +33 -0
- package/build/src/define_config.d.ts +772 -0
- package/build/src/define_config.js +351 -0
- package/build/src/doctor/checks.d.ts +197 -0
- package/build/src/doctor/checks.js +858 -0
- package/build/src/events/dispatcher.d.ts +45 -0
- package/build/src/events/dispatcher.js +117 -0
- package/build/src/host/account_api/account_api_controller.d.ts +245 -0
- package/build/src/host/account_api/account_api_controller.js +827 -0
- package/build/src/host/account_deletion_ops.d.ts +80 -0
- package/build/src/host/account_deletion_ops.js +118 -0
- package/build/src/host/account_deletion_service.d.ts +63 -0
- package/build/src/host/account_deletion_service.js +133 -0
- package/build/src/host/account_export_service.d.ts +76 -0
- package/build/src/host/account_export_service.js +140 -0
- package/build/src/host/account_home.d.ts +11 -0
- package/build/src/host/account_home.js +11 -0
- package/build/src/host/account_lockout.d.ts +86 -0
- package/build/src/host/account_lockout.js +185 -0
- package/build/src/host/active_org_cookie.d.ts +28 -0
- package/build/src/host/active_org_cookie.js +47 -0
- package/build/src/host/admin_api/admin_api_guard.d.ts +16 -0
- package/build/src/host/admin_api/admin_api_guard.js +59 -0
- package/build/src/host/admin_api/admin_orgs_service.d.ts +125 -0
- package/build/src/host/admin_api/admin_orgs_service.js +324 -0
- package/build/src/host/admin_api/admin_users_service.d.ts +163 -0
- package/build/src/host/admin_api/admin_users_service.js +308 -0
- package/build/src/host/admin_api/api_clients_controller.d.ts +54 -0
- package/build/src/host/admin_api/api_clients_controller.js +89 -0
- package/build/src/host/admin_api/api_keys_controller.d.ts +19 -0
- package/build/src/host/admin_api/api_keys_controller.js +36 -0
- package/build/src/host/admin_api/api_misc_controller.d.ts +19 -0
- package/build/src/host/admin_api/api_misc_controller.js +44 -0
- package/build/src/host/admin_api/api_orgs_controller.d.ts +108 -0
- package/build/src/host/admin_api/api_orgs_controller.js +189 -0
- package/build/src/host/admin_api/api_settings_controller.d.ts +55 -0
- package/build/src/host/admin_api/api_settings_controller.js +134 -0
- package/build/src/host/admin_api/api_users_controller.d.ts +108 -0
- package/build/src/host/admin_api/api_users_controller.js +187 -0
- package/build/src/host/admin_api/dto.d.ts +131 -0
- package/build/src/host/admin_api/dto.js +122 -0
- package/build/src/host/admin_api/token_verify_service.d.ts +34 -0
- package/build/src/host/admin_api/token_verify_service.js +74 -0
- package/build/src/host/admin_clients_service.d.ts +88 -0
- package/build/src/host/admin_clients_service.js +181 -0
- package/build/src/host/admin_console/admin_shell_controller.d.ts +27 -0
- package/build/src/host/admin_console/admin_shell_controller.js +167 -0
- package/build/src/host/admin_console/console_audit_controller.d.ts +17 -0
- package/build/src/host/admin_console/console_audit_controller.js +25 -0
- package/build/src/host/admin_console/console_clients_controller.d.ts +53 -0
- package/build/src/host/admin_console/console_clients_controller.js +102 -0
- package/build/src/host/admin_console/console_impersonation_controller.d.ts +23 -0
- package/build/src/host/admin_console/console_impersonation_controller.js +45 -0
- package/build/src/host/admin_console/console_keys_controller.d.ts +24 -0
- package/build/src/host/admin_console/console_keys_controller.js +41 -0
- package/build/src/host/admin_console/console_orgs_controller.d.ts +96 -0
- package/build/src/host/admin_console/console_orgs_controller.js +238 -0
- package/build/src/host/admin_console/console_overview_controller.d.ts +27 -0
- package/build/src/host/admin_console/console_overview_controller.js +44 -0
- package/build/src/host/admin_console/console_roles_controller.d.ts +31 -0
- package/build/src/host/admin_console/console_roles_controller.js +108 -0
- package/build/src/host/admin_console/console_sessions_controller.d.ts +91 -0
- package/build/src/host/admin_console/console_sessions_controller.js +125 -0
- package/build/src/host/admin_console/console_settings_controller.d.ts +47 -0
- package/build/src/host/admin_console/console_settings_controller.js +115 -0
- package/build/src/host/admin_console/console_users_controller.d.ts +110 -0
- package/build/src/host/admin_console/console_users_controller.js +212 -0
- package/build/src/host/admin_prefix.d.ts +50 -0
- package/build/src/host/admin_prefix.js +77 -0
- package/build/src/host/admin_sessions_service.d.ts +119 -0
- package/build/src/host/admin_sessions_service.js +284 -0
- package/build/src/host/admin_stats_service.d.ts +44 -0
- package/build/src/host/admin_stats_service.js +130 -0
- package/build/src/host/admin_validators.d.ts +247 -0
- package/build/src/host/admin_validators.js +197 -0
- package/build/src/host/augmentations.d.ts +12 -0
- package/build/src/host/augmentations.js +1 -0
- package/build/src/host/auth_host_config.d.ts +22 -0
- package/build/src/host/auth_host_config.js +13 -0
- package/build/src/host/avatar_storage.d.ts +68 -0
- package/build/src/host/avatar_storage.js +166 -0
- package/build/src/host/bot_protection.d.ts +187 -0
- package/build/src/host/bot_protection.js +132 -0
- package/build/src/host/branding.d.ts +19 -0
- package/build/src/host/branding.js +8 -0
- package/build/src/host/config_locks.d.ts +38 -0
- package/build/src/host/config_locks.js +70 -0
- package/build/src/host/console_session.d.ts +27 -0
- package/build/src/host/console_session.js +36 -0
- package/build/src/host/controllers/account_apps_controller.d.ts +15 -0
- package/build/src/host/controllers/account_apps_controller.js +61 -0
- package/build/src/host/controllers/account_confirm_controller.d.ts +24 -0
- package/build/src/host/controllers/account_confirm_controller.js +144 -0
- package/build/src/host/controllers/account_mfa_controller.d.ts +28 -0
- package/build/src/host/controllers/account_mfa_controller.js +208 -0
- package/build/src/host/controllers/account_orgs_controller.d.ts +80 -0
- package/build/src/host/controllers/account_orgs_controller.js +401 -0
- package/build/src/host/controllers/account_security_controller.d.ts +43 -0
- package/build/src/host/controllers/account_security_controller.js +546 -0
- package/build/src/host/controllers/account_session_controller.d.ts +21 -0
- package/build/src/host/controllers/account_session_controller.js +113 -0
- package/build/src/host/controllers/account_tokens_controller.d.ts +7 -0
- package/build/src/host/controllers/account_tokens_controller.js +67 -0
- package/build/src/host/controllers/interaction_controller.d.ts +125 -0
- package/build/src/host/controllers/interaction_controller.js +981 -0
- package/build/src/host/controllers/pat_introspection_controller.d.ts +22 -0
- package/build/src/host/controllers/pat_introspection_controller.js +46 -0
- package/build/src/host/controllers/registration_controller.d.ts +18 -0
- package/build/src/host/controllers/registration_controller.js +382 -0
- package/build/src/host/controllers/social_controller.d.ts +8 -0
- package/build/src/host/controllers/social_controller.js +89 -0
- package/build/src/host/csrf.d.ts +29 -0
- package/build/src/host/csrf.js +14 -0
- package/build/src/host/default_mailer.d.ts +112 -0
- package/build/src/host/default_mailer.js +417 -0
- package/build/src/host/durable/account_deletion_workflow.d.ts +48 -0
- package/build/src/host/durable/account_deletion_workflow.js +86 -0
- package/build/src/host/durable/account_export_workflow.d.ts +68 -0
- package/build/src/host/durable/account_export_workflow.js +93 -0
- package/build/src/host/durable/index.d.ts +68 -0
- package/build/src/host/durable/index.js +77 -0
- package/build/src/host/email_templates.d.ts +39 -0
- package/build/src/host/email_templates.js +69 -0
- package/build/src/host/geo.d.ts +22 -0
- package/build/src/host/geo.js +39 -0
- package/build/src/host/i18n.d.ts +1416 -0
- package/build/src/host/i18n.js +1583 -0
- package/build/src/host/impersonation.d.ts +25 -0
- package/build/src/host/impersonation.js +31 -0
- package/build/src/host/key_rotation.d.ts +14 -0
- package/build/src/host/key_rotation.js +27 -0
- package/build/src/host/key_rotation_actions.d.ts +42 -0
- package/build/src/host/key_rotation_actions.js +27 -0
- package/build/src/host/login_attempt.d.ts +98 -0
- package/build/src/host/login_attempt.js +211 -0
- package/build/src/host/login_notify.d.ts +27 -0
- package/build/src/host/login_notify.js +142 -0
- package/build/src/host/middleware/account_auth.d.ts +7 -0
- package/build/src/host/middleware/account_auth.js +11 -0
- package/build/src/host/otp_lockout.d.ts +103 -0
- package/build/src/host/otp_lockout.js +221 -0
- package/build/src/host/rate_limit.d.ts +39 -0
- package/build/src/host/rate_limit.js +94 -0
- package/build/src/host/register_auth_host.d.ts +97 -0
- package/build/src/host/register_auth_host.js +466 -0
- package/build/src/host/renderers/edge_renderer.d.ts +12 -0
- package/build/src/host/renderers/edge_renderer.js +38 -0
- package/build/src/host/renderers/inertia_renderer.d.ts +70 -0
- package/build/src/host/renderers/inertia_renderer.js +54 -0
- package/build/src/host/runtime_settings.d.ts +181 -0
- package/build/src/host/runtime_settings.js +307 -0
- package/build/src/host/runtime_toggles.d.ts +807 -0
- package/build/src/host/runtime_toggles.js +784 -0
- package/build/src/host/security_notice_service.d.ts +36 -0
- package/build/src/host/security_notice_service.js +87 -0
- package/build/src/host/session_context.d.ts +23 -0
- package/build/src/host/session_context.js +89 -0
- package/build/src/host/sudo_mode.d.ts +56 -0
- package/build/src/host/sudo_mode.js +99 -0
- package/build/src/host/svg_chart.d.ts +15 -0
- package/build/src/host/svg_chart.js +45 -0
- package/build/src/host/trusted_device.d.ts +61 -0
- package/build/src/host/trusted_device.js +65 -0
- package/build/src/host/ui-dist/assets/index-CRWcmsex.js +137 -0
- package/build/src/host/ui-dist/assets/index-DTSmD4RU.css +1 -0
- package/build/src/host/ui-dist/index.html +17 -0
- package/build/src/host/user_agent.d.ts +18 -0
- package/build/src/host/user_agent.js +50 -0
- package/build/src/host/validators.d.ts +127 -0
- package/build/src/host/validators.js +53 -0
- package/build/src/keys/jwks_manager.d.ts +6 -0
- package/build/src/keys/jwks_manager.js +11 -0
- package/build/src/keys/keystore.d.ts +52 -0
- package/build/src/keys/keystore.js +68 -0
- package/build/src/keys/keystore_codec.d.ts +20 -0
- package/build/src/keys/keystore_codec.js +42 -0
- package/build/src/keys/keystore_crypto.d.ts +9 -0
- package/build/src/keys/keystore_crypto.js +27 -0
- package/build/src/keys/keystore_manager.d.ts +43 -0
- package/build/src/keys/keystore_manager.js +104 -0
- package/build/src/keys/keystore_vault.d.ts +113 -0
- package/build/src/keys/keystore_vault.js +265 -0
- package/build/src/mixins/json_column.d.ts +33 -0
- package/build/src/mixins/json_column.js +38 -0
- package/build/src/mixins/with_audit_log.d.ts +19 -0
- package/build/src/mixins/with_audit_log.js +39 -0
- package/build/src/mixins/with_auth_user.d.ts +24 -0
- package/build/src/mixins/with_auth_user.js +46 -0
- package/build/src/mixins/with_credentials.d.ts +20 -0
- package/build/src/mixins/with_credentials.js +29 -0
- package/build/src/mixins/with_mfa.d.ts +35 -0
- package/build/src/mixins/with_mfa.js +21 -0
- package/build/src/mixins/with_personal_access_token.d.ts +19 -0
- package/build/src/mixins/with_personal_access_token.js +42 -0
- package/build/src/mixins/with_provider_identity.d.ts +20 -0
- package/build/src/mixins/with_provider_identity.js +32 -0
- package/build/src/mixins/with_webauthn_credential.d.ts +37 -0
- package/build/src/mixins/with_webauthn_credential.js +46 -0
- package/build/src/observability/diagnostics_bridge.d.ts +6 -0
- package/build/src/observability/diagnostics_bridge.js +27 -0
- package/build/src/observability/metrics_controller.d.ts +5 -0
- package/build/src/observability/metrics_controller.js +24 -0
- package/build/src/observability/metrics_service.d.ts +2 -0
- package/build/src/observability/metrics_service.js +7 -0
- package/build/src/observability/otel_recorder.d.ts +10 -0
- package/build/src/observability/otel_recorder.js +59 -0
- package/build/src/observability/telescope/data_providers.d.ts +24 -0
- package/build/src/observability/telescope/data_providers.js +235 -0
- package/build/src/observability/telescope/extension.d.ts +29 -0
- package/build/src/observability/telescope/extension.js +167 -0
- package/build/src/observability/telescope/index.d.ts +8 -0
- package/build/src/observability/telescope/index.js +8 -0
- package/build/src/observability/wire_provider_events.d.ts +12 -0
- package/build/src/observability/wire_provider_events.js +30 -0
- package/build/src/password/common_passwords.d.ts +31 -0
- package/build/src/password/common_passwords.js +73 -0
- package/build/src/password/password_manager.d.ts +163 -0
- package/build/src/password/password_manager.js +191 -0
- package/build/src/password/policy.d.ts +71 -0
- package/build/src/password/policy.js +55 -0
- package/build/src/password/pwned.d.ts +36 -0
- package/build/src/password/pwned.js +52 -0
- package/build/src/pat/lucid_pat_store.d.ts +6 -0
- package/build/src/pat/lucid_pat_store.js +62 -0
- package/build/src/pat/pat_store.d.ts +31 -0
- package/build/src/pat/pat_store.js +1 -0
- package/build/src/pat/pat_tokens.d.ts +4 -0
- package/build/src/pat/pat_tokens.js +9 -0
- package/build/src/provider/build_provider.d.ts +45 -0
- package/build/src/provider/build_provider.js +219 -0
- package/build/src/provider/device_sources.d.ts +6 -0
- package/build/src/provider/device_sources.js +65 -0
- package/build/src/provider/interaction_actions.d.ts +36 -0
- package/build/src/provider/interaction_actions.js +55 -0
- package/build/src/provider/key_rotation_scheduler.d.ts +28 -0
- package/build/src/provider/key_rotation_scheduler.js +40 -0
- package/build/src/provider/keystore_reload.d.ts +21 -0
- package/build/src/provider/keystore_reload.js +39 -0
- package/build/src/provider/logout_sources.d.ts +13 -0
- package/build/src/provider/logout_sources.js +64 -0
- package/build/src/provider/oidc_service.d.ts +81 -0
- package/build/src/provider/oidc_service.js +254 -0
- package/build/src/provider/single_flight_lock.d.ts +18 -0
- package/build/src/provider/single_flight_lock.js +31 -0
- package/build/src/provider/token_exchange.d.ts +21 -0
- package/build/src/provider/token_exchange.js +124 -0
- package/build/src/register_routes.d.ts +16 -0
- package/build/src/register_routes.js +21 -0
- package/build/src/schema/ensure.d.ts +41 -0
- package/build/src/schema/ensure.js +262 -0
- package/build/stubs/config/authkit.stub +20 -0
- package/build/stubs/config/authkit_react.stub +52 -0
- package/build/stubs/main.d.ts +1 -0
- package/build/stubs/main.js +2 -0
- package/build/stubs/models/auth_user.stub +22 -0
- package/build/stubs/ui/edge/views/consent.edge +13 -0
- package/build/stubs/ui/edge/views/login.edge +19 -0
- package/build/stubs/ui/react/components/auth_shell.tsx +67 -0
- package/build/stubs/ui/react/pages/account/login.tsx +56 -0
- package/build/stubs/ui/react/pages/account/mfa.tsx +132 -0
- package/build/stubs/ui/react/pages/account/tokens.tsx +88 -0
- package/build/stubs/ui/react/pages/consent.tsx +39 -0
- package/build/stubs/ui/react/pages/forgot.tsx +44 -0
- package/build/stubs/ui/react/pages/login.tsx +171 -0
- package/build/stubs/ui/react/pages/mfa-challenge.tsx +72 -0
- package/build/stubs/ui/react/pages/reset.tsx +58 -0
- package/build/stubs/ui/react/pages/signup.tsx +78 -0
- package/build/stubs/ui/react/pages/verify-email.tsx +24 -0
- package/build/types.d.ts +7 -0
- package/build/types.js +1 -0
- package/package.json +147 -0
- package/stubs/config/authkit.stub +20 -0
- package/stubs/config/authkit_react.stub +52 -0
- package/stubs/main.ts +2 -0
- package/stubs/models/auth_user.stub +22 -0
- package/stubs/ui/edge/views/consent.edge +13 -0
- package/stubs/ui/edge/views/login.edge +19 -0
- package/stubs/ui/react/components/auth_shell.tsx +67 -0
- package/stubs/ui/react/pages/account/login.tsx +56 -0
- package/stubs/ui/react/pages/account/mfa.tsx +132 -0
- package/stubs/ui/react/pages/account/tokens.tsx +88 -0
- package/stubs/ui/react/pages/consent.tsx +39 -0
- package/stubs/ui/react/pages/forgot.tsx +44 -0
- package/stubs/ui/react/pages/login.tsx +171 -0
- package/stubs/ui/react/pages/mfa-challenge.tsx +72 -0
- package/stubs/ui/react/pages/reset.tsx +58 -0
- package/stubs/ui/react/pages/signup.tsx +78 -0
- package/stubs/ui/react/pages/verify-email.tsx +24 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type MetricsRecorder } from '@adonis-agora/authkit-core';
|
|
2
|
+
import type { ResolvedServerConfig } from '../define_config.js';
|
|
3
|
+
import { buildProvider, type SessionTtlHolder, type TokenTtlHolder } from './build_provider.js';
|
|
4
|
+
import { type InteractionActions } from './interaction_actions.js';
|
|
5
|
+
import { type ManagedKeyInfo } from '../keys/keystore.js';
|
|
6
|
+
import type { KeystoreManager } from '../keys/keystore_manager.js';
|
|
7
|
+
export declare class OidcService {
|
|
8
|
+
#private;
|
|
9
|
+
get provider(): ReturnType<typeof buildProvider>;
|
|
10
|
+
get callback(): (req: any, res: any) => void;
|
|
11
|
+
get interactions(): InteractionActions;
|
|
12
|
+
/** Pathname do issuer sem barra final (ex.: `/oidc`). Vazio quando montado na raiz. */
|
|
13
|
+
readonly mountPath: string;
|
|
14
|
+
readonly recorder: MetricsRecorder;
|
|
15
|
+
/** Holder mutável dos TTLs de sessão OIDC (lido sincronamente pelo oidc-provider). */
|
|
16
|
+
readonly sessionTtlHolder: SessionTtlHolder;
|
|
17
|
+
/** Holder mutável dos TTLs de access/id/refresh tokens (lido sincronamente pelo oidc-provider). */
|
|
18
|
+
readonly tokenTtlHolder: TokenTtlHolder;
|
|
19
|
+
get config(): ResolvedServerConfig;
|
|
20
|
+
/** @internal Loader de JWKS do cofre (usado por reloadKeys). */
|
|
21
|
+
get jwksLoader(): (() => Promise<{
|
|
22
|
+
keys: Record<string, any>[];
|
|
23
|
+
}>) | undefined;
|
|
24
|
+
/** @internal Token barato de mudança do cofre (usado pelo poll de reload). */
|
|
25
|
+
get keystoreHead(): (() => Promise<string | null>) | undefined;
|
|
26
|
+
constructor(config: ResolvedServerConfig, appKey: string, recorder?: MetricsRecorder, deps?: {
|
|
27
|
+
/** Relê o keystore do cofre e devolve o JWKS (sem `iat`). Ausente → reloadKeys é no-op. */
|
|
28
|
+
jwksLoader?: () => Promise<{
|
|
29
|
+
keys: Record<string, any>[];
|
|
30
|
+
}>;
|
|
31
|
+
/** Token barato de mudança do cofre (kid/etag/mtime) p/ o poll. */
|
|
32
|
+
keystoreHead?: () => Promise<string | null>;
|
|
33
|
+
/** Fábrica do KeystoreManager (necessária para rotateKeys e keystoreAgeDays). */
|
|
34
|
+
keystoreManager?: () => Promise<KeystoreManager>;
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Recarrega as chaves de assinatura AO VIVO: relê o keystore do cofre e reconstrói
|
|
38
|
+
* o provider com o JWKS novo, trocando a instância atomicamente (#buildAndWire faz
|
|
39
|
+
* build-em-locais → assign no fim). No-op quando não há `jwksLoader` (source:'jwks'
|
|
40
|
+
* inline ou managed sem store).
|
|
41
|
+
*
|
|
42
|
+
* Serializado por mutex (#reloadChain): chamadas concorrentes são enfileiradas em
|
|
43
|
+
* vez de executar em paralelo, evitando builds sobrepostos.
|
|
44
|
+
*/
|
|
45
|
+
reloadKeys(): Promise<void>;
|
|
46
|
+
/** Idade (dias) da chave de assinatura corrente, ou null (sem keystore gerenciável). */
|
|
47
|
+
keystoreAgeDays(): Promise<number | null>;
|
|
48
|
+
/** Lista as chaves managed (kid/alg/idade/ativa), ou [] se não há keystore gerenciável. */
|
|
49
|
+
listManagedKeys(): Promise<ManagedKeyInfo[]>;
|
|
50
|
+
/**
|
|
51
|
+
* Rotaciona a chave de assinatura e aplica ao vivo (rotate → reloadKeys → audit
|
|
52
|
+
* keys.rotated). Lança quando não há keystore gerenciável. Usado pelo scheduler e
|
|
53
|
+
* pelo endpoint admin "rotacionar agora".
|
|
54
|
+
*
|
|
55
|
+
* Serializado por mutex (#rotateChain): chamadas concorrentes são enfileiradas para
|
|
56
|
+
* que duas rotações nunca se sobreponham em processo (evita perda silenciosa de escrita).
|
|
57
|
+
* Cada caller recebe o resultado da SUA própria rotação.
|
|
58
|
+
*/
|
|
59
|
+
rotateKeys(keep: number, retire?: boolean): Promise<{
|
|
60
|
+
newKid: string;
|
|
61
|
+
retiredKids: string[];
|
|
62
|
+
keptKids: string[];
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* Invalida o cache de clients DINÂMICOS do oidc-provider (a `dynamicClients`
|
|
66
|
+
* QuickLRU em `instance(provider)`). DEVE ser chamado após qualquer escrita
|
|
67
|
+
* (create/update/delete) no model `Client` via adapter, pelo console admin.
|
|
68
|
+
*
|
|
69
|
+
* NOTA sobre o porquê: o oidc-provider v9 cacheia clients carregados do adapter
|
|
70
|
+
* numa LRU CUJA CHAVE É O HASH (sha256) DO PAYLOAD persistido — não o client_id.
|
|
71
|
+
* Por isso uma alteração de metadata já é "auto-invalidante": `Client.find` relê o
|
|
72
|
+
* adapter, hasheia o payload NOVO, dá cache-miss e reconstrói o client. Mesmo assim
|
|
73
|
+
* limpamos a LRU explicitamente para (a) tornar o efeito imediato e determinístico
|
|
74
|
+
* (sem depender de pressão de LRU para expulsar a entrada antiga, agora inalcançável)
|
|
75
|
+
* e (b) liberar a entrada órfã na hora. É o caminho de invalidação suportado: a LRU
|
|
76
|
+
* é um detalhe interno acessível via o helper `weak_cache` do próprio provider.
|
|
77
|
+
*/
|
|
78
|
+
evictDynamicClientCache(): Promise<void>;
|
|
79
|
+
/** Verifica client_id + client_secret contra os clients da config (p/ endpoints custom como introspecção de PAT). */
|
|
80
|
+
verifyClientCredentials(clientId: string, clientSecret: string): boolean;
|
|
81
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { NoopRecorder } from '@adonis-agora/authkit-core';
|
|
3
|
+
import Koa from 'koa';
|
|
4
|
+
import mount from 'koa-mount';
|
|
5
|
+
import { wireProviderEvents } from '../observability/wire_provider_events.js';
|
|
6
|
+
import { buildProvider } from './build_provider.js';
|
|
7
|
+
import { createInteractionActions } from './interaction_actions.js';
|
|
8
|
+
import { registerTokenExchange } from './token_exchange.js';
|
|
9
|
+
import { readActiveOrgFromKoaCtx } from '../host/active_org_cookie.js';
|
|
10
|
+
import { isFirstParty } from '../host/branding.js';
|
|
11
|
+
import { signingKeyAgeDays, listKeyInfos } from '../keys/keystore.js';
|
|
12
|
+
export class OidcService {
|
|
13
|
+
#provider;
|
|
14
|
+
#callback;
|
|
15
|
+
#interactions;
|
|
16
|
+
#appKey;
|
|
17
|
+
get provider() { return this.#provider; }
|
|
18
|
+
get callback() { return this.#callback; }
|
|
19
|
+
get interactions() { return this.#interactions; }
|
|
20
|
+
/** Pathname do issuer sem barra final (ex.: `/oidc`). Vazio quando montado na raiz. */
|
|
21
|
+
mountPath;
|
|
22
|
+
recorder;
|
|
23
|
+
/** Holder mutável dos TTLs de sessão OIDC (lido sincronamente pelo oidc-provider). */
|
|
24
|
+
sessionTtlHolder;
|
|
25
|
+
/** Holder mutável dos TTLs de access/id/refresh tokens (lido sincronamente pelo oidc-provider). */
|
|
26
|
+
tokenTtlHolder;
|
|
27
|
+
#clients;
|
|
28
|
+
#config;
|
|
29
|
+
/** Closures de acesso ao cofre de chaves (injetadas pelo provider para hot-reload). */
|
|
30
|
+
#deps;
|
|
31
|
+
/** Mutex de serialização de reloadKeys: encadeia execuções para nunca sobrepor builds. */
|
|
32
|
+
#reloadChain = Promise.resolve();
|
|
33
|
+
/** Mutex de serialização de rotateKeys: evita que duas rotações concorrentes se sobreponham. */
|
|
34
|
+
#rotateChain = Promise.resolve();
|
|
35
|
+
get config() {
|
|
36
|
+
return this.#config;
|
|
37
|
+
}
|
|
38
|
+
/** @internal Loader de JWKS do cofre (usado por reloadKeys). */
|
|
39
|
+
get jwksLoader() {
|
|
40
|
+
return this.#deps.jwksLoader;
|
|
41
|
+
}
|
|
42
|
+
/** @internal Token barato de mudança do cofre (usado pelo poll de reload). */
|
|
43
|
+
get keystoreHead() {
|
|
44
|
+
return this.#deps.keystoreHead;
|
|
45
|
+
}
|
|
46
|
+
constructor(config, appKey, recorder = new NoopRecorder(), deps = {}) {
|
|
47
|
+
this.#config = config;
|
|
48
|
+
this.#clients = config.clients ?? [];
|
|
49
|
+
this.#appKey = appKey;
|
|
50
|
+
this.recorder = recorder;
|
|
51
|
+
this.#deps = deps;
|
|
52
|
+
// Inicializa o holder de TTL com os valores do config estático.
|
|
53
|
+
// Será atualizado em runtime quando a setting `session_policy` for salva/apagada.
|
|
54
|
+
const configSessionSec = config.ttl.session;
|
|
55
|
+
this.sessionTtlHolder = {
|
|
56
|
+
rememberSec: Math.max(1, configSessionSec),
|
|
57
|
+
transientSec: Math.max(1, configSessionSec),
|
|
58
|
+
};
|
|
59
|
+
// Inicializa o holder de TTL de tokens com os valores do config estático.
|
|
60
|
+
// Será atualizado em runtime quando a setting `token_ttl` for salva/apagada.
|
|
61
|
+
this.tokenTtlHolder = {
|
|
62
|
+
accessTokenSec: Math.max(1, config.ttl.accessToken),
|
|
63
|
+
idTokenSec: Math.max(1, config.ttl.idToken),
|
|
64
|
+
refreshTokenSec: Math.max(1, config.ttl.refreshToken),
|
|
65
|
+
};
|
|
66
|
+
// mountPath é estável (o issuer nunca muda): deriva diretamente de config.issuer
|
|
67
|
+
// para que #buildAndWire possa ser chamado sem precisar reconstituir o mountPath.
|
|
68
|
+
this.mountPath = new URL(config.issuer).pathname.replace(/\/+$/, '');
|
|
69
|
+
this.#buildAndWire(config.jwks);
|
|
70
|
+
}
|
|
71
|
+
#buildAndWire(jwks) {
|
|
72
|
+
const config = this.#config;
|
|
73
|
+
const provider = buildProvider({ ...config, jwks }, {
|
|
74
|
+
appKey: this.#appKey,
|
|
75
|
+
findAccount: async (ctx, sub) => {
|
|
76
|
+
const user = await config.findAccount(sub);
|
|
77
|
+
if (!user)
|
|
78
|
+
return undefined;
|
|
79
|
+
// Lê a org ativa do cookie de sessão (se organizations estiver disponível).
|
|
80
|
+
const activeOrg = readActiveOrgFromKoaCtx(ctx);
|
|
81
|
+
// GATE de least-privilege: roles globais e claims de org só são emitidas para
|
|
82
|
+
// clients FIRST-PARTY (`branding.firstParty`). Capturamos o clientId aqui (fora
|
|
83
|
+
// do closure `claims()`, pois o `ctx` da request vive neste escopo). Um client
|
|
84
|
+
// third-party NUNCA recebe roles/org — mesmo solicitando `scope=roles`.
|
|
85
|
+
const clientId = ctx?.oidc?.client?.clientId;
|
|
86
|
+
const firstParty = config.branding
|
|
87
|
+
? isFirstParty(config.branding, clientId)
|
|
88
|
+
: false;
|
|
89
|
+
return {
|
|
90
|
+
accountId: user.id,
|
|
91
|
+
claims: async (_use, _scope) => {
|
|
92
|
+
const base = {
|
|
93
|
+
sub: user.id,
|
|
94
|
+
email: user.email,
|
|
95
|
+
email_verified: true,
|
|
96
|
+
name: user.name,
|
|
97
|
+
picture: user.avatarUrl,
|
|
98
|
+
};
|
|
99
|
+
// roles/org_* são dados de autorização interna: só para first-party.
|
|
100
|
+
if (firstParty) {
|
|
101
|
+
base[config.globalRolesClaim] = user.globalRoles ?? [];
|
|
102
|
+
// Emite claims de org somente quando há uma org ativa na sessão.
|
|
103
|
+
if (activeOrg) {
|
|
104
|
+
base['org_id'] = activeOrg.orgId;
|
|
105
|
+
base['org_slug'] = activeOrg.orgSlug;
|
|
106
|
+
base['org_role'] = activeOrg.orgRole;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return base;
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
}, this.sessionTtlHolder, this.tokenTtlHolder);
|
|
114
|
+
wireProviderEvents(provider, this.recorder);
|
|
115
|
+
registerTokenExchange(provider, {
|
|
116
|
+
findAccount: config.findAccount,
|
|
117
|
+
globalRolesClaim: config.globalRolesClaim,
|
|
118
|
+
// Resource indicators (RFC 8707) suportados: o `audience` default + cada
|
|
119
|
+
// resource declarado. Usado para validar `audience`/`resource` no pedido de
|
|
120
|
+
// token-exchange — alvos fora desta lista são rejeitados (invalid_target).
|
|
121
|
+
supportedResources: [
|
|
122
|
+
config.accessTokens.audience,
|
|
123
|
+
...Object.keys(config.accessTokens.resources),
|
|
124
|
+
],
|
|
125
|
+
audit: config.audit,
|
|
126
|
+
});
|
|
127
|
+
// Quando o issuer tem um path (ex.: http://host/oidc), o provider precisa ser
|
|
128
|
+
// MONTADO sob esse path via koa-mount. Isso faz o oidc-provider gerar URLs de
|
|
129
|
+
// discovery e redirects de resume/interaction CORRETAMENTE prefixados (ex.:
|
|
130
|
+
// /oidc/auth, /oidc/jwks). Apenas remover o prefixo de req.url (abordagem antiga)
|
|
131
|
+
// fazia o provider se enxergar na raiz e anunciar URLs sem o /oidc.
|
|
132
|
+
// Para issuer na raiz, o mountPath é vazio e usamos o callback Node direto.
|
|
133
|
+
let callback;
|
|
134
|
+
if (this.mountPath && this.mountPath !== '/') {
|
|
135
|
+
const koa = new Koa();
|
|
136
|
+
// O app externo PRECISA herdar as Keygrip keys do provider. Sob koa-mount as
|
|
137
|
+
// requisições do provider rodam no contexto do app EXTERNO, então `ctx.cookies`
|
|
138
|
+
// usa as keys deste app. Sem isso, os cookies (_interaction, _session) seriam
|
|
139
|
+
// assinados/lidos de forma inconsistente entre o fluxo via mount (authorize) e as
|
|
140
|
+
// chamadas diretas `interactionDetails`/`interactionFinished` (que usam o contexto
|
|
141
|
+
// do provider), quebrando o "interaction session id cookie not found".
|
|
142
|
+
koa.keys = provider.keys;
|
|
143
|
+
koa.proxy = provider.proxy;
|
|
144
|
+
koa.use(mount(this.mountPath, provider));
|
|
145
|
+
callback = koa.callback();
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
callback = provider.callback();
|
|
149
|
+
}
|
|
150
|
+
const interactions = createInteractionActions(provider, { verifyCredentials: config.verifyCredentials });
|
|
151
|
+
// Atribuição atômica no final: um throw antes deste ponto não corrompe o estado.
|
|
152
|
+
this.#provider = provider;
|
|
153
|
+
this.#callback = callback;
|
|
154
|
+
this.#interactions = interactions;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Recarrega as chaves de assinatura AO VIVO: relê o keystore do cofre e reconstrói
|
|
158
|
+
* o provider com o JWKS novo, trocando a instância atomicamente (#buildAndWire faz
|
|
159
|
+
* build-em-locais → assign no fim). No-op quando não há `jwksLoader` (source:'jwks'
|
|
160
|
+
* inline ou managed sem store).
|
|
161
|
+
*
|
|
162
|
+
* Serializado por mutex (#reloadChain): chamadas concorrentes são enfileiradas em
|
|
163
|
+
* vez de executar em paralelo, evitando builds sobrepostos.
|
|
164
|
+
*/
|
|
165
|
+
async reloadKeys() {
|
|
166
|
+
const run = async () => {
|
|
167
|
+
const loader = this.#deps.jwksLoader;
|
|
168
|
+
if (!loader)
|
|
169
|
+
return;
|
|
170
|
+
const jwks = await loader();
|
|
171
|
+
this.#buildAndWire(jwks);
|
|
172
|
+
};
|
|
173
|
+
this.#reloadChain = this.#reloadChain.then(run, run);
|
|
174
|
+
return this.#reloadChain;
|
|
175
|
+
}
|
|
176
|
+
/** Idade (dias) da chave de assinatura corrente, ou null (sem keystore gerenciável). */
|
|
177
|
+
async keystoreAgeDays() {
|
|
178
|
+
const build = this.#deps.keystoreManager;
|
|
179
|
+
if (!build)
|
|
180
|
+
return null;
|
|
181
|
+
const m = await build();
|
|
182
|
+
return signingKeyAgeDays(await m.read());
|
|
183
|
+
}
|
|
184
|
+
/** Lista as chaves managed (kid/alg/idade/ativa), ou [] se não há keystore gerenciável. */
|
|
185
|
+
async listManagedKeys() {
|
|
186
|
+
const build = this.#deps.keystoreManager;
|
|
187
|
+
if (!build)
|
|
188
|
+
return [];
|
|
189
|
+
const m = await build();
|
|
190
|
+
return listKeyInfos(await m.read());
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Rotaciona a chave de assinatura e aplica ao vivo (rotate → reloadKeys → audit
|
|
194
|
+
* keys.rotated). Lança quando não há keystore gerenciável. Usado pelo scheduler e
|
|
195
|
+
* pelo endpoint admin "rotacionar agora".
|
|
196
|
+
*
|
|
197
|
+
* Serializado por mutex (#rotateChain): chamadas concorrentes são enfileiradas para
|
|
198
|
+
* que duas rotações nunca se sobreponham em processo (evita perda silenciosa de escrita).
|
|
199
|
+
* Cada caller recebe o resultado da SUA própria rotação.
|
|
200
|
+
*/
|
|
201
|
+
async rotateKeys(keep, retire = false) {
|
|
202
|
+
const run = async () => {
|
|
203
|
+
const build = this.#deps.keystoreManager;
|
|
204
|
+
if (!build)
|
|
205
|
+
throw new Error('AuthKit: rotação indisponível (jwks não é managed+store).');
|
|
206
|
+
const m = await build();
|
|
207
|
+
const { newKid, retiredKids, store } = await m.rotate(keep, retire);
|
|
208
|
+
await this.reloadKeys();
|
|
209
|
+
const keptKids = store.keys.map((k) => k.kid);
|
|
210
|
+
await this.#config.audit?.record({ type: 'keys.rotated', metadata: { newKid, retiredKids, keptKids, retire } }).catch(() => { });
|
|
211
|
+
return { newKid, retiredKids, keptKids };
|
|
212
|
+
};
|
|
213
|
+
// serializa: encadeia após a rotação em voo; cada caller recebe o resultado da SUA rotação
|
|
214
|
+
const result = this.#rotateChain.then(run, run);
|
|
215
|
+
this.#rotateChain = result.catch(() => { }); // a cadeia segue mesmo se uma rotação falhar
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Invalida o cache de clients DINÂMICOS do oidc-provider (a `dynamicClients`
|
|
220
|
+
* QuickLRU em `instance(provider)`). DEVE ser chamado após qualquer escrita
|
|
221
|
+
* (create/update/delete) no model `Client` via adapter, pelo console admin.
|
|
222
|
+
*
|
|
223
|
+
* NOTA sobre o porquê: o oidc-provider v9 cacheia clients carregados do adapter
|
|
224
|
+
* numa LRU CUJA CHAVE É O HASH (sha256) DO PAYLOAD persistido — não o client_id.
|
|
225
|
+
* Por isso uma alteração de metadata já é "auto-invalidante": `Client.find` relê o
|
|
226
|
+
* adapter, hasheia o payload NOVO, dá cache-miss e reconstrói o client. Mesmo assim
|
|
227
|
+
* limpamos a LRU explicitamente para (a) tornar o efeito imediato e determinístico
|
|
228
|
+
* (sem depender de pressão de LRU para expulsar a entrada antiga, agora inalcançável)
|
|
229
|
+
* e (b) liberar a entrada órfã na hora. É o caminho de invalidação suportado: a LRU
|
|
230
|
+
* é um detalhe interno acessível via o helper `weak_cache` do próprio provider.
|
|
231
|
+
*/
|
|
232
|
+
async evictDynamicClientCache() {
|
|
233
|
+
try {
|
|
234
|
+
const wc = await import('oidc-provider/lib/helpers/weak_cache.js');
|
|
235
|
+
const get = wc.default ?? wc.get;
|
|
236
|
+
const int = get(this.provider);
|
|
237
|
+
int?.dynamicClients?.clear?.();
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// Estrutura interna mudou numa versão futura do oidc-provider: a invalidação por
|
|
241
|
+
// hash-de-conteúdo (acima) continua garantindo correção; só perdemos a expulsão
|
|
242
|
+
// imediata da entrada órfã. Best-effort — não propaga erro pro caminho da request.
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/** Verifica client_id + client_secret contra os clients da config (p/ endpoints custom como introspecção de PAT). */
|
|
246
|
+
verifyClientCredentials(clientId, clientSecret) {
|
|
247
|
+
const client = this.#clients.find((c) => c.clientId === clientId);
|
|
248
|
+
if (!client || !client.clientSecret)
|
|
249
|
+
return false;
|
|
250
|
+
const a = Buffer.from(client.clientSecret);
|
|
251
|
+
const b = Buffer.from(clientSecret);
|
|
252
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Service do `@adonisjs/lock` (any de propósito — peer opt-in). */
|
|
2
|
+
type LockService = any;
|
|
3
|
+
/**
|
|
4
|
+
* Cria um executor single-flight: roda `fn` SÓ se conseguir o lock de imediato
|
|
5
|
+
* (sem esperar) — garante que apenas UMA instância execute a rotação agendada.
|
|
6
|
+
* Sem `@adonisjs/lock` instalado, assume single-instance e roda `fn` direto
|
|
7
|
+
* (no-lock). Mirror do padrão peer-lazy (limiter/drive). Libera no `finally`.
|
|
8
|
+
*/
|
|
9
|
+
export interface SingleFlightOptions {
|
|
10
|
+
key: string;
|
|
11
|
+
ttlMs: number;
|
|
12
|
+
/** Carrega o service do lock (default: import lazy de `@adonisjs/lock/services/main`). */
|
|
13
|
+
loadLock?: () => Promise<LockService | null>;
|
|
14
|
+
/** Store do lock (db/redis); default deixa o service usar o default do host. */
|
|
15
|
+
store?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function makeSingleFlightLock(opts: SingleFlightOptions): (fn: () => Promise<void>) => Promise<void>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
async function defaultLoadLock() {
|
|
10
|
+
const spec = '@adonisjs/lock/services/main';
|
|
11
|
+
return import(__rewriteRelativeImportExtension(spec))
|
|
12
|
+
.then((m) => m.default ?? null)
|
|
13
|
+
.catch(() => null);
|
|
14
|
+
}
|
|
15
|
+
export function makeSingleFlightLock(opts) {
|
|
16
|
+
const load = opts.loadLock ?? defaultLoadLock;
|
|
17
|
+
return async (fn) => {
|
|
18
|
+
const svc = await load();
|
|
19
|
+
if (!svc)
|
|
20
|
+
return fn(); // no-lock (single-instance)
|
|
21
|
+
const lock = (opts.store ? svc.use(opts.store) : svc.use()).createLock(opts.key, opts.ttlMs);
|
|
22
|
+
if (!(await lock.acquireImmediately()))
|
|
23
|
+
return; // outra instância tem o lock
|
|
24
|
+
try {
|
|
25
|
+
await fn();
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
await lock.release().catch(() => { });
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AuditSink } from '../audit/audit_sink.js';
|
|
2
|
+
export interface TokenExchangeAccount {
|
|
3
|
+
id: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
globalRoles?: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface TokenExchangeDeps {
|
|
9
|
+
findAccount: (sub: string) => Promise<TokenExchangeAccount | null>;
|
|
10
|
+
globalRolesClaim: string;
|
|
11
|
+
adminRole?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Resource indicators (RFC 8707) suportados pelo provider. Quando o pedido traz
|
|
14
|
+
* `audience`/`resource`, validamos contra esta lista; um alvo não suportado é
|
|
15
|
+
* rejeitado (conservador). Vazio/ausente => nenhum resource é aceito no pedido.
|
|
16
|
+
*/
|
|
17
|
+
supportedResources?: string[];
|
|
18
|
+
/** Sink de auditoria (best-effort). Quando presente, registra `impersonation`. */
|
|
19
|
+
audit?: AuditSink;
|
|
20
|
+
}
|
|
21
|
+
export declare function registerTokenExchange(provider: any, deps: TokenExchangeDeps): void;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { errors } from 'oidc-provider';
|
|
2
|
+
const TOKEN_EXCHANGE = 'urn:ietf:params:oauth:grant-type:token-exchange';
|
|
3
|
+
const ACCESS_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:access_token';
|
|
4
|
+
/**
|
|
5
|
+
* Interseção entre os scopes pedidos e os scopes permitidos do client (allowlist).
|
|
6
|
+
* Preserva a ordem do pedido. Nunca excede a allowlist do client.
|
|
7
|
+
*/
|
|
8
|
+
function intersectScopes(requested, allowed) {
|
|
9
|
+
const out = [];
|
|
10
|
+
for (const s of requested.split(' ')) {
|
|
11
|
+
const t = s.trim();
|
|
12
|
+
if (t && allowed.has(t) && !out.includes(t))
|
|
13
|
+
out.push(t);
|
|
14
|
+
}
|
|
15
|
+
return out.join(' ');
|
|
16
|
+
}
|
|
17
|
+
export function registerTokenExchange(provider, deps) {
|
|
18
|
+
const adminRole = deps.adminRole ?? 'ADMIN';
|
|
19
|
+
const supportedResources = new Set(deps.supportedResources ?? []);
|
|
20
|
+
const handler = async (ctx) => {
|
|
21
|
+
const { params, client } = ctx.oidc;
|
|
22
|
+
if (params.subject_token_type !== ACCESS_TOKEN_TYPE) {
|
|
23
|
+
throw new errors.InvalidRequest('unsupported subject_token_type');
|
|
24
|
+
}
|
|
25
|
+
if (!params.subject_token) {
|
|
26
|
+
throw new errors.InvalidRequest('subject_token is required');
|
|
27
|
+
}
|
|
28
|
+
const subjectAt = await provider.AccessToken.find(params.subject_token);
|
|
29
|
+
if (!subjectAt || subjectAt.isExpired) {
|
|
30
|
+
throw new errors.InvalidGrant('subject_token invalid or expired');
|
|
31
|
+
}
|
|
32
|
+
// O subject_token DEVE ter sido emitido para o MESMO client autenticado: senão
|
|
33
|
+
// um client B poderia trocar um AT emitido para o client A (cross-client).
|
|
34
|
+
if (subjectAt.clientId !== client?.clientId) {
|
|
35
|
+
throw new errors.InvalidGrant('subject_token was not issued to this client');
|
|
36
|
+
}
|
|
37
|
+
const actor = await deps.findAccount(subjectAt.accountId);
|
|
38
|
+
if (!actor || !(actor.globalRoles ?? []).includes(adminRole)) {
|
|
39
|
+
throw new errors.InvalidGrant('actor not permitted to impersonate');
|
|
40
|
+
}
|
|
41
|
+
const targetId = params.requested_subject;
|
|
42
|
+
if (!targetId) {
|
|
43
|
+
throw new errors.InvalidRequest('requested_subject is required');
|
|
44
|
+
}
|
|
45
|
+
const target = await deps.findAccount(targetId);
|
|
46
|
+
if (!target) {
|
|
47
|
+
throw new errors.InvalidGrant('requested_subject not found');
|
|
48
|
+
}
|
|
49
|
+
// audience/resource: se o pedido vier com um alvo, ele PRECISA estar entre os
|
|
50
|
+
// resource indicators suportados. Caso contrário rejeitamos (conservador) —
|
|
51
|
+
// nunca embutimos audiência arbitrária no token emitido.
|
|
52
|
+
const requestedTargets = [params.audience, params.resource].filter((v) => typeof v === 'string' && v.length > 0);
|
|
53
|
+
for (const tgt of requestedTargets) {
|
|
54
|
+
if (!supportedResources.has(tgt)) {
|
|
55
|
+
throw new errors.InvalidTarget('requested audience/resource is not supported');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// scope: nunca exceder os scopes permitidos do client autenticado. Quando o
|
|
59
|
+
// client DECLARA `scope` (allowlist), o pedido é reduzido à INTERSEÇÃO com ela.
|
|
60
|
+
// Quando o client NÃO declara `scope` (metadata ausente nesta lib = "não
|
|
61
|
+
// configurado", não "nenhum scope"), preservamos o comportamento atual: usa o
|
|
62
|
+
// `scope` pedido, ou o default mínimo se o pedido vier vazio.
|
|
63
|
+
const clientScopes = new Set(String(client?.scope ?? '')
|
|
64
|
+
.split(' ')
|
|
65
|
+
.map((s) => s.trim())
|
|
66
|
+
.filter(Boolean));
|
|
67
|
+
const DEFAULT_SCOPE = 'openid profile email';
|
|
68
|
+
let scope;
|
|
69
|
+
if (clientScopes.size) {
|
|
70
|
+
// Client com allowlist explícita: interseção (pedido) ou a própria allowlist.
|
|
71
|
+
scope = params.scope
|
|
72
|
+
? intersectScopes(params.scope, clientScopes)
|
|
73
|
+
: [...clientScopes].join(' ');
|
|
74
|
+
// Pedido explícito sem nenhuma interseção → erro claro, não token de scope vazio.
|
|
75
|
+
if (params.scope && !scope) {
|
|
76
|
+
throw new errors.InvalidScope('requested scope is not allowed for this client', params.scope);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// Client sem allowlist declarada: comportamento atual preservado.
|
|
81
|
+
scope = params.scope || DEFAULT_SCOPE;
|
|
82
|
+
}
|
|
83
|
+
const at = new provider.AccessToken({ accountId: target.id, client, scope });
|
|
84
|
+
const accessToken = await at.save();
|
|
85
|
+
const idToken = new provider.IdToken({
|
|
86
|
+
sub: target.id,
|
|
87
|
+
email: target.email,
|
|
88
|
+
email_verified: true,
|
|
89
|
+
name: target.name,
|
|
90
|
+
[deps.globalRolesClaim]: target.globalRoles ?? [],
|
|
91
|
+
}, { ctx });
|
|
92
|
+
idToken.scope = scope;
|
|
93
|
+
idToken.set('act', { sub: actor.id });
|
|
94
|
+
const idTokenJwt = await idToken.issue({ use: 'idtoken' });
|
|
95
|
+
await deps.audit?.record({
|
|
96
|
+
type: 'impersonation',
|
|
97
|
+
actorId: actor.id,
|
|
98
|
+
accountId: target.id,
|
|
99
|
+
email: target.email ?? null,
|
|
100
|
+
clientId: client?.clientId ?? null,
|
|
101
|
+
ip: ctx.req?.socket?.remoteAddress ?? null,
|
|
102
|
+
metadata: { scope },
|
|
103
|
+
});
|
|
104
|
+
ctx.body = {
|
|
105
|
+
access_token: accessToken,
|
|
106
|
+
issued_token_type: ACCESS_TOKEN_TYPE,
|
|
107
|
+
token_type: at.tokenType ?? 'Bearer',
|
|
108
|
+
expires_in: at.expiration ?? 3600,
|
|
109
|
+
id_token: idTokenJwt,
|
|
110
|
+
scope,
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
provider.registerGrantType(TOKEN_EXCHANGE, handler, [
|
|
114
|
+
'subject_token',
|
|
115
|
+
'subject_token_type',
|
|
116
|
+
'requested_subject',
|
|
117
|
+
'requested_token_type',
|
|
118
|
+
'scope',
|
|
119
|
+
'audience',
|
|
120
|
+
'resource',
|
|
121
|
+
'actor_token',
|
|
122
|
+
'actor_token_type',
|
|
123
|
+
], ['audience', 'resource']);
|
|
124
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Router } from '@adonisjs/core/http';
|
|
2
|
+
/**
|
|
3
|
+
* Registra a rota catch-all que delega ao handler do oidc-provider.
|
|
4
|
+
* O issuer do consumidor deve terminar em `mountPath` (default `/oidc`),
|
|
5
|
+
* pois o oidc-provider roteia internamente sob o issuer.
|
|
6
|
+
* Uso: registerOidcRoutes(router) no start/routes.ts do auth-service.
|
|
7
|
+
*
|
|
8
|
+
* Observabilidade (opt-in):
|
|
9
|
+
* - `metrics: true` monta `GET /authkit/metrics` (snapshot JSON).
|
|
10
|
+
* - `dashboard: true` monta `GET /authkit/dashboard` (HTML embutido).
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerOidcRoutes(router: Router, options?: {
|
|
13
|
+
mountPath?: string;
|
|
14
|
+
metrics?: boolean;
|
|
15
|
+
dashboard?: boolean;
|
|
16
|
+
}): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import OidcCallbackController from './controllers/oidc_callback_controller.js';
|
|
2
|
+
import MetricsController from './observability/metrics_controller.js';
|
|
3
|
+
/**
|
|
4
|
+
* Registra a rota catch-all que delega ao handler do oidc-provider.
|
|
5
|
+
* O issuer do consumidor deve terminar em `mountPath` (default `/oidc`),
|
|
6
|
+
* pois o oidc-provider roteia internamente sob o issuer.
|
|
7
|
+
* Uso: registerOidcRoutes(router) no start/routes.ts do auth-service.
|
|
8
|
+
*
|
|
9
|
+
* Observabilidade (opt-in):
|
|
10
|
+
* - `metrics: true` monta `GET /authkit/metrics` (snapshot JSON).
|
|
11
|
+
* - `dashboard: true` monta `GET /authkit/dashboard` (HTML embutido).
|
|
12
|
+
*/
|
|
13
|
+
export function registerOidcRoutes(router, options = {}) {
|
|
14
|
+
const mount = options.mountPath ?? '/oidc';
|
|
15
|
+
router.any(`${mount}/*`, [OidcCallbackController]).as('authkit.oidc.wildcard');
|
|
16
|
+
router.any(mount, [OidcCallbackController]).as('authkit.oidc.root');
|
|
17
|
+
if (options.metrics)
|
|
18
|
+
router.get('/authkit/metrics', [MetricsController, 'json']);
|
|
19
|
+
if (options.dashboard)
|
|
20
|
+
router.get('/authkit/dashboard', [MetricsController, 'dashboard']);
|
|
21
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema das tabelas que o PRÓPRIO authkit possui (nomes fixos). As tabelas
|
|
3
|
+
* do host (users, webauthn credentials, provider identities, PATs, audit)
|
|
4
|
+
* ficam de fora de propósito: nome e shape são decisão do host.
|
|
5
|
+
*
|
|
6
|
+
* `ensureAuthkitSchema()` é ADITIVO e idempotente:
|
|
7
|
+
* - cria as tabelas que faltam;
|
|
8
|
+
* - adiciona colunas novas em tabelas existentes (ALTER ADD);
|
|
9
|
+
* - nunca dropa nada nem altera tipo de coluna existente.
|
|
10
|
+
*
|
|
11
|
+
* Roda automaticamente no boot quando `schema.autoManage` está ligado
|
|
12
|
+
* (default), ou manualmente dentro de uma migration do host:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* // database/migrations/xxxx_authkit_schema.ts
|
|
16
|
+
* import { BaseSchema } from '@adonisjs/lucid/schema'
|
|
17
|
+
* import { ensureAuthkitSchema } from '@adonis-agora/authkit-server'
|
|
18
|
+
*
|
|
19
|
+
* export default class extends BaseSchema {
|
|
20
|
+
* async up() {
|
|
21
|
+
* await ensureAuthkitSchema(this.db)
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export interface EnsureSchemaOptions {
|
|
27
|
+
/** Conexão Lucid a usar. Default: conexão primária. */
|
|
28
|
+
connection?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface EnsureSchemaReport {
|
|
31
|
+
/** Tabelas criadas do zero nesta execução. */
|
|
32
|
+
created: string[];
|
|
33
|
+
/** Colunas adicionadas em tabelas já existentes: tabela → colunas. */
|
|
34
|
+
altered: Record<string, string[]>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Garante que as tabelas do authkit existem e têm todas as colunas que esta
|
|
38
|
+
* versão da lib espera. Aditivo e idempotente — seguro de rodar em todo boot
|
|
39
|
+
* e dentro de migrations.
|
|
40
|
+
*/
|
|
41
|
+
export declare function ensureAuthkitSchema(db: any, options?: EnsureSchemaOptions): Promise<EnsureSchemaReport>;
|