@nauth-toolkit/core 0.1.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/dist/adapters/database-columns.d.ts +10 -0
- package/dist/adapters/database-columns.d.ts.map +1 -0
- package/dist/adapters/database-columns.js +85 -0
- package/dist/adapters/database-columns.js.map +1 -0
- package/dist/adapters/express.adapter.d.ts +41 -0
- package/dist/adapters/express.adapter.d.ts.map +1 -0
- package/dist/adapters/express.adapter.js +188 -0
- package/dist/adapters/express.adapter.js.map +1 -0
- package/dist/adapters/fastify.adapter.d.ts +33 -0
- package/dist/adapters/fastify.adapter.d.ts.map +1 -0
- package/dist/adapters/fastify.adapter.js +223 -0
- package/dist/adapters/fastify.adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +5 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +25 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/storage.factory.d.ts +7 -0
- package/dist/adapters/storage.factory.d.ts.map +1 -0
- package/dist/adapters/storage.factory.js +24 -0
- package/dist/adapters/storage.factory.js.map +1 -0
- package/dist/bootstrap.d.ts +41 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +113 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/dto/auth-challenge.dto.d.ts +19 -0
- package/dist/dto/auth-challenge.dto.d.ts.map +1 -0
- package/dist/dto/auth-challenge.dto.js +86 -0
- package/dist/dto/auth-challenge.dto.js.map +1 -0
- package/dist/dto/auth-response.dto.d.ts +31 -0
- package/dist/dto/auth-response.dto.d.ts.map +1 -0
- package/dist/dto/auth-response.dto.js +18 -0
- package/dist/dto/auth-response.dto.js.map +1 -0
- package/dist/dto/challenge-response.dto.d.ts +36 -0
- package/dist/dto/challenge-response.dto.d.ts.map +1 -0
- package/dist/dto/challenge-response.dto.js +3 -0
- package/dist/dto/challenge-response.dto.js.map +1 -0
- package/dist/dto/change-password-request.dto.d.ts +5 -0
- package/dist/dto/change-password-request.dto.d.ts.map +1 -0
- package/dist/dto/change-password-request.dto.js +30 -0
- package/dist/dto/change-password-request.dto.js.map +1 -0
- package/dist/dto/change-password-response.dto.d.ts +4 -0
- package/dist/dto/change-password-response.dto.d.ts.map +1 -0
- package/dist/dto/change-password-response.dto.js +8 -0
- package/dist/dto/change-password-response.dto.js.map +1 -0
- package/dist/dto/change-password.dto.d.ts +5 -0
- package/dist/dto/change-password.dto.d.ts.map +1 -0
- package/dist/dto/change-password.dto.js +29 -0
- package/dist/dto/change-password.dto.js.map +1 -0
- package/dist/dto/error-response.dto.d.ts +9 -0
- package/dist/dto/error-response.dto.d.ts.map +1 -0
- package/dist/dto/error-response.dto.js +59 -0
- package/dist/dto/error-response.dto.js.map +1 -0
- package/dist/dto/get-available-methods.dto.d.ts +7 -0
- package/dist/dto/get-available-methods.dto.d.ts.map +1 -0
- package/dist/dto/get-available-methods.dto.js +33 -0
- package/dist/dto/get-available-methods.dto.js.map +1 -0
- package/dist/dto/get-challenge-data-response.dto.d.ts +4 -0
- package/dist/dto/get-challenge-data-response.dto.d.ts.map +1 -0
- package/dist/dto/get-challenge-data-response.dto.js +8 -0
- package/dist/dto/get-challenge-data-response.dto.js.map +1 -0
- package/dist/dto/get-challenge-data.dto.d.ts +8 -0
- package/dist/dto/get-challenge-data.dto.d.ts.map +1 -0
- package/dist/dto/get-challenge-data.dto.js +40 -0
- package/dist/dto/get-challenge-data.dto.js.map +1 -0
- package/dist/dto/get-client-info.dto.d.ts +17 -0
- package/dist/dto/get-client-info.dto.d.ts.map +1 -0
- package/dist/dto/get-client-info.dto.js +20 -0
- package/dist/dto/get-client-info.dto.js.map +1 -0
- package/dist/dto/get-device-token-response.dto.d.ts +4 -0
- package/dist/dto/get-device-token-response.dto.d.ts.map +1 -0
- package/dist/dto/get-device-token-response.dto.js +8 -0
- package/dist/dto/get-device-token-response.dto.js.map +1 -0
- package/dist/dto/get-events-by-type.dto.d.ts +17 -0
- package/dist/dto/get-events-by-type.dto.d.ts.map +1 -0
- package/dist/dto/get-events-by-type.dto.js +20 -0
- package/dist/dto/get-events-by-type.dto.js.map +1 -0
- package/dist/dto/get-ip-address-response.dto.d.ts +4 -0
- package/dist/dto/get-ip-address-response.dto.d.ts.map +1 -0
- package/dist/dto/get-ip-address-response.dto.js +8 -0
- package/dist/dto/get-ip-address-response.dto.js.map +1 -0
- package/dist/dto/get-mfa-status.dto.d.ts +16 -0
- package/dist/dto/get-mfa-status.dto.d.ts.map +1 -0
- package/dist/dto/get-mfa-status.dto.js +41 -0
- package/dist/dto/get-mfa-status.dto.js.map +1 -0
- package/dist/dto/get-risk-assessment-history.dto.d.ts +9 -0
- package/dist/dto/get-risk-assessment-history.dto.d.ts.map +1 -0
- package/dist/dto/get-risk-assessment-history.dto.js +13 -0
- package/dist/dto/get-risk-assessment-history.dto.js.map +1 -0
- package/dist/dto/get-session-id-response.dto.d.ts +4 -0
- package/dist/dto/get-session-id-response.dto.d.ts.map +1 -0
- package/dist/dto/get-session-id-response.dto.js +8 -0
- package/dist/dto/get-session-id-response.dto.js.map +1 -0
- package/dist/dto/get-setup-data-response.dto.d.ts +4 -0
- package/dist/dto/get-setup-data-response.dto.d.ts.map +1 -0
- package/dist/dto/get-setup-data-response.dto.js +8 -0
- package/dist/dto/get-setup-data-response.dto.js.map +1 -0
- package/dist/dto/get-setup-data.dto.d.ts +7 -0
- package/dist/dto/get-setup-data.dto.d.ts.map +1 -0
- package/dist/dto/get-setup-data.dto.js +43 -0
- package/dist/dto/get-setup-data.dto.js.map +1 -0
- package/dist/dto/get-suspicious-activity.dto.d.ts +9 -0
- package/dist/dto/get-suspicious-activity.dto.d.ts.map +1 -0
- package/dist/dto/get-suspicious-activity.dto.js +13 -0
- package/dist/dto/get-suspicious-activity.dto.js.map +1 -0
- package/dist/dto/get-user-agent-response.dto.d.ts +4 -0
- package/dist/dto/get-user-agent-response.dto.d.ts.map +1 -0
- package/dist/dto/get-user-agent-response.dto.js +8 -0
- package/dist/dto/get-user-agent-response.dto.js.map +1 -0
- package/dist/dto/get-user-auth-history.dto.d.ts +20 -0
- package/dist/dto/get-user-auth-history.dto.d.ts.map +1 -0
- package/dist/dto/get-user-auth-history.dto.js +22 -0
- package/dist/dto/get-user-auth-history.dto.js.map +1 -0
- package/dist/dto/get-user-by-email.dto.d.ts +5 -0
- package/dist/dto/get-user-by-email.dto.d.ts.map +1 -0
- package/dist/dto/get-user-by-email.dto.js +36 -0
- package/dist/dto/get-user-by-email.dto.js.map +1 -0
- package/dist/dto/get-user-by-id.dto.d.ts +4 -0
- package/dist/dto/get-user-by-id.dto.d.ts.map +1 -0
- package/dist/dto/get-user-by-id.dto.js +29 -0
- package/dist/dto/get-user-by-id.dto.js.map +1 -0
- package/dist/dto/get-user-devices.dto.d.ts +8 -0
- package/dist/dto/get-user-devices.dto.d.ts.map +1 -0
- package/dist/dto/get-user-devices.dto.js +33 -0
- package/dist/dto/get-user-devices.dto.js.map +1 -0
- package/dist/dto/get-user-response.dto.d.ts +2 -0
- package/dist/dto/get-user-response.dto.d.ts.map +1 -0
- package/dist/dto/get-user-response.dto.js +6 -0
- package/dist/dto/get-user-response.dto.js.map +1 -0
- package/dist/dto/has-provider.dto.d.ts +7 -0
- package/dist/dto/has-provider.dto.d.ts.map +1 -0
- package/dist/dto/has-provider.dto.js +38 -0
- package/dist/dto/has-provider.dto.js.map +1 -0
- package/dist/dto/index.d.ts +51 -0
- package/dist/dto/index.d.ts.map +1 -0
- package/dist/dto/index.js +67 -0
- package/dist/dto/index.js.map +1 -0
- package/dist/dto/is-trusted-device-response.dto.d.ts +4 -0
- package/dist/dto/is-trusted-device-response.dto.d.ts.map +1 -0
- package/dist/dto/is-trusted-device-response.dto.js +8 -0
- package/dist/dto/is-trusted-device-response.dto.js.map +1 -0
- package/dist/dto/list-providers-response.dto.d.ts +4 -0
- package/dist/dto/list-providers-response.dto.d.ts.map +1 -0
- package/dist/dto/list-providers-response.dto.js +8 -0
- package/dist/dto/list-providers-response.dto.js.map +1 -0
- package/dist/dto/login.dto.d.ts +7 -0
- package/dist/dto/login.dto.d.ts.map +1 -0
- package/dist/dto/login.dto.js +68 -0
- package/dist/dto/login.dto.js.map +1 -0
- package/dist/dto/logout-all-response.dto.d.ts +4 -0
- package/dist/dto/logout-all-response.dto.d.ts.map +1 -0
- package/dist/dto/logout-all-response.dto.js +8 -0
- package/dist/dto/logout-all-response.dto.js.map +1 -0
- package/dist/dto/logout-all.dto.d.ts +5 -0
- package/dist/dto/logout-all.dto.d.ts.map +1 -0
- package/dist/dto/logout-all.dto.js +42 -0
- package/dist/dto/logout-all.dto.js.map +1 -0
- package/dist/dto/logout-response.dto.d.ts +4 -0
- package/dist/dto/logout-response.dto.d.ts.map +1 -0
- package/dist/dto/logout-response.dto.js +8 -0
- package/dist/dto/logout-response.dto.js.map +1 -0
- package/dist/dto/logout.dto.d.ts +5 -0
- package/dist/dto/logout.dto.d.ts.map +1 -0
- package/dist/dto/logout.dto.js +36 -0
- package/dist/dto/logout.dto.js.map +1 -0
- package/dist/dto/refresh-token.dto.d.ts +4 -0
- package/dist/dto/refresh-token.dto.d.ts.map +1 -0
- package/dist/dto/refresh-token.dto.js +24 -0
- package/dist/dto/refresh-token.dto.js.map +1 -0
- package/dist/dto/remove-devices.dto.d.ts +9 -0
- package/dist/dto/remove-devices.dto.d.ts.map +1 -0
- package/dist/dto/remove-devices.dto.js +50 -0
- package/dist/dto/remove-devices.dto.js.map +1 -0
- package/dist/dto/resend-code-response.dto.d.ts +4 -0
- package/dist/dto/resend-code-response.dto.d.ts.map +1 -0
- package/dist/dto/resend-code-response.dto.js +8 -0
- package/dist/dto/resend-code-response.dto.js.map +1 -0
- package/dist/dto/resend-code.dto.d.ts +4 -0
- package/dist/dto/resend-code.dto.d.ts.map +1 -0
- package/dist/dto/resend-code.dto.js +29 -0
- package/dist/dto/resend-code.dto.js.map +1 -0
- package/dist/dto/reset-password.dto.d.ts +8 -0
- package/dist/dto/reset-password.dto.d.ts.map +1 -0
- package/dist/dto/reset-password.dto.js +61 -0
- package/dist/dto/reset-password.dto.js.map +1 -0
- package/dist/dto/respond-challenge.dto.d.ts +33 -0
- package/dist/dto/respond-challenge.dto.d.ts.map +1 -0
- package/dist/dto/respond-challenge.dto.js +131 -0
- package/dist/dto/respond-challenge.dto.js.map +1 -0
- package/dist/dto/set-mfa-exemption.dto.d.ts +12 -0
- package/dist/dto/set-mfa-exemption.dto.d.ts.map +1 -0
- package/dist/dto/set-mfa-exemption.dto.js +66 -0
- package/dist/dto/set-mfa-exemption.dto.js.map +1 -0
- package/dist/dto/set-must-change-password-response.dto.d.ts +4 -0
- package/dist/dto/set-must-change-password-response.dto.d.ts.map +1 -0
- package/dist/dto/set-must-change-password-response.dto.js +8 -0
- package/dist/dto/set-must-change-password-response.dto.js.map +1 -0
- package/dist/dto/set-must-change-password.dto.d.ts +4 -0
- package/dist/dto/set-must-change-password.dto.d.ts.map +1 -0
- package/dist/dto/set-must-change-password.dto.js +29 -0
- package/dist/dto/set-must-change-password.dto.js.map +1 -0
- package/dist/dto/set-preferred-method.dto.d.ts +8 -0
- package/dist/dto/set-preferred-method.dto.d.ts.map +1 -0
- package/dist/dto/set-preferred-method.dto.js +49 -0
- package/dist/dto/set-preferred-method.dto.js.map +1 -0
- package/dist/dto/setup-mfa.dto.d.ts +9 -0
- package/dist/dto/setup-mfa.dto.d.ts.map +1 -0
- package/dist/dto/setup-mfa.dto.js +55 -0
- package/dist/dto/setup-mfa.dto.js.map +1 -0
- package/dist/dto/signup.dto.d.ts +10 -0
- package/dist/dto/signup.dto.d.ts.map +1 -0
- package/dist/dto/signup.dto.js +109 -0
- package/dist/dto/signup.dto.js.map +1 -0
- package/dist/dto/social-auth.dto.d.ts +54 -0
- package/dist/dto/social-auth.dto.d.ts.map +1 -0
- package/dist/dto/social-auth.dto.js +232 -0
- package/dist/dto/social-auth.dto.js.map +1 -0
- package/dist/dto/trust-device-response.dto.d.ts +4 -0
- package/dist/dto/trust-device-response.dto.d.ts.map +1 -0
- package/dist/dto/trust-device-response.dto.js +8 -0
- package/dist/dto/trust-device-response.dto.js.map +1 -0
- package/dist/dto/trust-device.dto.d.ts +1 -0
- package/dist/dto/trust-device.dto.d.ts.map +1 -0
- package/dist/dto/trust-device.dto.js +2 -0
- package/dist/dto/trust-device.dto.js.map +1 -0
- package/dist/dto/update-user-attributes-request.dto.d.ts +5 -0
- package/dist/dto/update-user-attributes-request.dto.d.ts.map +1 -0
- package/dist/dto/update-user-attributes-request.dto.js +30 -0
- package/dist/dto/update-user-attributes-request.dto.js.map +1 -0
- package/dist/dto/user-response.dto.d.ts +20 -0
- package/dist/dto/user-response.dto.d.ts.map +1 -0
- package/dist/dto/user-response.dto.js +42 -0
- package/dist/dto/user-response.dto.js.map +1 -0
- package/dist/dto/user-update.dto.d.ts +12 -0
- package/dist/dto/user-update.dto.d.ts.map +1 -0
- package/dist/dto/user-update.dto.js +119 -0
- package/dist/dto/user-update.dto.js.map +1 -0
- package/dist/dto/verify-email.dto.d.ts +29 -0
- package/dist/dto/verify-email.dto.d.ts.map +1 -0
- package/dist/dto/verify-email.dto.js +161 -0
- package/dist/dto/verify-email.dto.js.map +1 -0
- package/dist/dto/verify-mfa-code.dto.d.ts +10 -0
- package/dist/dto/verify-mfa-code.dto.d.ts.map +1 -0
- package/dist/dto/verify-mfa-code.dto.js +56 -0
- package/dist/dto/verify-mfa-code.dto.js.map +1 -0
- package/dist/dto/verify-phone-by-sub.dto.d.ts +6 -0
- package/dist/dto/verify-phone-by-sub.dto.d.ts.map +1 -0
- package/dist/dto/verify-phone-by-sub.dto.js +49 -0
- package/dist/dto/verify-phone-by-sub.dto.js.map +1 -0
- package/dist/dto/verify-phone.dto.d.ts +24 -0
- package/dist/dto/verify-phone.dto.d.ts.map +1 -0
- package/dist/dto/verify-phone.dto.js +124 -0
- package/dist/dto/verify-phone.dto.js.map +1 -0
- package/dist/entities/auth-audit.entity.d.ts +31 -0
- package/dist/entities/auth-audit.entity.d.ts.map +1 -0
- package/dist/entities/auth-audit.entity.js +33 -0
- package/dist/entities/auth-audit.entity.js.map +1 -0
- package/dist/entities/challenge-session.entity.d.ts +17 -0
- package/dist/entities/challenge-session.entity.d.ts.map +1 -0
- package/dist/entities/challenge-session.entity.js +21 -0
- package/dist/entities/challenge-session.entity.js.map +1 -0
- package/dist/entities/index.d.ts +12 -0
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/index.js +26 -0
- package/dist/entities/index.js.map +1 -0
- package/dist/entities/login-attempt.entity.d.ts +13 -0
- package/dist/entities/login-attempt.entity.d.ts.map +1 -0
- package/dist/entities/login-attempt.entity.js +17 -0
- package/dist/entities/login-attempt.entity.js.map +1 -0
- package/dist/entities/mfa-device.entity.d.ts +22 -0
- package/dist/entities/mfa-device.entity.d.ts.map +1 -0
- package/dist/entities/mfa-device.entity.js +25 -0
- package/dist/entities/mfa-device.entity.js.map +1 -0
- package/dist/entities/rate-limit.entity.d.ts +9 -0
- package/dist/entities/rate-limit.entity.d.ts.map +1 -0
- package/dist/entities/rate-limit.entity.js +13 -0
- package/dist/entities/rate-limit.entity.js.map +1 -0
- package/dist/entities/session.entity.d.ts +32 -0
- package/dist/entities/session.entity.d.ts.map +1 -0
- package/dist/entities/session.entity.js +36 -0
- package/dist/entities/session.entity.js.map +1 -0
- package/dist/entities/social-account.entity.d.ts +13 -0
- package/dist/entities/social-account.entity.d.ts.map +1 -0
- package/dist/entities/social-account.entity.js +17 -0
- package/dist/entities/social-account.entity.js.map +1 -0
- package/dist/entities/storage-lock.entity.d.ts +8 -0
- package/dist/entities/storage-lock.entity.d.ts.map +1 -0
- package/dist/entities/storage-lock.entity.js +12 -0
- package/dist/entities/storage-lock.entity.js.map +1 -0
- package/dist/entities/trusted-device.entity.d.ts +17 -0
- package/dist/entities/trusted-device.entity.d.ts.map +1 -0
- package/dist/entities/trusted-device.entity.js +21 -0
- package/dist/entities/trusted-device.entity.js.map +1 -0
- package/dist/entities/user.entity.d.ts +41 -0
- package/dist/entities/user.entity.d.ts.map +1 -0
- package/dist/entities/user.entity.js +45 -0
- package/dist/entities/user.entity.js.map +1 -0
- package/dist/entities/verification-token.entity.d.ts +19 -0
- package/dist/entities/verification-token.entity.d.ts.map +1 -0
- package/dist/entities/verification-token.entity.js +29 -0
- package/dist/entities/verification-token.entity.js.map +1 -0
- package/dist/enums/auth-audit-event-type.enum.d.ts +55 -0
- package/dist/enums/auth-audit-event-type.enum.d.ts.map +1 -0
- package/dist/enums/auth-audit-event-type.enum.js +59 -0
- package/dist/enums/auth-audit-event-type.enum.js.map +1 -0
- package/dist/enums/error-codes.enum.d.ts +53 -0
- package/dist/enums/error-codes.enum.d.ts.map +1 -0
- package/dist/enums/error-codes.enum.js +57 -0
- package/dist/enums/error-codes.enum.js.map +1 -0
- package/dist/enums/mfa-method.enum.d.ts +11 -0
- package/dist/enums/mfa-method.enum.d.ts.map +1 -0
- package/dist/enums/mfa-method.enum.js +18 -0
- package/dist/enums/mfa-method.enum.js.map +1 -0
- package/dist/enums/risk-factor.enum.d.ts +14 -0
- package/dist/enums/risk-factor.enum.d.ts.map +1 -0
- package/dist/enums/risk-factor.enum.js +18 -0
- package/dist/enums/risk-factor.enum.js.map +1 -0
- package/dist/exceptions/nauth.exception.d.ts +18 -0
- package/dist/exceptions/nauth.exception.d.ts.map +1 -0
- package/dist/exceptions/nauth.exception.js +64 -0
- package/dist/exceptions/nauth.exception.js.map +1 -0
- package/dist/handlers/auth.handler.d.ts +18 -0
- package/dist/handlers/auth.handler.d.ts.map +1 -0
- package/dist/handlers/auth.handler.js +173 -0
- package/dist/handlers/auth.handler.js.map +1 -0
- package/dist/handlers/client-info.handler.d.ts +12 -0
- package/dist/handlers/client-info.handler.d.ts.map +1 -0
- package/dist/handlers/client-info.handler.js +61 -0
- package/dist/handlers/client-info.handler.js.map +1 -0
- package/dist/handlers/csrf.handler.d.ts +13 -0
- package/dist/handlers/csrf.handler.d.ts.map +1 -0
- package/dist/handlers/csrf.handler.js +84 -0
- package/dist/handlers/csrf.handler.js.map +1 -0
- package/dist/handlers/token-delivery.handler.d.ts +12 -0
- package/dist/handlers/token-delivery.handler.d.ts.map +1 -0
- package/dist/handlers/token-delivery.handler.js +86 -0
- package/dist/handlers/token-delivery.handler.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/client-info.interface.d.ts +16 -0
- package/dist/interfaces/client-info.interface.d.ts.map +1 -0
- package/dist/interfaces/client-info.interface.js +3 -0
- package/dist/interfaces/client-info.interface.js.map +1 -0
- package/dist/interfaces/config.interface.d.ts +279 -0
- package/dist/interfaces/config.interface.d.ts.map +1 -0
- package/dist/interfaces/config.interface.js +3 -0
- package/dist/interfaces/config.interface.js.map +1 -0
- package/dist/interfaces/entities.interface.d.ts +169 -0
- package/dist/interfaces/entities.interface.d.ts.map +1 -0
- package/dist/interfaces/entities.interface.js +3 -0
- package/dist/interfaces/entities.interface.js.map +1 -0
- package/dist/interfaces/index.d.ts +11 -0
- package/dist/interfaces/index.d.ts.map +1 -0
- package/dist/interfaces/index.js +27 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/logger.interface.d.ts +43 -0
- package/dist/interfaces/logger.interface.d.ts.map +1 -0
- package/dist/interfaces/logger.interface.js +12 -0
- package/dist/interfaces/logger.interface.js.map +1 -0
- package/dist/interfaces/mfa-provider.interface.d.ts +12 -0
- package/dist/interfaces/mfa-provider.interface.d.ts.map +1 -0
- package/dist/interfaces/mfa-provider.interface.js +3 -0
- package/dist/interfaces/mfa-provider.interface.js.map +1 -0
- package/dist/interfaces/oauth.interface.d.ts +24 -0
- package/dist/interfaces/oauth.interface.d.ts.map +1 -0
- package/dist/interfaces/oauth.interface.js +3 -0
- package/dist/interfaces/oauth.interface.js.map +1 -0
- package/dist/interfaces/provider.interface.d.ts +12 -0
- package/dist/interfaces/provider.interface.d.ts.map +1 -0
- package/dist/interfaces/provider.interface.js +3 -0
- package/dist/interfaces/provider.interface.js.map +1 -0
- package/dist/interfaces/social-auth-provider.interface.d.ts +13 -0
- package/dist/interfaces/social-auth-provider.interface.d.ts.map +1 -0
- package/dist/interfaces/social-auth-provider.interface.js +3 -0
- package/dist/interfaces/social-auth-provider.interface.js.map +1 -0
- package/dist/interfaces/storage-adapter.interface.d.ts +39 -0
- package/dist/interfaces/storage-adapter.interface.d.ts.map +1 -0
- package/dist/interfaces/storage-adapter.interface.js +3 -0
- package/dist/interfaces/storage-adapter.interface.js.map +1 -0
- package/dist/interfaces/template.interface.d.ts +99 -0
- package/dist/interfaces/template.interface.d.ts.map +1 -0
- package/dist/interfaces/template.interface.js +15 -0
- package/dist/interfaces/template.interface.js.map +1 -0
- package/dist/interfaces/token-verifier.interface.d.ts +7 -0
- package/dist/interfaces/token-verifier.interface.d.ts.map +1 -0
- package/dist/interfaces/token-verifier.interface.js +3 -0
- package/dist/interfaces/token-verifier.interface.js.map +1 -0
- package/dist/internal.d.ts +20 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +53 -0
- package/dist/internal.js.map +1 -0
- package/dist/platform/interfaces.d.ts +56 -0
- package/dist/platform/interfaces.d.ts.map +1 -0
- package/dist/platform/interfaces.js +3 -0
- package/dist/platform/interfaces.js.map +1 -0
- package/dist/schemas/auth-config.schema.d.ts +3411 -0
- package/dist/schemas/auth-config.schema.d.ts.map +1 -0
- package/dist/schemas/auth-config.schema.js +428 -0
- package/dist/schemas/auth-config.schema.js.map +1 -0
- package/dist/services/adaptive-mfa-decision.service.d.ts +39 -0
- package/dist/services/adaptive-mfa-decision.service.d.ts.map +1 -0
- package/dist/services/adaptive-mfa-decision.service.js +223 -0
- package/dist/services/adaptive-mfa-decision.service.js.map +1 -0
- package/dist/services/auth-audit.service.d.ts +44 -0
- package/dist/services/auth-audit.service.d.ts.map +1 -0
- package/dist/services/auth-audit.service.js +241 -0
- package/dist/services/auth-audit.service.js.map +1 -0
- package/dist/services/auth-challenge-helper.service.d.ts +48 -0
- package/dist/services/auth-challenge-helper.service.d.ts.map +1 -0
- package/dist/services/auth-challenge-helper.service.js +425 -0
- package/dist/services/auth-challenge-helper.service.js.map +1 -0
- package/dist/services/auth-flow-context-builder.service.d.ts +31 -0
- package/dist/services/auth-flow-context-builder.service.d.ts.map +1 -0
- package/dist/services/auth-flow-context-builder.service.js +253 -0
- package/dist/services/auth-flow-context-builder.service.js.map +1 -0
- package/dist/services/auth-flow-rules.d.ts +18 -0
- package/dist/services/auth-flow-rules.d.ts.map +1 -0
- package/dist/services/auth-flow-rules.js +55 -0
- package/dist/services/auth-flow-rules.js.map +1 -0
- package/dist/services/auth-flow-state-definitions.d.ts +5 -0
- package/dist/services/auth-flow-state-definitions.d.ts.map +1 -0
- package/dist/services/auth-flow-state-definitions.js +87 -0
- package/dist/services/auth-flow-state-definitions.js.map +1 -0
- package/dist/services/auth-flow-state-machine.service.d.ts +17 -0
- package/dist/services/auth-flow-state-machine.service.d.ts.map +1 -0
- package/dist/services/auth-flow-state-machine.service.js +91 -0
- package/dist/services/auth-flow-state-machine.service.js.map +1 -0
- package/dist/services/auth-flow-state-machine.types.d.ts +55 -0
- package/dist/services/auth-flow-state-machine.types.d.ts.map +1 -0
- package/dist/services/auth-flow-state-machine.types.js +16 -0
- package/dist/services/auth-flow-state-machine.types.js.map +1 -0
- package/dist/services/auth.service.d.ts +87 -0
- package/dist/services/auth.service.d.ts.map +1 -0
- package/dist/services/auth.service.js +2356 -0
- package/dist/services/auth.service.js.map +1 -0
- package/dist/services/challenge.service.d.ts +32 -0
- package/dist/services/challenge.service.d.ts.map +1 -0
- package/dist/services/challenge.service.js +293 -0
- package/dist/services/challenge.service.js.map +1 -0
- package/dist/services/client-info.service.d.ts +20 -0
- package/dist/services/client-info.service.d.ts.map +1 -0
- package/dist/services/client-info.service.js +202 -0
- package/dist/services/client-info.service.js.map +1 -0
- package/dist/services/csrf.service.d.ts +13 -0
- package/dist/services/csrf.service.d.ts.map +1 -0
- package/dist/services/csrf.service.js +67 -0
- package/dist/services/csrf.service.js.map +1 -0
- package/dist/services/email-verification.service.d.ts +30 -0
- package/dist/services/email-verification.service.d.ts.map +1 -0
- package/dist/services/email-verification.service.js +373 -0
- package/dist/services/email-verification.service.js.map +1 -0
- package/dist/services/geo-location.service.d.ts +85 -0
- package/dist/services/geo-location.service.d.ts.map +1 -0
- package/dist/services/geo-location.service.js +338 -0
- package/dist/services/geo-location.service.js.map +1 -0
- package/dist/services/index.d.ts +14 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +30 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/jwt.service.d.ts +62 -0
- package/dist/services/jwt.service.d.ts.map +1 -0
- package/dist/services/jwt.service.js +261 -0
- package/dist/services/jwt.service.js.map +1 -0
- package/dist/services/mfa-base.service.d.ts +37 -0
- package/dist/services/mfa-base.service.d.ts.map +1 -0
- package/dist/services/mfa-base.service.js +297 -0
- package/dist/services/mfa-base.service.js.map +1 -0
- package/dist/services/mfa.service.d.ts +35 -0
- package/dist/services/mfa.service.d.ts.map +1 -0
- package/dist/services/mfa.service.js +449 -0
- package/dist/services/mfa.service.js.map +1 -0
- package/dist/services/password.service.d.ts +19 -0
- package/dist/services/password.service.d.ts.map +1 -0
- package/dist/services/password.service.js +150 -0
- package/dist/services/password.service.js.map +1 -0
- package/dist/services/phone-verification.service.d.ts +32 -0
- package/dist/services/phone-verification.service.d.ts.map +1 -0
- package/dist/services/phone-verification.service.js +474 -0
- package/dist/services/phone-verification.service.js.map +1 -0
- package/dist/services/risk-detection.service.d.ts +30 -0
- package/dist/services/risk-detection.service.d.ts.map +1 -0
- package/dist/services/risk-detection.service.js +518 -0
- package/dist/services/risk-detection.service.js.map +1 -0
- package/dist/services/risk-scoring.service.d.ts +12 -0
- package/dist/services/risk-scoring.service.d.ts.map +1 -0
- package/dist/services/risk-scoring.service.js +44 -0
- package/dist/services/risk-scoring.service.js.map +1 -0
- package/dist/services/session.service.d.ts +64 -0
- package/dist/services/session.service.d.ts.map +1 -0
- package/dist/services/session.service.js +455 -0
- package/dist/services/session.service.js.map +1 -0
- package/dist/services/social-auth-base.service.d.ts +57 -0
- package/dist/services/social-auth-base.service.d.ts.map +1 -0
- package/dist/services/social-auth-base.service.js +340 -0
- package/dist/services/social-auth-base.service.js.map +1 -0
- package/dist/services/social-auth.service.d.ts +31 -0
- package/dist/services/social-auth.service.d.ts.map +1 -0
- package/dist/services/social-auth.service.js +172 -0
- package/dist/services/social-auth.service.js.map +1 -0
- package/dist/services/social-provider-registry.service.d.ts +9 -0
- package/dist/services/social-provider-registry.service.d.ts.map +1 -0
- package/dist/services/social-provider-registry.service.js +30 -0
- package/dist/services/social-provider-registry.service.js.map +1 -0
- package/dist/services/trusted-device.service.d.ts +29 -0
- package/dist/services/trusted-device.service.d.ts.map +1 -0
- package/dist/services/trusted-device.service.js +190 -0
- package/dist/services/trusted-device.service.js.map +1 -0
- package/dist/storage/account-lockout-storage.service.d.ts +16 -0
- package/dist/storage/account-lockout-storage.service.d.ts.map +1 -0
- package/dist/storage/account-lockout-storage.service.js +50 -0
- package/dist/storage/account-lockout-storage.service.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +20 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/memory-storage.adapter.d.ts +33 -0
- package/dist/storage/memory-storage.adapter.d.ts.map +1 -0
- package/dist/storage/memory-storage.adapter.js +195 -0
- package/dist/storage/memory-storage.adapter.js.map +1 -0
- package/dist/storage/rate-limit-storage.service.d.ts +11 -0
- package/dist/storage/rate-limit-storage.service.d.ts.map +1 -0
- package/dist/storage/rate-limit-storage.service.js +33 -0
- package/dist/storage/rate-limit-storage.service.js.map +1 -0
- package/dist/templates/html-template.engine.d.ts +16 -0
- package/dist/templates/html-template.engine.d.ts.map +1 -0
- package/dist/templates/html-template.engine.js +502 -0
- package/dist/templates/html-template.engine.js.map +1 -0
- package/dist/templates/index.d.ts +2 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +18 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/utils/common-passwords.d.ts +4 -0
- package/dist/utils/common-passwords.d.ts.map +1 -0
- package/dist/utils/common-passwords.js +108 -0
- package/dist/utils/common-passwords.js.map +1 -0
- package/dist/utils/context-storage.d.ts +13 -0
- package/dist/utils/context-storage.d.ts.map +1 -0
- package/dist/utils/context-storage.js +54 -0
- package/dist/utils/context-storage.js.map +1 -0
- package/dist/utils/cookie-names.util.d.ts +7 -0
- package/dist/utils/cookie-names.util.d.ts.map +1 -0
- package/dist/utils/cookie-names.util.js +30 -0
- package/dist/utils/cookie-names.util.js.map +1 -0
- package/dist/utils/cookies.util.d.ts +12 -0
- package/dist/utils/cookies.util.d.ts.map +1 -0
- package/dist/utils/cookies.util.js +48 -0
- package/dist/utils/cookies.util.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +24 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/ip-extractor.d.ts +12 -0
- package/dist/utils/ip-extractor.d.ts.map +1 -0
- package/dist/utils/ip-extractor.js +88 -0
- package/dist/utils/ip-extractor.js.map +1 -0
- package/dist/utils/nauth-logger.d.ts +20 -0
- package/dist/utils/nauth-logger.d.ts.map +1 -0
- package/dist/utils/nauth-logger.js +129 -0
- package/dist/utils/nauth-logger.js.map +1 -0
- package/dist/utils/pii-redactor.d.ts +16 -0
- package/dist/utils/pii-redactor.d.ts.map +1 -0
- package/dist/utils/pii-redactor.js +147 -0
- package/dist/utils/pii-redactor.js.map +1 -0
- package/dist/utils/setup/get-repositories.d.ts +16 -0
- package/dist/utils/setup/get-repositories.d.ts.map +1 -0
- package/dist/utils/setup/get-repositories.js +36 -0
- package/dist/utils/setup/get-repositories.js.map +1 -0
- package/dist/utils/setup/init-services.d.ts +41 -0
- package/dist/utils/setup/init-services.d.ts.map +1 -0
- package/dist/utils/setup/init-services.js +107 -0
- package/dist/utils/setup/init-services.js.map +1 -0
- package/dist/utils/setup/init-social.d.ts +13 -0
- package/dist/utils/setup/init-social.d.ts.map +1 -0
- package/dist/utils/setup/init-social.js +77 -0
- package/dist/utils/setup/init-social.js.map +1 -0
- package/dist/utils/setup/init-storage.d.ts +4 -0
- package/dist/utils/setup/init-storage.d.ts.map +1 -0
- package/dist/utils/setup/init-storage.js +79 -0
- package/dist/utils/setup/init-storage.js.map +1 -0
- package/dist/utils/setup/register-mfa.d.ts +5 -0
- package/dist/utils/setup/register-mfa.d.ts.map +1 -0
- package/dist/utils/setup/register-mfa.js +85 -0
- package/dist/utils/setup/register-mfa.js.map +1 -0
- package/dist/utils/setup/run-nauth-migrations.d.ts +5 -0
- package/dist/utils/setup/run-nauth-migrations.d.ts.map +1 -0
- package/dist/utils/setup/run-nauth-migrations.js +67 -0
- package/dist/utils/setup/run-nauth-migrations.js.map +1 -0
- package/dist/utils/token-delivery-policy.d.ts +6 -0
- package/dist/utils/token-delivery-policy.d.ts.map +1 -0
- package/dist/utils/token-delivery-policy.js +15 -0
- package/dist/utils/token-delivery-policy.js.map +1 -0
- package/dist/validators/template.validator.d.ts +7 -0
- package/dist/validators/template.validator.d.ts.map +1 -0
- package/dist/validators/template.validator.js +95 -0
- package/dist/validators/template.validator.js.map +1 -0
- package/jest.config.js +15 -0
- package/jest.setup.ts +6 -0
- package/package.json +73 -0
- package/src/adapters/database-columns.ts +165 -0
- package/src/adapters/express.adapter.ts +385 -0
- package/src/adapters/fastify.adapter.ts +416 -0
- package/src/adapters/index.ts +16 -0
- package/src/adapters/storage.factory.ts +143 -0
- package/src/bootstrap.ts +374 -0
- package/src/dto/auth-challenge.dto.ts +231 -0
- package/src/dto/auth-response.dto.ts +253 -0
- package/src/dto/challenge-response.dto.ts +234 -0
- package/src/dto/change-password-request.dto.ts +50 -0
- package/src/dto/change-password-response.dto.ts +29 -0
- package/src/dto/change-password.dto.ts +57 -0
- package/src/dto/error-response.dto.ts +136 -0
- package/src/dto/get-available-methods.dto.ts +55 -0
- package/src/dto/get-challenge-data-response.dto.ts +28 -0
- package/src/dto/get-challenge-data.dto.ts +69 -0
- package/src/dto/get-client-info.dto.ts +104 -0
- package/src/dto/get-device-token-response.dto.ts +25 -0
- package/src/dto/get-events-by-type.dto.ts +76 -0
- package/src/dto/get-ip-address-response.dto.ts +24 -0
- package/src/dto/get-mfa-status.dto.ts +94 -0
- package/src/dto/get-risk-assessment-history.dto.ts +39 -0
- package/src/dto/get-session-id-response.dto.ts +25 -0
- package/src/dto/get-setup-data-response.dto.ts +31 -0
- package/src/dto/get-setup-data.dto.ts +75 -0
- package/src/dto/get-suspicious-activity.dto.ts +42 -0
- package/src/dto/get-user-agent-response.dto.ts +23 -0
- package/src/dto/get-user-auth-history.dto.ts +95 -0
- package/src/dto/get-user-by-email.dto.ts +61 -0
- package/src/dto/get-user-by-id.dto.ts +46 -0
- package/src/dto/get-user-devices.dto.ts +53 -0
- package/src/dto/get-user-response.dto.ts +17 -0
- package/src/dto/has-provider.dto.ts +56 -0
- package/src/dto/index.ts +57 -0
- package/src/dto/is-trusted-device-response.dto.ts +34 -0
- package/src/dto/list-providers-response.dto.ts +23 -0
- package/src/dto/login.dto.ts +95 -0
- package/src/dto/logout-all-response.dto.ts +24 -0
- package/src/dto/logout-all.dto.ts +65 -0
- package/src/dto/logout-response.dto.ts +25 -0
- package/src/dto/logout.dto.ts +64 -0
- package/src/dto/refresh-token.dto.ts +36 -0
- package/src/dto/remove-devices.dto.ts +85 -0
- package/src/dto/resend-code-response.dto.ts +32 -0
- package/src/dto/resend-code.dto.ts +51 -0
- package/src/dto/reset-password.dto.ts +115 -0
- package/src/dto/respond-challenge.dto.ts +272 -0
- package/src/dto/set-mfa-exemption.dto.ts +112 -0
- package/src/dto/set-must-change-password-response.dto.ts +27 -0
- package/src/dto/set-must-change-password.dto.ts +46 -0
- package/src/dto/set-preferred-method.dto.ts +80 -0
- package/src/dto/setup-mfa.dto.ts +98 -0
- package/src/dto/signup.dto.ts +174 -0
- package/src/dto/social-auth.dto.ts +422 -0
- package/src/dto/trust-device-response.dto.ts +30 -0
- package/src/dto/trust-device.dto.ts +9 -0
- package/src/dto/update-user-attributes-request.dto.ts +51 -0
- package/src/dto/user-response.dto.ts +138 -0
- package/src/dto/user-update.dto.ts +222 -0
- package/src/dto/verify-email.dto.ts +313 -0
- package/src/dto/verify-mfa-code.dto.ts +103 -0
- package/src/dto/verify-phone-by-sub.dto.ts +78 -0
- package/src/dto/verify-phone.dto.ts +245 -0
- package/src/entities/auth-audit.entity.ts +232 -0
- package/src/entities/challenge-session.entity.ts +116 -0
- package/src/entities/index.ts +29 -0
- package/src/entities/login-attempt.entity.ts +64 -0
- package/src/entities/mfa-device.entity.ts +151 -0
- package/src/entities/rate-limit.entity.ts +44 -0
- package/src/entities/session.entity.ts +180 -0
- package/src/entities/social-account.entity.ts +96 -0
- package/src/entities/storage-lock.entity.ts +39 -0
- package/src/entities/trusted-device.entity.ts +112 -0
- package/src/entities/user.entity.ts +243 -0
- package/src/entities/verification-token.entity.ts +141 -0
- package/src/enums/auth-audit-event-type.enum.ts +360 -0
- package/src/enums/error-codes.enum.ts +420 -0
- package/src/enums/mfa-method.enum.ts +97 -0
- package/src/enums/risk-factor.enum.ts +111 -0
- package/src/exceptions/nauth.exception.ts +231 -0
- package/src/handlers/auth.handler.ts +260 -0
- package/src/handlers/client-info.handler.ts +101 -0
- package/src/handlers/csrf.handler.ts +156 -0
- package/src/handlers/token-delivery.handler.ts +118 -0
- package/src/index.ts +118 -0
- package/src/interfaces/client-info.interface.ts +85 -0
- package/src/interfaces/config.interface.ts +2135 -0
- package/src/interfaces/entities.interface.ts +226 -0
- package/src/interfaces/index.ts +15 -0
- package/src/interfaces/logger.interface.ts +283 -0
- package/src/interfaces/mfa-provider.interface.ts +154 -0
- package/src/interfaces/oauth.interface.ts +148 -0
- package/src/interfaces/provider.interface.ts +47 -0
- package/src/interfaces/social-auth-provider.interface.ts +131 -0
- package/src/interfaces/storage-adapter.interface.ts +82 -0
- package/src/interfaces/template.interface.ts +510 -0
- package/src/interfaces/token-verifier.interface.ts +110 -0
- package/src/internal.ts +178 -0
- package/src/platform/interfaces.ts +299 -0
- package/src/schemas/auth-config.schema.ts +646 -0
- package/src/services/adaptive-mfa-decision.service.spec.ts +1058 -0
- package/src/services/adaptive-mfa-decision.service.ts +457 -0
- package/src/services/auth-audit.service.spec.ts +675 -0
- package/src/services/auth-audit.service.ts +558 -0
- package/src/services/auth-challenge-helper.service.spec.ts +3227 -0
- package/src/services/auth-challenge-helper.service.ts +825 -0
- package/src/services/auth-flow-context-builder.service.ts +520 -0
- package/src/services/auth-flow-rules.ts +202 -0
- package/src/services/auth-flow-state-definitions.ts +190 -0
- package/src/services/auth-flow-state-machine.service.ts +207 -0
- package/src/services/auth-flow-state-machine.types.ts +316 -0
- package/src/services/auth.service.spec.ts +4195 -0
- package/src/services/auth.service.ts +3727 -0
- package/src/services/challenge.service.spec.ts +1363 -0
- package/src/services/challenge.service.ts +696 -0
- package/src/services/client-info.service.spec.ts +572 -0
- package/src/services/client-info.service.ts +374 -0
- package/src/services/csrf.service.ts +54 -0
- package/src/services/email-verification.service.spec.ts +1229 -0
- package/src/services/email-verification.service.ts +578 -0
- package/src/services/geo-location.service.spec.ts +603 -0
- package/src/services/geo-location.service.ts +599 -0
- package/src/services/index.ts +13 -0
- package/src/services/jwt.service.spec.ts +882 -0
- package/src/services/jwt.service.ts +621 -0
- package/src/services/mfa-base.service.spec.ts +246 -0
- package/src/services/mfa-base.service.ts +611 -0
- package/src/services/mfa.service.spec.ts +693 -0
- package/src/services/mfa.service.ts +960 -0
- package/src/services/password.service.spec.ts +166 -0
- package/src/services/password.service.ts +309 -0
- package/src/services/phone-verification.service.spec.ts +1120 -0
- package/src/services/phone-verification.service.ts +751 -0
- package/src/services/risk-detection.service.spec.ts +1292 -0
- package/src/services/risk-detection.service.ts +1012 -0
- package/src/services/risk-scoring.service.spec.ts +204 -0
- package/src/services/risk-scoring.service.ts +131 -0
- package/src/services/session.service.spec.ts +1293 -0
- package/src/services/session.service.ts +803 -0
- package/src/services/social-account.service.spec.ts +725 -0
- package/src/services/social-auth-base.service.spec.ts +418 -0
- package/src/services/social-auth-base.service.ts +581 -0
- package/src/services/social-auth.service.spec.ts +238 -0
- package/src/services/social-auth.service.ts +436 -0
- package/src/services/social-provider-registry.service.spec.ts +238 -0
- package/src/services/social-provider-registry.service.ts +122 -0
- package/src/services/trusted-device.service.spec.ts +505 -0
- package/src/services/trusted-device.service.ts +339 -0
- package/src/storage/account-lockout-storage.service.spec.ts +310 -0
- package/src/storage/account-lockout-storage.service.ts +89 -0
- package/src/storage/index.ts +3 -0
- package/src/storage/memory-storage.adapter.ts +443 -0
- package/src/storage/rate-limit-storage.service.spec.ts +247 -0
- package/src/storage/rate-limit-storage.service.ts +38 -0
- package/src/templates/html-template.engine.spec.ts +161 -0
- package/src/templates/html-template.engine.ts +688 -0
- package/src/templates/index.ts +7 -0
- package/src/utils/common-passwords.spec.ts +230 -0
- package/src/utils/common-passwords.ts +170 -0
- package/src/utils/context-storage.ts +188 -0
- package/src/utils/cookie-names.util.ts +67 -0
- package/src/utils/cookies.util.ts +94 -0
- package/src/utils/index.ts +12 -0
- package/src/utils/ip-extractor.spec.ts +330 -0
- package/src/utils/ip-extractor.ts +220 -0
- package/src/utils/nauth-logger.spec.ts +388 -0
- package/src/utils/nauth-logger.ts +215 -0
- package/src/utils/pii-redactor.spec.ts +130 -0
- package/src/utils/pii-redactor.ts +288 -0
- package/src/utils/setup/get-repositories.ts +140 -0
- package/src/utils/setup/init-services.ts +422 -0
- package/src/utils/setup/init-social.ts +189 -0
- package/src/utils/setup/init-storage.ts +94 -0
- package/src/utils/setup/register-mfa.ts +165 -0
- package/src/utils/setup/run-nauth-migrations.ts +61 -0
- package/src/utils/token-delivery-policy.ts +38 -0
- package/src/validators/template.validator.ts +219 -0
- package/tsconfig.json +37 -0
- package/tsconfig.lint.json +6 -0
|
@@ -0,0 +1,960 @@
|
|
|
1
|
+
import { Repository } from 'typeorm';
|
|
2
|
+
import { BaseMFADevice, BaseUser } from '../entities';
|
|
3
|
+
import { IUser, IMFADevice } from '../interfaces/entities.interface';
|
|
4
|
+
import { IMFAProviderService } from '../interfaces/mfa-provider.interface';
|
|
5
|
+
import { NAuthException } from '../exceptions/nauth.exception';
|
|
6
|
+
import { AuthErrorCode } from '../enums/error-codes.enum';
|
|
7
|
+
import { MFAMethod, MFADeviceMethod } from '../enums/mfa-method.enum';
|
|
8
|
+
import { ChallengeService } from './challenge.service';
|
|
9
|
+
import { AuthChallenge } from '../dto/auth-challenge.dto';
|
|
10
|
+
import { NAuthConfig } from '../interfaces/config.interface';
|
|
11
|
+
import { NAuthLogger } from '../utils/nauth-logger';
|
|
12
|
+
import { InternalAuthAuditService as AuthAuditService } from './auth-audit.service';
|
|
13
|
+
import { AuthAuditEventType } from '../enums/auth-audit-event-type.enum';
|
|
14
|
+
import { ClientInfoService } from './client-info.service';
|
|
15
|
+
import {
|
|
16
|
+
GetAvailableMethodsDTO,
|
|
17
|
+
GetAvailableMethodsResponseDTO,
|
|
18
|
+
GetChallengeDataDTO,
|
|
19
|
+
GetChallengeDataResponseDTO,
|
|
20
|
+
GetMFAStatusDTO,
|
|
21
|
+
GetMFAStatusResponseDTO,
|
|
22
|
+
GetSetupDataDTO,
|
|
23
|
+
GetSetupDataResponseDTO,
|
|
24
|
+
GetUserDevicesDTO,
|
|
25
|
+
GetUserDevicesResponseDTO,
|
|
26
|
+
HasProviderDTO,
|
|
27
|
+
HasProviderResponseDTO,
|
|
28
|
+
ListProvidersResponseDTO,
|
|
29
|
+
RemoveDevicesDTO,
|
|
30
|
+
RemoveDevicesResponseDTO,
|
|
31
|
+
SetMFAExemptionDTO,
|
|
32
|
+
SetMFAExemptionResponseDTO,
|
|
33
|
+
SetPreferredMethodDTO,
|
|
34
|
+
SetPreferredMethodResponseDTO,
|
|
35
|
+
SetupMFADTO,
|
|
36
|
+
SetupMFAResponseDTO,
|
|
37
|
+
VerifyMFACodeDTO,
|
|
38
|
+
VerifyMFACodeResponseDTO,
|
|
39
|
+
} from '../dto';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* MFA Service Registry
|
|
43
|
+
*
|
|
44
|
+
* Central registry for managing MFA provider services.
|
|
45
|
+
* Routes requests to the appropriate provider based on method name.
|
|
46
|
+
*
|
|
47
|
+
* Provider services (TOTP, SMS, Passkey) automatically register themselves
|
|
48
|
+
* when their modules are imported via OnModuleInit.
|
|
49
|
+
*
|
|
50
|
+
* **Key Features:**
|
|
51
|
+
* - Provider registration and lookup
|
|
52
|
+
* - Unified interface for MFA operations
|
|
53
|
+
* - Routing verification requests to correct provider
|
|
54
|
+
* - Device management operations
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* @Controller('auth')
|
|
59
|
+
* export class AuthController {
|
|
60
|
+
* constructor(private readonly mfaService: MFAService) {}
|
|
61
|
+
*
|
|
62
|
+
* @Post('mfa/verify')
|
|
63
|
+
* async verifyMFA(@Body() dto: { method: string; code: string }) {
|
|
64
|
+
* const provider = this.mfaService.getProvider(dto.method);
|
|
65
|
+
* return await provider.verify(user, dto.code);
|
|
66
|
+
* }
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export class MFAService {
|
|
71
|
+
private readonly providers = new Map<string, IMFAProviderService>();
|
|
72
|
+
|
|
73
|
+
constructor(
|
|
74
|
+
private readonly mfaDeviceRepository: Repository<BaseMFADevice>,
|
|
75
|
+
private readonly userRepository: Repository<BaseUser>,
|
|
76
|
+
private readonly challengeService?: ChallengeService,
|
|
77
|
+
private readonly config?: NAuthConfig,
|
|
78
|
+
private readonly logger?: NAuthLogger,
|
|
79
|
+
private readonly auditService?: AuthAuditService,
|
|
80
|
+
private readonly clientInfoService?: ClientInfoService,
|
|
81
|
+
) {}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Register an MFA provider
|
|
85
|
+
*
|
|
86
|
+
* Called automatically by provider modules during initialization.
|
|
87
|
+
* Provider method names must be unique.
|
|
88
|
+
*
|
|
89
|
+
* @param provider - Provider service instance (must have methodName property)
|
|
90
|
+
* @throws {NAuthException} If provider is already registered
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* // In provider module's OnModuleInit
|
|
95
|
+
* this.mfaService.registerProvider(this.totpProvider);
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
registerProvider(provider: IMFAProviderService): void {
|
|
99
|
+
const name = provider.methodName;
|
|
100
|
+
if (this.providers.has(name)) {
|
|
101
|
+
throw new NAuthException(AuthErrorCode.VALIDATION_FAILED, `MFA provider '${name}' is already registered`);
|
|
102
|
+
}
|
|
103
|
+
this.providers.set(name, provider);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get a provider by method name
|
|
108
|
+
*
|
|
109
|
+
* @param methodName - Method name (e.g., 'totp', 'sms', 'passkey')
|
|
110
|
+
* @returns Provider service instance
|
|
111
|
+
* @throws {NAuthException} If provider is not registered
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const totpProvider = this.mfaService.getProvider('totp');
|
|
116
|
+
* const setupData = await totpProvider.setup(user);
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
getProvider(methodName: string): IMFAProviderService {
|
|
120
|
+
const provider = this.providers.get(methodName);
|
|
121
|
+
if (!provider) {
|
|
122
|
+
throw new NAuthException(
|
|
123
|
+
AuthErrorCode.VALIDATION_FAILED,
|
|
124
|
+
`MFA provider '${methodName}' is not registered. Import the provider module (e.g., TOTPMFAModule) and ensure it's properly configured.`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return provider;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Check if a provider is registered
|
|
132
|
+
*
|
|
133
|
+
* @param dto - Request DTO with method name
|
|
134
|
+
* @returns Response DTO with hasProvider flag
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const result = await this.mfaService.hasProvider({ methodName: 'totp' });
|
|
139
|
+
* if (result.hasProvider) {
|
|
140
|
+
* // TOTP is available
|
|
141
|
+
* }
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
hasProvider(dto: HasProviderDTO): HasProviderResponseDTO {
|
|
145
|
+
return {
|
|
146
|
+
hasProvider: this.providers.has(dto.methodName),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get all registered provider method names
|
|
152
|
+
*
|
|
153
|
+
* @returns Response DTO with array of method names
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* const result = this.mfaService.listProviders(); // { providers: ['totp', 'sms', 'passkey'] }
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
listProviders(): ListProvidersResponseDTO {
|
|
161
|
+
return {
|
|
162
|
+
providers: Array.from(this.providers.keys()),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get available MFA methods for a user
|
|
168
|
+
*
|
|
169
|
+
* Returns list of methods that are:
|
|
170
|
+
* - Registered as providers
|
|
171
|
+
* - Allowed by configuration
|
|
172
|
+
*
|
|
173
|
+
* This returns ALL methods that can be set up, not just ones the user has configured.
|
|
174
|
+
* Use getUserDevices() to check which methods the user has actually set up.
|
|
175
|
+
*
|
|
176
|
+
* @param dto - Request DTO with user sub
|
|
177
|
+
* @returns Response DTO with array of available method names
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```typescript
|
|
181
|
+
* const result = await this.mfaService.getAvailableMethods({ sub: user.sub });
|
|
182
|
+
* // Returns: { availableMethods: ['totp', 'sms', 'passkey'] }
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
async getAvailableMethods(dto: GetAvailableMethodsDTO): Promise<GetAvailableMethodsResponseDTO> {
|
|
186
|
+
// Look up user by sub to validate user exists
|
|
187
|
+
const userEntity = await this.userRepository.findOne({ where: { sub: dto.sub } });
|
|
188
|
+
if (!userEntity) {
|
|
189
|
+
throw new NAuthException(AuthErrorCode.NOT_FOUND, 'User not found');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const available: string[] = [];
|
|
193
|
+
|
|
194
|
+
for (const [methodName, provider] of this.providers.entries()) {
|
|
195
|
+
// Check if method is allowed by configuration
|
|
196
|
+
if (!provider.isMethodAllowed()) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Return all allowed methods (whether user has set them up or not)
|
|
201
|
+
available.push(methodName);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
availableMethods: available,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Verify MFA code using appropriate provider
|
|
211
|
+
*
|
|
212
|
+
* Routes the verification request to the correct provider based on method name.
|
|
213
|
+
*
|
|
214
|
+
* @param dto - Request DTO with user sub, method name, code, and optional device ID
|
|
215
|
+
* @returns Response DTO with verification result
|
|
216
|
+
* @throws {NAuthException} If method is not available or verification fails
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* // Verify TOTP code
|
|
221
|
+
* const result = await this.mfaService.verifyCode({
|
|
222
|
+
* sub: user.sub,
|
|
223
|
+
* methodName: 'totp',
|
|
224
|
+
* code: '123456'
|
|
225
|
+
* });
|
|
226
|
+
*
|
|
227
|
+
* // Verify backup code
|
|
228
|
+
* const result = await this.mfaService.verifyCode({
|
|
229
|
+
* sub: user.sub,
|
|
230
|
+
* methodName: 'backup',
|
|
231
|
+
* code: 'ABC12345'
|
|
232
|
+
* });
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
async verifyCode(dto: VerifyMFACodeDTO): Promise<VerifyMFACodeResponseDTO> {
|
|
236
|
+
// Look up user by sub
|
|
237
|
+
const userEntity = await this.userRepository.findOne({ where: { sub: dto.sub } });
|
|
238
|
+
if (!userEntity) {
|
|
239
|
+
throw new NAuthException(AuthErrorCode.NOT_FOUND, 'User not found');
|
|
240
|
+
}
|
|
241
|
+
const user = userEntity as unknown as IUser;
|
|
242
|
+
|
|
243
|
+
// Handle backup codes specially (not a provider, uses base class helper)
|
|
244
|
+
if (dto.methodName === MFAMethod.BACKUP) {
|
|
245
|
+
// Get any provider to access backup code verification
|
|
246
|
+
// All providers extend BaseMFAProviderService which has verifyBackupCode
|
|
247
|
+
const firstProvider = Array.from(this.providers.values())[0];
|
|
248
|
+
if (firstProvider && 'verifyBackupCode' in firstProvider) {
|
|
249
|
+
const providerWithBackup = firstProvider as IMFAProviderService & {
|
|
250
|
+
verifyBackupCode: (user: IUser, code: string) => Promise<boolean>;
|
|
251
|
+
};
|
|
252
|
+
const isValid = await providerWithBackup.verifyBackupCode(user, dto.code as string);
|
|
253
|
+
return { valid: isValid };
|
|
254
|
+
}
|
|
255
|
+
throw new NAuthException(AuthErrorCode.VALIDATION_FAILED, 'Backup code verification not available');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Get provider and verify
|
|
259
|
+
const provider = this.getProvider(dto.methodName);
|
|
260
|
+
const isValid = await provider.verify(user, dto.code, dto.deviceId);
|
|
261
|
+
return { valid: isValid };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Setup MFA device using appropriate provider
|
|
266
|
+
*
|
|
267
|
+
* @param dto - Request DTO with user sub, method name, and optional setup data
|
|
268
|
+
* @returns Response DTO with provider-specific setup data
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* const result = await this.mfaService.setup({
|
|
273
|
+
* sub: user.sub,
|
|
274
|
+
* methodName: 'totp'
|
|
275
|
+
* });
|
|
276
|
+
* // Returns: { setupData: { secret, qrCode, manualEntryKey } }
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
async setup(dto: SetupMFADTO): Promise<SetupMFAResponseDTO> {
|
|
280
|
+
// Look up user by sub
|
|
281
|
+
const userEntity = await this.userRepository.findOne({ where: { sub: dto.sub } });
|
|
282
|
+
if (!userEntity) {
|
|
283
|
+
throw new NAuthException(AuthErrorCode.NOT_FOUND, 'User not found');
|
|
284
|
+
}
|
|
285
|
+
const user = userEntity as unknown as IUser;
|
|
286
|
+
|
|
287
|
+
const provider = this.getProvider(dto.methodName);
|
|
288
|
+
const setupData = await provider.setup(user, dto.setupData);
|
|
289
|
+
return {
|
|
290
|
+
setupData: setupData as Record<string, unknown>,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Get user's MFA devices
|
|
296
|
+
*
|
|
297
|
+
* @param dto - Request DTO with user sub
|
|
298
|
+
* @returns Response DTO with array of MFA devices
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* ```typescript
|
|
302
|
+
* const result = await this.mfaService.getUserDevices({ sub: user.sub });
|
|
303
|
+
* // Returns: { devices: [...] }
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
async getUserDevices(dto: GetUserDevicesDTO): Promise<GetUserDevicesResponseDTO> {
|
|
307
|
+
// Look up user by sub to get internal ID
|
|
308
|
+
const userEntity = await this.userRepository.findOne({ where: { sub: dto.sub } });
|
|
309
|
+
if (!userEntity) {
|
|
310
|
+
throw new NAuthException(AuthErrorCode.NOT_FOUND, 'User not found');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Only fetch active devices (inactive devices are soft-deleted)
|
|
314
|
+
const devices = await this.mfaDeviceRepository.find({
|
|
315
|
+
where: { userId: userEntity.id, isActive: true },
|
|
316
|
+
order: { createdAt: 'DESC' },
|
|
317
|
+
} as Record<string, unknown>);
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
devices: devices as unknown as IMFADevice[],
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Get comprehensive MFA status for a user
|
|
326
|
+
*
|
|
327
|
+
* Returns complete MFA configuration status including:
|
|
328
|
+
* - Whether MFA is enabled/required
|
|
329
|
+
* - Configured and available methods
|
|
330
|
+
* - Preferred method
|
|
331
|
+
* - Backup codes status
|
|
332
|
+
* - MFA exemption information
|
|
333
|
+
*
|
|
334
|
+
* This method encapsulates all business logic for MFA status,
|
|
335
|
+
* ensuring consumer apps don't need to query databases or build responses manually.
|
|
336
|
+
*
|
|
337
|
+
* @param dto - Request DTO with user sub
|
|
338
|
+
* @returns Response DTO with complete MFA status
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```typescript
|
|
342
|
+
* @Get('mfa/status')
|
|
343
|
+
* async getMFAStatus(@CurrentUser() user: IUser) {
|
|
344
|
+
* return await this.mfaService.getMFAStatus({ sub: user.sub });
|
|
345
|
+
* }
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
async getMFAStatus(dto: GetMFAStatusDTO): Promise<GetMFAStatusResponseDTO> {
|
|
349
|
+
// Get user entity with MFA-related fields
|
|
350
|
+
// Note: mfaExemptGrantedBy is intentionally excluded as it's sensitive admin information
|
|
351
|
+
const userEntity = await this.userRepository.findOne({
|
|
352
|
+
select: [
|
|
353
|
+
'id',
|
|
354
|
+
'mfaEnabled',
|
|
355
|
+
'backupCodes',
|
|
356
|
+
'preferredMfaMethod',
|
|
357
|
+
'mfaExempt',
|
|
358
|
+
'mfaExemptReason',
|
|
359
|
+
'mfaExemptGrantedAt',
|
|
360
|
+
],
|
|
361
|
+
where: { sub: dto.sub },
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
if (!userEntity) {
|
|
365
|
+
throw new NAuthException(AuthErrorCode.NOT_FOUND, 'User not found');
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const enabled = userEntity.mfaEnabled || false;
|
|
369
|
+
|
|
370
|
+
// Get available methods (all registered & allowed methods)
|
|
371
|
+
const availableMethodsResult = await this.getAvailableMethods({ sub: dto.sub });
|
|
372
|
+
|
|
373
|
+
// Add 'backup' to available methods if backup codes are enabled in config
|
|
374
|
+
const finalAvailableMethods = [...availableMethodsResult.availableMethods];
|
|
375
|
+
if (this.config?.mfa?.backup?.enabled) {
|
|
376
|
+
if (!finalAvailableMethods.includes(MFAMethod.BACKUP)) {
|
|
377
|
+
finalAvailableMethods.push(MFAMethod.BACKUP);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Get user's configured devices
|
|
382
|
+
const devicesResult = await this.getUserDevices({ sub: dto.sub });
|
|
383
|
+
const configuredMethods = [
|
|
384
|
+
...new Set(devicesResult.devices.filter((d) => d.isActive).map((d) => d.type)),
|
|
385
|
+
] as MFADeviceMethod[];
|
|
386
|
+
|
|
387
|
+
// Determine if MFA is required based on config and user state
|
|
388
|
+
const required = enabled && configuredMethods.length > 0;
|
|
389
|
+
|
|
390
|
+
// Check backup codes
|
|
391
|
+
const hasBackupCodes = !!userEntity.backupCodes && userEntity.backupCodes.length > 0;
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
enabled,
|
|
395
|
+
required,
|
|
396
|
+
configuredMethods,
|
|
397
|
+
availableMethods: finalAvailableMethods,
|
|
398
|
+
hasBackupCodes,
|
|
399
|
+
preferredMethod: userEntity.preferredMfaMethod as MFADeviceMethod | undefined,
|
|
400
|
+
mfaExempt: userEntity.mfaExempt || false,
|
|
401
|
+
mfaExemptReason: userEntity.mfaExemptReason || null,
|
|
402
|
+
mfaExemptGrantedAt: userEntity.mfaExemptGrantedAt || null,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Remove MFA devices by method type
|
|
408
|
+
*
|
|
409
|
+
* Comprehensive method that handles all aspects of MFA device removal:
|
|
410
|
+
* - Looks up user by sub (consumer apps should pass user.sub from @CurrentUser())
|
|
411
|
+
* - Validates method type
|
|
412
|
+
* - Removes all active devices of the specified method type
|
|
413
|
+
* - Updates user's preferred method if the removed method was preferred
|
|
414
|
+
* - Updates device primary flags
|
|
415
|
+
* - Disables MFA if this was the last device
|
|
416
|
+
* - Creates MFA_SETUP_REQUIRED challenge if MFA enforcement requires it
|
|
417
|
+
*
|
|
418
|
+
* This method encapsulates all database operations related to MFA device removal,
|
|
419
|
+
* ensuring the consumer app doesn't need to directly manipulate nauth_* tables.
|
|
420
|
+
*
|
|
421
|
+
* @param dto - Request DTO with user sub and method type
|
|
422
|
+
* @returns Response DTO with deletedCount and whether MFA was disabled
|
|
423
|
+
* @throws {NAuthException} If user not found, invalid method type, or no devices found
|
|
424
|
+
*
|
|
425
|
+
* @example
|
|
426
|
+
* ```typescript
|
|
427
|
+
* // Consumer app controller
|
|
428
|
+
* @Delete('mfa/devices/:method')
|
|
429
|
+
* async removeMFAMethod(@CurrentUser() user: IUser, @Param('method') method: string) {
|
|
430
|
+
* const result = await this.mfaService.removeDevices({ userSub: user.sub, methodType: method });
|
|
431
|
+
* return { message: 'MFA method removed successfully', ...result };
|
|
432
|
+
* }
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
async removeDevices(dto: RemoveDevicesDTO): Promise<RemoveDevicesResponseDTO> {
|
|
436
|
+
// Validate method type
|
|
437
|
+
const validMethods = [MFAMethod.TOTP, MFAMethod.SMS, MFAMethod.EMAIL, MFAMethod.PASSKEY];
|
|
438
|
+
const normalizedMethod = dto.methodType.toLowerCase();
|
|
439
|
+
if (!validMethods.includes(normalizedMethod as MFAMethod)) {
|
|
440
|
+
throw new NAuthException(
|
|
441
|
+
AuthErrorCode.VALIDATION_FAILED,
|
|
442
|
+
`Invalid MFA method: ${dto.methodType}. Valid methods are: ${validMethods.join(', ')}`,
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Look up user by sub using repository directly (no AuthService dependency needed)
|
|
447
|
+
const userEntity = await this.userRepository.findOne({ where: { sub: dto.userSub } });
|
|
448
|
+
if (!userEntity) {
|
|
449
|
+
throw new NAuthException(AuthErrorCode.NOT_FOUND, 'User entity not found');
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const userId = userEntity.id;
|
|
453
|
+
if (!userId) {
|
|
454
|
+
throw new NAuthException(AuthErrorCode.INTERNAL_ERROR, 'User entity missing internal ID');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Cast to IUser for type safety
|
|
458
|
+
const user = userEntity as unknown as IUser;
|
|
459
|
+
|
|
460
|
+
const preferredMethod = userEntity.preferredMfaMethod;
|
|
461
|
+
const isPreferredMethod = preferredMethod === normalizedMethod;
|
|
462
|
+
|
|
463
|
+
// Get all active devices for this user
|
|
464
|
+
const devicesResult = await this.getUserDevices({ sub: dto.userSub });
|
|
465
|
+
const activeDevices = devicesResult.devices.filter((d) => d.isActive);
|
|
466
|
+
|
|
467
|
+
// Get devices of the method type to remove
|
|
468
|
+
const devicesToRemove = activeDevices.filter((d) => d.type.toLowerCase() === normalizedMethod);
|
|
469
|
+
|
|
470
|
+
if (devicesToRemove.length === 0) {
|
|
471
|
+
throw new NAuthException(
|
|
472
|
+
AuthErrorCode.VALIDATION_FAILED,
|
|
473
|
+
`No active ${normalizedMethod} MFA devices found for this user`,
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Delete all devices of this method type
|
|
478
|
+
let deletedCount = 0;
|
|
479
|
+
for (const device of devicesToRemove) {
|
|
480
|
+
const result = await this.mfaDeviceRepository.delete(device.id);
|
|
481
|
+
deletedCount += result.affected || 0;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Check if any devices remain after removal
|
|
485
|
+
const remainingDevicesResult = await this.getUserDevices({ sub: dto.userSub });
|
|
486
|
+
const remainingActiveDevices = remainingDevicesResult.devices.filter((d) => d.isActive);
|
|
487
|
+
let mfaDisabled = false;
|
|
488
|
+
|
|
489
|
+
// If no active devices remain, disable MFA for user
|
|
490
|
+
if (remainingActiveDevices.length === 0) {
|
|
491
|
+
userEntity.mfaEnabled = false;
|
|
492
|
+
userEntity.mfaMethods = [];
|
|
493
|
+
userEntity.preferredMfaMethod = null;
|
|
494
|
+
await this.userRepository.save(userEntity);
|
|
495
|
+
mfaDisabled = true;
|
|
496
|
+
|
|
497
|
+
// ============================================================================
|
|
498
|
+
// Audit: Record MFA disabled (all devices removed)
|
|
499
|
+
// ============================================================================
|
|
500
|
+
if (this.auditService && this.clientInfoService) {
|
|
501
|
+
try {
|
|
502
|
+
await this.auditService?.recordEvent({
|
|
503
|
+
userId: user.id,
|
|
504
|
+
eventType: AuthAuditEventType.MFA_DISABLED,
|
|
505
|
+
eventStatus: 'INFO',
|
|
506
|
+
reason: 'all_devices_removed',
|
|
507
|
+
description: 'MFA disabled - all devices removed',
|
|
508
|
+
// Client info automatically included from context
|
|
509
|
+
metadata: {
|
|
510
|
+
removedMethod: normalizedMethod,
|
|
511
|
+
deletedCount,
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
} catch (auditError) {
|
|
515
|
+
// Non-blocking: Log but continue
|
|
516
|
+
const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
|
|
517
|
+
this.logger?.error?.(`Failed to record MFA_DISABLED audit event: ${errorMessage}`, {
|
|
518
|
+
error: auditError,
|
|
519
|
+
userId: user.id,
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Automatically create MFA_SETUP_REQUIRED challenge if MFA enforcement requires it
|
|
525
|
+
if (this.challengeService && this.config?.mfa?.enabled) {
|
|
526
|
+
const enforcement = this.config.mfa.enforcement || 'OPTIONAL';
|
|
527
|
+
if (enforcement === 'REQUIRED' || enforcement === 'ADAPTIVE') {
|
|
528
|
+
const user = userEntity as unknown as IUser;
|
|
529
|
+
try {
|
|
530
|
+
// Client info (ipAddress, userAgent) automatically extracted from ClientInfoService
|
|
531
|
+
await this.challengeService.createChallengeSession(user, AuthChallenge.MFA_SETUP_REQUIRED, {
|
|
532
|
+
allowedMethods: this.config.mfa.allowedMethods || [],
|
|
533
|
+
requiresSetup: true,
|
|
534
|
+
});
|
|
535
|
+
this.logger?.log?.(`Created MFA_SETUP_REQUIRED challenge for user ${user.sub} after MFA removal`);
|
|
536
|
+
} catch (error) {
|
|
537
|
+
// Log but don't fail the removal if challenge creation fails
|
|
538
|
+
this.logger?.warn?.(`Failed to create MFA_SETUP_REQUIRED challenge after MFA removal: ${error}`);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
} else {
|
|
543
|
+
// Update mfaMethods array with remaining methods
|
|
544
|
+
const remainingMethods = [...new Set(remainingActiveDevices.map((d) => d.type))];
|
|
545
|
+
userEntity.mfaMethods = remainingMethods;
|
|
546
|
+
|
|
547
|
+
// If the removed method was preferred, update preferred method and device primary flags
|
|
548
|
+
if (isPreferredMethod) {
|
|
549
|
+
const newPreferredMethod = remainingActiveDevices[0].type;
|
|
550
|
+
userEntity.preferredMfaMethod = newPreferredMethod;
|
|
551
|
+
await this.userRepository.save(userEntity);
|
|
552
|
+
|
|
553
|
+
// Update device primary flags - set first remaining device as primary
|
|
554
|
+
if (remainingActiveDevices[0].id) {
|
|
555
|
+
await this.mfaDeviceRepository.update({ id: remainingActiveDevices[0].id }, { isPrimary: true });
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Unset primary flag on other devices
|
|
559
|
+
for (let i = 1; i < remainingActiveDevices.length; i++) {
|
|
560
|
+
if (remainingActiveDevices[i].id) {
|
|
561
|
+
await this.mfaDeviceRepository.update({ id: remainingActiveDevices[i].id }, { isPrimary: false });
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
this.logger?.log?.(`Updated preferred MFA method to ${newPreferredMethod} after removing ${normalizedMethod}`);
|
|
566
|
+
} else {
|
|
567
|
+
// No preferred method change needed, just update mfaMethods
|
|
568
|
+
await this.userRepository.save(userEntity);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// ============================================================================
|
|
573
|
+
// Audit: Record MFA device removal
|
|
574
|
+
// ============================================================================
|
|
575
|
+
if (deletedCount > 0 && this.auditService && this.clientInfoService) {
|
|
576
|
+
try {
|
|
577
|
+
const user = userEntity as unknown as IUser;
|
|
578
|
+
await this.auditService?.recordEvent({
|
|
579
|
+
userId: user.id,
|
|
580
|
+
eventType: AuthAuditEventType.MFA_DEVICE_REMOVED,
|
|
581
|
+
eventStatus: 'INFO',
|
|
582
|
+
metadata: {
|
|
583
|
+
method: normalizedMethod,
|
|
584
|
+
deletedCount,
|
|
585
|
+
remainingDevices: remainingActiveDevices.length,
|
|
586
|
+
mfaDisabled,
|
|
587
|
+
},
|
|
588
|
+
// Client info automatically included from context
|
|
589
|
+
});
|
|
590
|
+
} catch (auditError) {
|
|
591
|
+
// Non-blocking: Log but continue
|
|
592
|
+
const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
|
|
593
|
+
this.logger?.error?.(`Failed to record MFA_DEVICE_REMOVED audit event: ${errorMessage}`, {
|
|
594
|
+
error: auditError,
|
|
595
|
+
userId: user.id,
|
|
596
|
+
method: normalizedMethod,
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
return { deletedCount, mfaDisabled };
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Set preferred MFA method for a user
|
|
606
|
+
*
|
|
607
|
+
* Updates the user's preferred MFA method and device primary flags.
|
|
608
|
+
* Validates that the method is configured for the user before setting it as preferred.
|
|
609
|
+
*
|
|
610
|
+
* This method encapsulates all database operations related to preferred method updates,
|
|
611
|
+
* ensuring the consumer app doesn't need to directly manipulate nauth_* tables.
|
|
612
|
+
*
|
|
613
|
+
* @param dto - Request DTO with user sub and method type
|
|
614
|
+
* @returns Response DTO with success message
|
|
615
|
+
* @throws {NAuthException} If user not found, invalid method type, or method not configured
|
|
616
|
+
*
|
|
617
|
+
* @example
|
|
618
|
+
* ```typescript
|
|
619
|
+
* // Consumer app controller
|
|
620
|
+
* @Put('mfa/preferred')
|
|
621
|
+
* async setPreferredMFAMethod(@CurrentUser() user: IUser, @Body() body: { method: string }) {
|
|
622
|
+
* return await this.mfaService.setPreferredMethod({ userSub: user.sub, methodType: body.method });
|
|
623
|
+
* }
|
|
624
|
+
* ```
|
|
625
|
+
*/
|
|
626
|
+
async setPreferredMethod(dto: SetPreferredMethodDTO): Promise<SetPreferredMethodResponseDTO> {
|
|
627
|
+
// Validate method type
|
|
628
|
+
const validMethods = [MFAMethod.TOTP, MFAMethod.SMS, MFAMethod.EMAIL, MFAMethod.PASSKEY];
|
|
629
|
+
const normalizedMethod = dto.methodType.toLowerCase();
|
|
630
|
+
if (!validMethods.includes(normalizedMethod as MFAMethod)) {
|
|
631
|
+
throw new NAuthException(
|
|
632
|
+
AuthErrorCode.VALIDATION_FAILED,
|
|
633
|
+
`Invalid MFA method: ${dto.methodType}. Valid methods are: ${validMethods.join(', ')}`,
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// Look up user by sub using repository directly (no AuthService dependency needed)
|
|
638
|
+
const userEntity = await this.userRepository.findOne({ where: { sub: dto.userSub } });
|
|
639
|
+
if (!userEntity) {
|
|
640
|
+
throw new NAuthException(AuthErrorCode.NOT_FOUND, 'User not found');
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const userId = userEntity.id;
|
|
644
|
+
if (!userId) {
|
|
645
|
+
throw new NAuthException(AuthErrorCode.INTERNAL_ERROR, 'User entity missing internal ID');
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Cast to IUser for type safety
|
|
649
|
+
const user = userEntity as unknown as IUser;
|
|
650
|
+
|
|
651
|
+
// Verify user has this method configured
|
|
652
|
+
const devicesResult = await this.getUserDevices({ sub: dto.userSub });
|
|
653
|
+
// Normalize device types for comparison (database might store in different case)
|
|
654
|
+
const preferredDevice = devicesResult.devices.find((d) => d.type.toLowerCase() === normalizedMethod && d.isActive);
|
|
655
|
+
|
|
656
|
+
if (!preferredDevice) {
|
|
657
|
+
throw new NAuthException(
|
|
658
|
+
AuthErrorCode.VALIDATION_FAILED,
|
|
659
|
+
`MFA method '${normalizedMethod}' is not configured for this user`,
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// Update user's preferred method directly via repository
|
|
664
|
+
await this.userRepository.update(
|
|
665
|
+
{ id: userId },
|
|
666
|
+
{
|
|
667
|
+
preferredMfaMethod: normalizedMethod as MFADeviceMethod,
|
|
668
|
+
},
|
|
669
|
+
);
|
|
670
|
+
|
|
671
|
+
// Update device isPrimary flags: set preferred device as primary, unset others
|
|
672
|
+
const activeDevices = devicesResult.devices.filter((d) => d.isActive);
|
|
673
|
+
for (const device of activeDevices) {
|
|
674
|
+
await this.mfaDeviceRepository.update({ id: device.id }, { isPrimary: device.id === preferredDevice.id });
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
this.logger?.log?.(`Device ${preferredDevice.id} set as primary for user ${dto.userSub}`);
|
|
678
|
+
|
|
679
|
+
// ============================================================================
|
|
680
|
+
// Audit: Record preferred MFA method update
|
|
681
|
+
// ============================================================================
|
|
682
|
+
if (this.auditService && this.clientInfoService) {
|
|
683
|
+
try {
|
|
684
|
+
const previousMethod = userEntity.preferredMfaMethod;
|
|
685
|
+
await this.auditService?.recordEvent({
|
|
686
|
+
userId: user.id,
|
|
687
|
+
eventType: AuthAuditEventType.MFA_PREFERRED_METHOD_UPDATED,
|
|
688
|
+
eventStatus: 'INFO',
|
|
689
|
+
metadata: {
|
|
690
|
+
// Client info automatically included from context
|
|
691
|
+
previousMethod: previousMethod || null,
|
|
692
|
+
newMethod: normalizedMethod,
|
|
693
|
+
deviceId: preferredDevice.id,
|
|
694
|
+
},
|
|
695
|
+
});
|
|
696
|
+
} catch (auditError) {
|
|
697
|
+
// Non-blocking: Log but continue
|
|
698
|
+
const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
|
|
699
|
+
this.logger?.error?.(`Failed to record MFA_PREFERRED_METHOD_UPDATED audit event: ${errorMessage}`, {
|
|
700
|
+
error: auditError,
|
|
701
|
+
userId: user.id,
|
|
702
|
+
method: normalizedMethod,
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return {
|
|
708
|
+
message: 'Preferred method updated',
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Grant or revoke a user's exemption from multi-factor authentication (MFA) requirements.
|
|
714
|
+
*
|
|
715
|
+
* SECURITY: This admin-only operation updates the user's MFA exemption status, logs the action,
|
|
716
|
+
* and records an audit event. MFA exemption bypasses MFA at login, but all other security controls remain enforced.
|
|
717
|
+
*
|
|
718
|
+
* @param dto - Request DTO with user sub, exempt flag, reason, and grantedBy
|
|
719
|
+
* @returns Response DTO with updated exemption fields
|
|
720
|
+
* @throws {NAuthException} If the user is not found
|
|
721
|
+
*
|
|
722
|
+
* @example
|
|
723
|
+
* ```typescript
|
|
724
|
+
* // Grant MFA exemption
|
|
725
|
+
* await mfaService.setMFAExemption({
|
|
726
|
+
* userSub: 'user-uuid',
|
|
727
|
+
* exempt: true,
|
|
728
|
+
* reason: 'Business partner requires MFA bypass',
|
|
729
|
+
* grantedBy: 'admin@example.com'
|
|
730
|
+
* });
|
|
731
|
+
*
|
|
732
|
+
* // Revoke MFA exemption
|
|
733
|
+
* await mfaService.setMFAExemption({
|
|
734
|
+
* userSub: 'user-uuid',
|
|
735
|
+
* exempt: false,
|
|
736
|
+
* reason: 'MFA now mandatory for this user',
|
|
737
|
+
* grantedBy: 'admin@example.com'
|
|
738
|
+
* });
|
|
739
|
+
* ```
|
|
740
|
+
*/
|
|
741
|
+
async setMFAExemption(dto: SetMFAExemptionDTO): Promise<SetMFAExemptionResponseDTO> {
|
|
742
|
+
// Find user by sub (external identifier)
|
|
743
|
+
const userEntity = await this.userRepository.findOne({ where: { sub: dto.userSub } });
|
|
744
|
+
if (!userEntity) {
|
|
745
|
+
throw new NAuthException(AuthErrorCode.NOT_FOUND, 'User not found');
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const user = userEntity as unknown as IUser;
|
|
749
|
+
|
|
750
|
+
// Prepare update
|
|
751
|
+
const updateFields: Record<string, unknown> = {
|
|
752
|
+
mfaExempt: dto.exempt,
|
|
753
|
+
mfaExemptReason: dto.reason || null,
|
|
754
|
+
mfaExemptGrantedAt: dto.exempt ? new Date() : null,
|
|
755
|
+
mfaExemptGrantedBy: dto.exempt ? dto.grantedBy || null : null,
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
// If revoking exemption and MFA is required, check if user needs to set up MFA
|
|
759
|
+
// Note: This is just for logging - actual MFA setup requirement is checked by state machine on next login
|
|
760
|
+
if (!dto.exempt && userEntity.mfaExempt === true && !userEntity.mfaEnabled) {
|
|
761
|
+
this.logger?.warn?.(`MFA exemption revoked for user ${dto.userSub} - MFA setup will be required on next login`);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Update user in database
|
|
765
|
+
await this.userRepository.update(userEntity.id, updateFields);
|
|
766
|
+
|
|
767
|
+
// Log the exemption change for audit trail
|
|
768
|
+
this.logger?.log?.(`MFA exemption ${dto.exempt ? 'granted' : 'revoked'} for user ${dto.userSub}`, {
|
|
769
|
+
userSub: dto.userSub,
|
|
770
|
+
exempt: dto.exempt,
|
|
771
|
+
reason: dto.reason || 'No reason provided',
|
|
772
|
+
grantedBy: dto.grantedBy || 'System',
|
|
773
|
+
timestamp: new Date().toISOString(),
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
// ============================================================================
|
|
777
|
+
// Audit: Record MFA exemption grant/revoke
|
|
778
|
+
// ============================================================================
|
|
779
|
+
if (this.auditService && this.clientInfoService) {
|
|
780
|
+
try {
|
|
781
|
+
await this.auditService.recordEvent({
|
|
782
|
+
userId: user.id,
|
|
783
|
+
eventType: dto.exempt ? AuthAuditEventType.MFA_EXEMPTION_GRANTED : AuthAuditEventType.MFA_EXEMPTION_REVOKED,
|
|
784
|
+
eventStatus: 'INFO',
|
|
785
|
+
performedBy: dto.grantedBy || null,
|
|
786
|
+
// Client info automatically included from context
|
|
787
|
+
reason: dto.reason || null,
|
|
788
|
+
metadata: {
|
|
789
|
+
previousExemptStatus: userEntity.mfaExempt,
|
|
790
|
+
newExemptStatus: dto.exempt,
|
|
791
|
+
},
|
|
792
|
+
});
|
|
793
|
+
} catch (auditError) {
|
|
794
|
+
// Non-blocking: Log but continue
|
|
795
|
+
const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
|
|
796
|
+
this.logger?.error?.(`Failed to record MFA exemption audit event: ${errorMessage}`, {
|
|
797
|
+
error: auditError,
|
|
798
|
+
userId: user.id,
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Fetch updated user to return exemption fields
|
|
804
|
+
const exemptionData = await this.userRepository.findOne({
|
|
805
|
+
where: { id: userEntity.id },
|
|
806
|
+
select: ['mfaExempt', 'mfaExemptReason', 'mfaExemptGrantedAt'],
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
if (!exemptionData) {
|
|
810
|
+
throw new NAuthException(AuthErrorCode.NOT_FOUND, 'User not found after update');
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
return {
|
|
814
|
+
mfaExempt: exemptionData.mfaExempt || false,
|
|
815
|
+
mfaExemptReason: exemptionData.mfaExemptReason || null,
|
|
816
|
+
mfaExemptGrantedAt: exemptionData.mfaExemptGrantedAt || null,
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Get MFA setup data during MFA_SETUP_REQUIRED challenge
|
|
822
|
+
*
|
|
823
|
+
* Returns provider-specific setup data:
|
|
824
|
+
* - TOTP: { secret, qrCode, manualEntryKey }
|
|
825
|
+
* - SMS: { maskedPhone } or error if phone required
|
|
826
|
+
* - Passkey: WebAuthn registration options
|
|
827
|
+
*
|
|
828
|
+
* @param dto - Request DTO with session token, method, and optional setup data
|
|
829
|
+
* @returns Response DTO with provider-specific setup data
|
|
830
|
+
* @throws {NAuthException} INVALID_CHALLENGE_SESSION | VALIDATION_FAILED | PHONE_REQUIRED
|
|
831
|
+
*
|
|
832
|
+
* @example
|
|
833
|
+
* ```typescript
|
|
834
|
+
* const result = await mfaService.getSetupData({
|
|
835
|
+
* session: 'session-token',
|
|
836
|
+
* method: 'totp'
|
|
837
|
+
* });
|
|
838
|
+
* // Returns: { setupData: { secret: '...', qrCode: '...', manualEntryKey: '...' } }
|
|
839
|
+
*
|
|
840
|
+
* const result = await mfaService.getSetupData({
|
|
841
|
+
* session: 'session-token',
|
|
842
|
+
* method: 'sms',
|
|
843
|
+
* setupData: { phoneNumber: '+1234567890' }
|
|
844
|
+
* });
|
|
845
|
+
* // Returns: { setupData: { maskedPhone: '***-***-7890' } }
|
|
846
|
+
* ```
|
|
847
|
+
*/
|
|
848
|
+
async getSetupData(dto: GetSetupDataDTO): Promise<GetSetupDataResponseDTO> {
|
|
849
|
+
if (!this.challengeService) {
|
|
850
|
+
throw new NAuthException(AuthErrorCode.INTERNAL_ERROR, 'Challenge service is not available');
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
this.logger?.debug?.(`Getting MFA setup data: session=${dto.session}, method=${dto.method}`);
|
|
854
|
+
|
|
855
|
+
// Validate session and ensure it's MFA_SETUP_REQUIRED
|
|
856
|
+
const challengeSession = await this.challengeService.validateSession(dto.session);
|
|
857
|
+
|
|
858
|
+
if (challengeSession.challengeName !== AuthChallenge.MFA_SETUP_REQUIRED) {
|
|
859
|
+
throw new NAuthException(
|
|
860
|
+
AuthErrorCode.VALIDATION_FAILED,
|
|
861
|
+
`Cannot get setup data: expected MFA_SETUP_REQUIRED challenge, got ${challengeSession.challengeName}`,
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Get user from session
|
|
866
|
+
const user = challengeSession.user;
|
|
867
|
+
if (!user) {
|
|
868
|
+
throw new NAuthException(AuthErrorCode.VALIDATION_FAILED, 'Challenge session has no associated user');
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// Get provider and call setup
|
|
872
|
+
// Pass challenge session ID in setupData so provider can link verification tokens
|
|
873
|
+
const setupDataWithSession = {
|
|
874
|
+
...(dto.setupData || {}),
|
|
875
|
+
challengeSessionId: challengeSession.id,
|
|
876
|
+
};
|
|
877
|
+
this.logger?.debug?.(`Passing challengeSessionId=${challengeSession.id} to ${dto.method} provider for MFA setup`);
|
|
878
|
+
const provider = this.getProvider(dto.method);
|
|
879
|
+
const result = await provider.setup(user, setupDataWithSession);
|
|
880
|
+
|
|
881
|
+
this.logger?.debug?.(`MFA setup data generated: method=${dto.method}, user=${user.sub}`);
|
|
882
|
+
|
|
883
|
+
return {
|
|
884
|
+
setupData: result as Record<string, unknown>,
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* Get MFA challenge data during MFA_REQUIRED challenge
|
|
890
|
+
*
|
|
891
|
+
* Currently only used for passkey authentication to get WebAuthn options.
|
|
892
|
+
* SMS/TOTP codes are sent automatically when the challenge is created.
|
|
893
|
+
*
|
|
894
|
+
* @param dto - Request DTO with session token and method
|
|
895
|
+
* @returns Response DTO with provider-specific challenge data
|
|
896
|
+
* @throws {NAuthException} INVALID_CHALLENGE_SESSION | VALIDATION_FAILED
|
|
897
|
+
*
|
|
898
|
+
* @example
|
|
899
|
+
* ```typescript
|
|
900
|
+
* const result = await mfaService.getChallengeData({
|
|
901
|
+
* session: 'session-token',
|
|
902
|
+
* method: 'passkey'
|
|
903
|
+
* });
|
|
904
|
+
* // Returns: { challengeData: { challenge: '...', allowCredentials: [...], ... } }
|
|
905
|
+
* ```
|
|
906
|
+
*/
|
|
907
|
+
async getChallengeData(dto: GetChallengeDataDTO): Promise<GetChallengeDataResponseDTO> {
|
|
908
|
+
if (!this.challengeService) {
|
|
909
|
+
throw new NAuthException(AuthErrorCode.INTERNAL_ERROR, 'Challenge service is not available');
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
this.logger?.debug?.(`Getting MFA challenge data: session=${dto.session}, method=${dto.method}`);
|
|
913
|
+
|
|
914
|
+
// Validate session and ensure it's MFA_REQUIRED
|
|
915
|
+
const challengeSession = await this.challengeService.validateSession(dto.session);
|
|
916
|
+
|
|
917
|
+
if (challengeSession.challengeName !== AuthChallenge.MFA_REQUIRED) {
|
|
918
|
+
throw new NAuthException(
|
|
919
|
+
AuthErrorCode.VALIDATION_FAILED,
|
|
920
|
+
`Cannot get challenge data: expected MFA_REQUIRED challenge, got ${challengeSession.challengeName}`,
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// Get user from session
|
|
925
|
+
const user = challengeSession.user;
|
|
926
|
+
if (!user) {
|
|
927
|
+
throw new NAuthException(AuthErrorCode.VALIDATION_FAILED, 'Challenge session has no associated user');
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// Get provider and send challenge
|
|
931
|
+
const provider = this.getProvider(dto.method);
|
|
932
|
+
|
|
933
|
+
if (!provider.sendChallenge) {
|
|
934
|
+
throw new NAuthException(
|
|
935
|
+
AuthErrorCode.VALIDATION_FAILED,
|
|
936
|
+
`MFA method '${dto.method}' does not support challenge data generation`,
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
const challengeData = await provider.sendChallenge(user);
|
|
941
|
+
|
|
942
|
+
// For passkey, store the challenge in session metadata for verification
|
|
943
|
+
if (dto.method === 'passkey') {
|
|
944
|
+
const passkeyOptions = challengeData as { options: { challenge: string } };
|
|
945
|
+
const passkeyChallenge = passkeyOptions.options?.challenge;
|
|
946
|
+
if (passkeyChallenge) {
|
|
947
|
+
await this.challengeService.updateMetadata(dto.session, {
|
|
948
|
+
passkeyChallenge,
|
|
949
|
+
});
|
|
950
|
+
this.logger?.debug?.(`Passkey challenge stored in session metadata: user=${user.sub}`);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
this.logger?.debug?.(`MFA challenge data generated: method=${dto.method}, user=${user.sub}`);
|
|
955
|
+
|
|
956
|
+
return {
|
|
957
|
+
challengeData: challengeData as Record<string, unknown>,
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
}
|