@ackplus/nest-auth 0.1.51 → 1.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/README.md +6 -513
- package/eslint.config.mjs +59 -0
- package/jest.config.ts +10 -0
- package/package.json +14 -44
- package/project.json +86 -0
- package/src/index.ts +30 -0
- package/src/lib/admin-console/admin-console.module.ts +62 -0
- package/src/lib/admin-console/controllers/admin-auth.controller.ts +339 -0
- package/src/lib/admin-console/controllers/admin-console.controller.ts +82 -0
- package/src/lib/admin-console/controllers/admin-permissions.controller.ts +180 -0
- package/src/lib/admin-console/controllers/admin-roles.controller.ts +89 -0
- package/src/lib/admin-console/controllers/admin-tenants.controller.ts +68 -0
- package/src/lib/admin-console/controllers/admin-users.controller.ts +379 -0
- package/src/lib/admin-console/decorators/current-admin.decorator.ts +9 -0
- package/src/lib/admin-console/dto/admin-permission.dto.ts +106 -0
- package/src/lib/admin-console/dto/admin-role.dto.ts +45 -0
- package/src/lib/admin-console/dto/admin-tenant.dto.ts +43 -0
- package/src/lib/admin-console/dto/admin-user.dto.ts +87 -0
- package/src/lib/admin-console/dto/create-dashboard-admin.dto.ts +34 -0
- package/src/lib/admin-console/dto/login.dto.ts +10 -0
- package/src/lib/admin-console/dto/reset-password.dto.ts +21 -0
- package/src/lib/admin-console/dto/setup-admin.dto.ts +23 -0
- package/src/lib/admin-console/dto/signup.dto.ts +51 -0
- package/src/lib/admin-console/entities/admin-user.entity.ts +74 -0
- package/src/lib/admin-console/guards/admin-session.guard.ts +47 -0
- package/src/lib/admin-console/services/admin-auth.service.ts +82 -0
- package/src/lib/admin-console/services/admin-console-config.service.ts +62 -0
- package/src/lib/admin-console/services/admin-session.service.ts +106 -0
- package/src/lib/admin-console/services/admin-user.service.ts +96 -0
- package/src/lib/admin-console/static/index.html +771 -0
- package/src/lib/auth/auth.module.ts +58 -0
- package/src/lib/auth/controllers/auth.controller.ts +393 -0
- package/src/lib/auth/controllers/mfa.controller.ts +200 -0
- package/src/lib/auth/dto/credentials/email-credentials.dto.ts +24 -0
- package/src/lib/auth/dto/credentials/phone-credentials.dto.ts +24 -0
- package/src/lib/auth/dto/credentials/social-credentials.dto.ts +15 -0
- package/src/lib/auth/dto/index.ts +1 -0
- package/src/lib/auth/dto/requests/change-password.request.dto.ts +34 -0
- package/src/lib/auth/dto/requests/forgot-password.request.dto.ts +30 -0
- package/src/lib/auth/dto/requests/initialize-admin.request.dto.ts +51 -0
- package/src/lib/auth/dto/requests/login.request.dto.ts +65 -0
- package/src/lib/auth/dto/requests/refresh-token.request.dto.ts +12 -0
- package/src/lib/auth/dto/requests/reset-password-with-token.request.dto.ts +22 -0
- package/src/lib/auth/dto/requests/reset-password.request.dto.ts +50 -0
- package/src/lib/auth/dto/requests/send-email-verification.request.dto.ts +12 -0
- package/src/lib/auth/dto/requests/send-mfa-code.request.dto.ts +19 -0
- package/src/lib/auth/dto/requests/signup.request.dto.ts +42 -0
- package/src/lib/auth/dto/requests/toggle-mfa.request.dto.ts +12 -0
- package/src/lib/auth/dto/requests/verify-2fa.request.dto.ts +24 -0
- package/src/lib/auth/dto/requests/verify-email.request.dto.ts +22 -0
- package/src/lib/auth/dto/requests/verify-forgot-password-otp-request-dto.ts +41 -0
- package/src/lib/auth/dto/requests/verify-totp-setup.request.dto.ts +22 -0
- package/src/lib/auth/dto/responses/auth-cookie.response.dto.ts +58 -0
- package/src/lib/auth/dto/responses/auth-success.response.dto.ts +58 -0
- package/src/lib/auth/dto/responses/auth.response.dto.ts +99 -0
- package/src/lib/auth/dto/responses/client-config.response.dto.ts +153 -0
- package/src/lib/auth/dto/responses/initialize-admin.response.dto.ts +22 -0
- package/src/lib/auth/dto/responses/mfa-code-response.dto.ts +27 -0
- package/src/lib/auth/dto/responses/mfa-status.response.dto.ts +89 -0
- package/src/lib/auth/dto/responses/verify-otp.response.dto.ts +9 -0
- package/src/lib/auth/entities/mfa-secret.entity.ts +33 -0
- package/src/lib/auth/entities/otp.entity.ts +33 -0
- package/src/lib/auth/events/{logged-out-all.event.d.ts → logged-out-all.event.ts} +6 -3
- package/src/lib/auth/events/{logged-out.event.d.ts → logged-out.event.ts} +5 -3
- package/src/lib/auth/events/{password-reset-requested.event.d.ts → password-reset-requested.event.ts} +6 -3
- package/src/lib/auth/events/{password-reset.event.d.ts → password-reset.event.ts} +6 -3
- package/src/lib/auth/events/{user-2fa-verified.event.d.ts → user-2fa-verified.event.ts} +6 -3
- package/src/lib/auth/events/{user-logged-in.event.d.ts → user-logged-in.event.ts} +7 -3
- package/src/lib/auth/events/{user-refresh-token.event.d.ts → user-refresh-token.event.ts} +6 -3
- package/src/lib/auth/events/{user-registered.event.d.ts → user-registered.event.ts} +7 -3
- package/src/lib/auth/guards/auth.guard.ts +386 -0
- package/src/lib/auth/{index.d.ts → index.ts} +28 -1
- package/src/lib/auth/interceptors/refresh-token.interceptor.ts +117 -0
- package/src/lib/auth/services/auth.service.ts +947 -0
- package/src/lib/auth/services/client-config.service.ts +157 -0
- package/src/lib/auth/services/cookie.service.ts +43 -0
- package/src/lib/auth/services/mfa.service.ts +391 -0
- package/src/lib/auth.constants.ts +63 -0
- package/src/lib/core/core.module.ts +50 -0
- package/src/lib/core/decorators/auth.decorator.ts +38 -0
- package/src/lib/core/decorators/permissions.decorator.ts +17 -0
- package/src/lib/core/decorators/public.decorator.ts +33 -0
- package/src/lib/core/decorators/role.decorator.ts +12 -0
- package/src/lib/core/decorators/skip-mfa.decorator.ts +4 -0
- package/src/lib/core/dto/message.response.dto.ts +6 -0
- package/src/lib/core/{entities.d.ts → entities.ts} +18 -1
- package/src/lib/core/{index.d.ts → index.ts} +17 -0
- package/src/lib/core/interfaces/auth-module-options.interface.ts +211 -0
- package/src/lib/core/interfaces/mfa-options.interface.ts +46 -0
- package/src/lib/core/interfaces/otp.interface.ts +6 -0
- package/src/lib/core/interfaces/session-options.interface.ts +19 -0
- package/src/lib/core/interfaces/{token-payload.interface.d.ts → token-payload.interface.ts} +4 -1
- package/src/lib/core/providers/apple-auth.provider.ts +61 -0
- package/src/lib/core/providers/base-auth.provider.ts +74 -0
- package/src/lib/core/providers/email-auth.provider.ts +71 -0
- package/src/lib/core/providers/facebook-auth.provider.ts +55 -0
- package/src/lib/core/providers/github-auth.provider.ts +79 -0
- package/src/lib/core/providers/google-auth.provider.ts +61 -0
- package/src/lib/core/providers/jwt-auth.provider.ts +50 -0
- package/src/lib/core/providers/phone-auth.provider.ts +45 -0
- package/src/lib/core/services/auth-config.service.ts +184 -0
- package/src/lib/core/services/auth-provider-registry.service.ts +93 -0
- package/src/lib/core/services/{debug-logger.service.js → debug-logger.service.ts} +92 -59
- package/src/lib/core/services/initialization.service.ts +29 -0
- package/src/lib/core/services/jwt.service.ts +137 -0
- package/src/lib/nest-auth.module.ts +152 -0
- package/src/lib/permission/entities/permission.entity.ts +56 -0
- package/src/lib/permission/index.ts +4 -0
- package/src/lib/permission/permission.module.ts +14 -0
- package/src/lib/permission/services/permission.service.ts +233 -0
- package/src/lib/request-context/index.ts +2 -0
- package/src/lib/request-context/request-context.middleware.ts +13 -0
- package/src/lib/request-context/{request-context.js → request-context.ts} +51 -27
- package/src/lib/role/entities/role.entity.ts +103 -0
- package/src/lib/role/{index.d.ts → index.ts} +2 -0
- package/src/lib/role/role.module.ts +15 -0
- package/src/lib/role/services/{role.service.js → role.service.ts} +117 -52
- package/src/lib/session/entities/session.entity.ts +54 -0
- package/src/lib/session/index.ts +20 -0
- package/src/lib/session/interfaces/session-repository.interface.ts +58 -0
- package/src/lib/session/repositories/base-session.repository.ts +74 -0
- package/src/lib/session/repositories/memory-session.repository.ts +153 -0
- package/src/lib/session/repositories/redis-session.repository.ts +171 -0
- package/src/lib/session/repositories/typeorm-session.repository.ts +86 -0
- package/src/lib/session/services/session-manager.service.ts +261 -0
- package/src/lib/session/session.module.ts +102 -0
- package/src/lib/session/utils/session.util.ts +166 -0
- package/src/lib/tenant/entities/tenant.entity.ts +40 -0
- package/src/lib/tenant/events/tenant-created.event.ts +9 -0
- package/src/lib/tenant/events/tenant-deleted.event.ts +11 -0
- package/src/lib/tenant/events/{tenant-updated.event.d.ts → tenant-updated.event.ts} +6 -3
- package/src/lib/tenant/index.ts +9 -0
- package/src/lib/tenant/services/tenant.service.ts +336 -0
- package/src/lib/tenant/tenant.module.ts +19 -0
- package/src/lib/types/express.d.ts +14 -0
- package/src/lib/user/dto/requests/update-user.dto.ts +15 -0
- package/src/lib/user/entities/access-key.entity.ts +53 -0
- package/src/lib/user/entities/identity.entity.ts +31 -0
- package/src/lib/user/entities/user.entity.ts +212 -0
- package/src/lib/user/events/{user-created.event.d.ts → user-created.event.ts} +4 -3
- package/src/lib/user/events/{user-deleted.event.d.ts → user-deleted.event.ts} +6 -3
- package/src/lib/user/events/{user-updated.event.d.ts → user-updated.event.ts} +6 -3
- package/src/lib/user/index.ts +11 -0
- package/src/lib/user/services/access-key.service.ts +145 -0
- package/src/lib/user/services/{user.service.js → user.service.ts} +199 -95
- package/src/lib/user/user.module.ts +26 -0
- package/src/lib/utils/database.utils.ts +6 -0
- package/src/lib/utils/date.util.ts +106 -0
- package/src/lib/utils/device.util.ts +111 -0
- package/src/lib/utils/index.ts +6 -0
- package/src/lib/utils/otp.ts +3 -0
- package/src/lib/utils/security.util.ts +27 -0
- package/src/lib/utils/slug.util.ts +58 -0
- package/src/types/ms.d.ts +1 -0
- package/test/access-key.service.spec.ts +204 -0
- package/test/auth.service.spec.ts +541 -0
- package/test/mfa.service.spec.ts +359 -0
- package/test/role.service.spec.ts +418 -0
- package/test/tenant.service.spec.ts +218 -0
- package/test/test.setup.ts +66 -0
- package/test/user.service.spec.ts +374 -0
- package/tsconfig.json +17 -0
- package/tsconfig.lib.json +15 -0
- package/tsconfig.spec.json +15 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/ui/.env +1 -0
- package/ui/.env.example +1 -0
- package/ui/.eslintignore +7 -0
- package/ui/README.md +288 -0
- package/ui/index.html +17 -0
- package/ui/package.json +34 -0
- package/ui/postcss.config.js +6 -0
- package/ui/src/App.tsx +245 -0
- package/ui/src/components/AuthGuard.tsx +59 -0
- package/ui/src/components/AuthProvider.tsx +76 -0
- package/ui/src/components/Button.tsx +37 -0
- package/ui/src/components/Card.tsx +37 -0
- package/ui/src/components/ErrorMessage.tsx +15 -0
- package/ui/src/components/FormDialog.tsx +61 -0
- package/ui/src/components/FormFooter.tsx +37 -0
- package/ui/src/components/Layout.tsx +112 -0
- package/ui/src/components/LoadingMessage.tsx +11 -0
- package/ui/src/components/Modal.tsx +97 -0
- package/ui/src/components/MultiSelect.tsx +145 -0
- package/ui/src/components/PageHeader.tsx +42 -0
- package/ui/src/components/PanelHeader.tsx +28 -0
- package/ui/src/components/PermissionInput.tsx +473 -0
- package/ui/src/components/SearchInput.tsx +69 -0
- package/ui/src/components/Select.tsx +51 -0
- package/ui/src/components/SwaggerUIWrapper.tsx +316 -0
- package/ui/src/components/Table.tsx +207 -0
- package/ui/src/components/Tag.tsx +9 -0
- package/ui/src/components/TagsInput.tsx +96 -0
- package/ui/src/components/admin/AdminForm.tsx +170 -0
- package/ui/src/components/admin/CreateAdminDialog.tsx +38 -0
- package/ui/src/components/auth/LoginFooter.tsx +17 -0
- package/ui/src/components/auth/LoginHeader.tsx +14 -0
- package/ui/src/components/auth/components/CodeBlock.tsx +43 -0
- package/ui/src/components/auth/components/CreateAccountCodeExamples.tsx +60 -0
- package/ui/src/components/auth/components/PasswordRequirements.tsx +16 -0
- package/ui/src/components/auth/components/PasswordStrengthIndicator.tsx +48 -0
- package/ui/src/components/auth/components/ResetPasswordCodeExamples.tsx +76 -0
- package/ui/src/components/auth/components/Tabs.tsx +32 -0
- package/ui/src/components/auth/dialogs/CreateAccountDialog.tsx +79 -0
- package/ui/src/components/auth/dialogs/ForgotPasswordDialog.tsx +79 -0
- package/ui/src/components/auth/forms/CreateAccountForm.tsx +226 -0
- package/ui/src/components/auth/forms/LoginForm.tsx +149 -0
- package/ui/src/components/auth/forms/ResetPasswordForm.tsx +202 -0
- package/ui/src/components/auth/types.ts +17 -0
- package/ui/src/components/auth/utils/security.ts +82 -0
- package/ui/src/components/auth/utils/utils.ts +25 -0
- package/ui/src/components/form/EmailField.tsx +25 -0
- package/ui/src/components/form/FormField.tsx +102 -0
- package/ui/src/components/form/FormMultiSelect.tsx +46 -0
- package/ui/src/components/form/FormSelect.tsx +60 -0
- package/ui/src/components/form/FormTagsInput.tsx +42 -0
- package/ui/src/components/form/FormTextarea.tsx +42 -0
- package/ui/src/components/form/PasswordField.tsx +93 -0
- package/ui/src/components/form/SecretKeyField.tsx +49 -0
- package/ui/src/components/permission/CreatePermissionDialog.tsx +44 -0
- package/ui/src/components/permission/EditPermissionDialog.tsx +55 -0
- package/ui/src/components/permission/PermissionForm.tsx +251 -0
- package/ui/src/components/role/CreateRoleDialog.tsx +45 -0
- package/ui/src/components/role/EditRoleDialog.tsx +55 -0
- package/ui/src/components/role/RoleDialog.tsx +252 -0
- package/ui/src/components/role/RoleForm.tsx +246 -0
- package/ui/src/components/tenant/CreateTenantDialog.tsx +41 -0
- package/ui/src/components/tenant/EditTenantDialog.tsx +52 -0
- package/ui/src/components/tenant/TenantForm.tsx +160 -0
- package/ui/src/components/user/CreateUserDialog.tsx +45 -0
- package/ui/src/components/user/UserDetailModal.tsx +815 -0
- package/ui/src/components/user/UserForm.tsx +191 -0
- package/ui/src/data/nest-auth.json +1687 -0
- package/ui/src/hooks/useApi.ts +69 -0
- package/ui/src/hooks/useAuth.ts +100 -0
- package/ui/src/hooks/useConfirm.tsx +105 -0
- package/ui/src/hooks/useFormFooter.tsx +42 -0
- package/ui/src/hooks/usePagination.ts +69 -0
- package/ui/src/index.css +59 -0
- package/ui/src/main.tsx +13 -0
- package/ui/src/pages/AdminsPage.tsx +178 -0
- package/ui/src/pages/ApiPage.tsx +89 -0
- package/ui/src/pages/DashboardPage.tsx +281 -0
- package/ui/src/pages/LoginPage.tsx +39 -0
- package/ui/src/pages/PermissionsPage.tsx +376 -0
- package/ui/src/pages/RolesPage.tsx +274 -0
- package/ui/src/pages/TenantsPage.tsx +221 -0
- package/ui/src/pages/UsersPage.tsx +387 -0
- package/ui/src/services/api.ts +115 -0
- package/ui/src/types/index.ts +136 -0
- package/ui/src/vite-env.d.ts +9 -0
- package/ui/tailwind.config.js +45 -0
- package/ui/tsconfig.json +24 -0
- package/ui/tsconfig.node.json +10 -0
- package/ui/vite.config.ts +37 -0
- package/ui/yarn.lock +3137 -0
- package/src/index.d.ts +0 -11
- package/src/index.js +0 -18
- package/src/index.js.map +0 -1
- package/src/lib/auth/auth.module.d.ts +0 -2
- package/src/lib/auth/auth.module.js +0 -54
- package/src/lib/auth/auth.module.js.map +0 -1
- package/src/lib/auth/controllers/auth.controller.d.ts +0 -29
- package/src/lib/auth/controllers/auth.controller.js +0 -206
- package/src/lib/auth/controllers/auth.controller.js.map +0 -1
- package/src/lib/auth/controllers/mfa.controller.d.ts +0 -23
- package/src/lib/auth/controllers/mfa.controller.js +0 -131
- package/src/lib/auth/controllers/mfa.controller.js.map +0 -1
- package/src/lib/auth/dto/index.d.ts +0 -0
- package/src/lib/auth/dto/index.js +0 -1
- package/src/lib/auth/dto/index.js.map +0 -1
- package/src/lib/auth/dto/requests/forgot-password.request.dto.d.ts +0 -5
- package/src/lib/auth/dto/requests/forgot-password.request.dto.js +0 -30
- package/src/lib/auth/dto/requests/forgot-password.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/login.request.dto.d.ts +0 -6
- package/src/lib/auth/dto/requests/login.request.dto.js +0 -38
- package/src/lib/auth/dto/requests/login.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/refresh-token.request.dto.d.ts +0 -3
- package/src/lib/auth/dto/requests/refresh-token.request.dto.js +0 -15
- package/src/lib/auth/dto/requests/refresh-token.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/reset-password.request.dto.d.ts +0 -7
- package/src/lib/auth/dto/requests/reset-password.request.dto.js +0 -42
- package/src/lib/auth/dto/requests/reset-password.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/send-mfa-code.request.dto.d.ts +0 -4
- package/src/lib/auth/dto/requests/send-mfa-code.request.dto.js +0 -16
- package/src/lib/auth/dto/requests/send-mfa-code.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/signup.request.dto.d.ts +0 -7
- package/src/lib/auth/dto/requests/signup.request.dto.js +0 -37
- package/src/lib/auth/dto/requests/signup.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/social-login.request.dto.d.ts +0 -3
- package/src/lib/auth/dto/requests/social-login.request.dto.js +0 -16
- package/src/lib/auth/dto/requests/social-login.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/verify-2fa.request.dto.d.ts +0 -5
- package/src/lib/auth/dto/requests/verify-2fa.request.dto.js +0 -21
- package/src/lib/auth/dto/requests/verify-2fa.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/verify-forgot-password-otp-request-dto.d.ts +0 -6
- package/src/lib/auth/dto/requests/verify-forgot-password-otp-request-dto.js +0 -35
- package/src/lib/auth/dto/requests/verify-forgot-password-otp-request-dto.js.map +0 -1
- package/src/lib/auth/dto/requests/verify-totp-setup.request.dto.d.ts +0 -4
- package/src/lib/auth/dto/requests/verify-totp-setup.request.dto.js +0 -20
- package/src/lib/auth/dto/requests/verify-totp-setup.request.dto.js.map +0 -1
- package/src/lib/auth/dto/responses/auth.response.dto.d.ts +0 -16
- package/src/lib/auth/dto/responses/auth.response.dto.js +0 -50
- package/src/lib/auth/dto/responses/auth.response.dto.js.map +0 -1
- package/src/lib/auth/entities/mfa-secret.entity.d.ts +0 -12
- package/src/lib/auth/entities/mfa-secret.entity.js +0 -50
- package/src/lib/auth/entities/mfa-secret.entity.js.map +0 -1
- package/src/lib/auth/entities/otp.entity.d.ts +0 -13
- package/src/lib/auth/entities/otp.entity.js +0 -50
- package/src/lib/auth/entities/otp.entity.js.map +0 -1
- package/src/lib/auth/events/logged-out-all.event.js +0 -10
- package/src/lib/auth/events/logged-out-all.event.js.map +0 -1
- package/src/lib/auth/events/logged-out.event.js +0 -10
- package/src/lib/auth/events/logged-out.event.js.map +0 -1
- package/src/lib/auth/events/password-reset-requested.event.js +0 -10
- package/src/lib/auth/events/password-reset-requested.event.js.map +0 -1
- package/src/lib/auth/events/password-reset.event.js +0 -10
- package/src/lib/auth/events/password-reset.event.js.map +0 -1
- package/src/lib/auth/events/user-2fa-verified.event.js +0 -10
- package/src/lib/auth/events/user-2fa-verified.event.js.map +0 -1
- package/src/lib/auth/events/user-logged-in.event.js +0 -10
- package/src/lib/auth/events/user-logged-in.event.js.map +0 -1
- package/src/lib/auth/events/user-refresh-token.event.js +0 -10
- package/src/lib/auth/events/user-refresh-token.event.js.map +0 -1
- package/src/lib/auth/events/user-registered.event.js +0 -10
- package/src/lib/auth/events/user-registered.event.js.map +0 -1
- package/src/lib/auth/guards/auth.guard.d.ts +0 -28
- package/src/lib/auth/guards/auth.guard.js +0 -304
- package/src/lib/auth/guards/auth.guard.js.map +0 -1
- package/src/lib/auth/index.js +0 -31
- package/src/lib/auth/index.js.map +0 -1
- package/src/lib/auth/services/auth.service.d.ts +0 -53
- package/src/lib/auth/services/auth.service.js +0 -522
- package/src/lib/auth/services/auth.service.js.map +0 -1
- package/src/lib/auth/services/cookie.service.d.ts +0 -9
- package/src/lib/auth/services/cookie.service.js +0 -43
- package/src/lib/auth/services/cookie.service.js.map +0 -1
- package/src/lib/auth/services/mfa.service.d.ts +0 -38
- package/src/lib/auth/services/mfa.service.js +0 -254
- package/src/lib/auth/services/mfa.service.js.map +0 -1
- package/src/lib/auth.constants.d.ts +0 -39
- package/src/lib/auth.constants.js +0 -43
- package/src/lib/auth.constants.js.map +0 -1
- package/src/lib/core/core.module.d.ts +0 -2
- package/src/lib/core/core.module.js +0 -53
- package/src/lib/core/core.module.js.map +0 -1
- package/src/lib/core/decorators/auth.decorator.d.ts +0 -1
- package/src/lib/core/decorators/auth.decorator.js +0 -8
- package/src/lib/core/decorators/auth.decorator.js.map +0 -1
- package/src/lib/core/decorators/permissions.decorator.d.ts +0 -2
- package/src/lib/core/decorators/permissions.decorator.js +0 -14
- package/src/lib/core/decorators/permissions.decorator.js.map +0 -1
- package/src/lib/core/decorators/role.decorator.d.ts +0 -3
- package/src/lib/core/decorators/role.decorator.js +0 -14
- package/src/lib/core/decorators/role.decorator.js.map +0 -1
- package/src/lib/core/decorators/skip-mfa.decorator.d.ts +0 -2
- package/src/lib/core/decorators/skip-mfa.decorator.js +0 -8
- package/src/lib/core/decorators/skip-mfa.decorator.js.map +0 -1
- package/src/lib/core/dto/message.response.dto.d.ts +0 -3
- package/src/lib/core/dto/message.response.dto.js +0 -13
- package/src/lib/core/dto/message.response.dto.js.map +0 -1
- package/src/lib/core/entities.js +0 -31
- package/src/lib/core/entities.js.map +0 -1
- package/src/lib/core/index.js +0 -27
- package/src/lib/core/index.js.map +0 -1
- package/src/lib/core/interfaces/auth-module-options.interface.d.ts +0 -62
- package/src/lib/core/interfaces/auth-module-options.interface.js +0 -3
- package/src/lib/core/interfaces/auth-module-options.interface.js.map +0 -1
- package/src/lib/core/interfaces/mfa-options.interface.d.ts +0 -25
- package/src/lib/core/interfaces/mfa-options.interface.js +0 -10
- package/src/lib/core/interfaces/mfa-options.interface.js.map +0 -1
- package/src/lib/core/interfaces/otp.interface.d.ts +0 -5
- package/src/lib/core/interfaces/otp.interface.js +0 -10
- package/src/lib/core/interfaces/otp.interface.js.map +0 -1
- package/src/lib/core/interfaces/session-options.interface.d.ts +0 -12
- package/src/lib/core/interfaces/session-options.interface.js +0 -9
- package/src/lib/core/interfaces/session-options.interface.js.map +0 -1
- package/src/lib/core/interfaces/token-payload.interface.js +0 -3
- package/src/lib/core/interfaces/token-payload.interface.js.map +0 -1
- package/src/lib/core/providers/apple-auth.provider.d.ts +0 -18
- package/src/lib/core/providers/apple-auth.provider.js +0 -57
- package/src/lib/core/providers/apple-auth.provider.js.map +0 -1
- package/src/lib/core/providers/base-auth.provider.d.ts +0 -26
- package/src/lib/core/providers/base-auth.provider.js +0 -43
- package/src/lib/core/providers/base-auth.provider.js.map +0 -1
- package/src/lib/core/providers/email-auth.provider.d.ts +0 -17
- package/src/lib/core/providers/email-auth.provider.js +0 -40
- package/src/lib/core/providers/email-auth.provider.js.map +0 -1
- package/src/lib/core/providers/facebook-auth.provider.d.ts +0 -18
- package/src/lib/core/providers/facebook-auth.provider.js +0 -56
- package/src/lib/core/providers/facebook-auth.provider.js.map +0 -1
- package/src/lib/core/providers/google-auth.provider.d.ts +0 -21
- package/src/lib/core/providers/google-auth.provider.js +0 -58
- package/src/lib/core/providers/google-auth.provider.js.map +0 -1
- package/src/lib/core/providers/jwt-auth.provider.d.ts +0 -33
- package/src/lib/core/providers/jwt-auth.provider.js +0 -50
- package/src/lib/core/providers/jwt-auth.provider.js.map +0 -1
- package/src/lib/core/providers/phone-auth.provider.d.ts +0 -18
- package/src/lib/core/providers/phone-auth.provider.js +0 -43
- package/src/lib/core/providers/phone-auth.provider.js.map +0 -1
- package/src/lib/core/services/auth-config.service.d.ts +0 -12
- package/src/lib/core/services/auth-config.service.js +0 -79
- package/src/lib/core/services/auth-config.service.js.map +0 -1
- package/src/lib/core/services/auth-provider-registry.service.d.ts +0 -24
- package/src/lib/core/services/auth-provider-registry.service.js +0 -71
- package/src/lib/core/services/auth-provider-registry.service.js.map +0 -1
- package/src/lib/core/services/debug-logger.service.d.ts +0 -38
- package/src/lib/core/services/debug-logger.service.js.map +0 -1
- package/src/lib/core/services/initialization.service.d.ts +0 -10
- package/src/lib/core/services/initialization.service.js +0 -34
- package/src/lib/core/services/initialization.service.js.map +0 -1
- package/src/lib/core/services/jwt.service.d.ts +0 -14
- package/src/lib/core/services/jwt.service.js +0 -92
- package/src/lib/core/services/jwt.service.js.map +0 -1
- package/src/lib/nest-auth.module.d.ts +0 -11
- package/src/lib/nest-auth.module.js +0 -177
- package/src/lib/nest-auth.module.js.map +0 -1
- package/src/lib/request-context/request-context.d.ts +0 -22
- package/src/lib/request-context/request-context.js.map +0 -1
- package/src/lib/request-context/request-context.middleware.d.ts +0 -4
- package/src/lib/request-context/request-context.middleware.js +0 -16
- package/src/lib/request-context/request-context.middleware.js.map +0 -1
- package/src/lib/role/entities/role.entity.d.ts +0 -20
- package/src/lib/role/entities/role.entity.js +0 -110
- package/src/lib/role/entities/role.entity.js.map +0 -1
- package/src/lib/role/index.js +0 -5
- package/src/lib/role/index.js.map +0 -1
- package/src/lib/role/role.module.d.ts +0 -2
- package/src/lib/role/role.module.js +0 -23
- package/src/lib/role/role.module.js.map +0 -1
- package/src/lib/role/services/role.service.d.ts +0 -20
- package/src/lib/role/services/role.service.js.map +0 -1
- package/src/lib/session/entities/session.entity.d.ts +0 -16
- package/src/lib/session/entities/session.entity.js +0 -63
- package/src/lib/session/entities/session.entity.js.map +0 -1
- package/src/lib/session/index.d.ts +0 -3
- package/src/lib/session/index.js +0 -7
- package/src/lib/session/index.js.map +0 -1
- package/src/lib/session/services/base-session.service.d.ts +0 -23
- package/src/lib/session/services/base-session.service.js +0 -64
- package/src/lib/session/services/base-session.service.js.map +0 -1
- package/src/lib/session/services/database-session.service.d.ts +0 -17
- package/src/lib/session/services/database-session.service.js +0 -51
- package/src/lib/session/services/database-session.service.js.map +0 -1
- package/src/lib/session/services/redis-session.service.d.ts +0 -20
- package/src/lib/session/services/redis-session.service.js +0 -117
- package/src/lib/session/services/redis-session.service.js.map +0 -1
- package/src/lib/session/session.module.d.ts +0 -2
- package/src/lib/session/session.module.js +0 -33
- package/src/lib/session/session.module.js.map +0 -1
- package/src/lib/tenant/entities/tenant.entity.d.ts +0 -10
- package/src/lib/tenant/entities/tenant.entity.js +0 -44
- package/src/lib/tenant/entities/tenant.entity.js.map +0 -1
- package/src/lib/tenant/events/tenant-created.event.d.ts +0 -8
- package/src/lib/tenant/events/tenant-created.event.js +0 -10
- package/src/lib/tenant/events/tenant-created.event.js.map +0 -1
- package/src/lib/tenant/events/tenant-deleted.event.d.ts +0 -8
- package/src/lib/tenant/events/tenant-deleted.event.js +0 -10
- package/src/lib/tenant/events/tenant-deleted.event.js.map +0 -1
- package/src/lib/tenant/events/tenant-updated.event.js +0 -10
- package/src/lib/tenant/events/tenant-updated.event.js.map +0 -1
- package/src/lib/tenant/index.d.ts +0 -1
- package/src/lib/tenant/index.js +0 -5
- package/src/lib/tenant/index.js.map +0 -1
- package/src/lib/tenant/services/tenant.service.d.ts +0 -26
- package/src/lib/tenant/services/tenant.service.js +0 -200
- package/src/lib/tenant/services/tenant.service.js.map +0 -1
- package/src/lib/tenant/tenant.module.d.ts +0 -2
- package/src/lib/tenant/tenant.module.js +0 -27
- package/src/lib/tenant/tenant.module.js.map +0 -1
- package/src/lib/user/dto/requests/update-user.dto.d.ts +0 -5
- package/src/lib/user/dto/requests/update-user.dto.js +0 -24
- package/src/lib/user/dto/requests/update-user.dto.js.map +0 -1
- package/src/lib/user/entities/access-key.entity.d.ts +0 -16
- package/src/lib/user/entities/access-key.entity.js +0 -63
- package/src/lib/user/entities/access-key.entity.js.map +0 -1
- package/src/lib/user/entities/identity.entity.d.ts +0 -12
- package/src/lib/user/entities/identity.entity.js +0 -47
- package/src/lib/user/entities/identity.entity.js.map +0 -1
- package/src/lib/user/entities/user.entity.d.ts +0 -39
- package/src/lib/user/entities/user.entity.js +0 -201
- package/src/lib/user/entities/user.entity.js.map +0 -1
- package/src/lib/user/events/user-created.event.js +0 -10
- package/src/lib/user/events/user-created.event.js.map +0 -1
- package/src/lib/user/events/user-deleted.event.js +0 -10
- package/src/lib/user/events/user-deleted.event.js.map +0 -1
- package/src/lib/user/events/user-updated.event.js +0 -10
- package/src/lib/user/events/user-updated.event.js.map +0 -1
- package/src/lib/user/index.d.ts +0 -3
- package/src/lib/user/index.js +0 -7
- package/src/lib/user/index.js.map +0 -1
- package/src/lib/user/services/access-key.service.d.ts +0 -19
- package/src/lib/user/services/access-key.service.js +0 -119
- package/src/lib/user/services/access-key.service.js.map +0 -1
- package/src/lib/user/services/user.service.d.ts +0 -24
- package/src/lib/user/services/user.service.js.map +0 -1
- package/src/lib/user/user.module.d.ts +0 -2
- package/src/lib/user/user.module.js +0 -34
- package/src/lib/user/user.module.js.map +0 -1
- package/src/lib/utils/database.utils.d.ts +0 -2
- package/src/lib/utils/database.utils.js +0 -8
- package/src/lib/utils/database.utils.js.map +0 -1
- package/src/lib/utils/otp.d.ts +0 -1
- package/src/lib/utils/otp.js +0 -7
- package/src/lib/utils/otp.js.map +0 -1
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException } from '@nestjs/common';
|
|
2
|
+
import { UNAUTHORIZED_EXCEPTION_CODE } from '../../auth.constants';
|
|
3
|
+
import { Reflector } from '@nestjs/core';
|
|
4
|
+
import { Request, Response } from 'express';
|
|
5
|
+
import { JwtService } from '../../core/services/jwt.service';
|
|
6
|
+
import { SessionManagerService } from '../../session/services/session-manager.service';
|
|
7
|
+
import { AccessKeyService } from '../../user/services/access-key.service';
|
|
8
|
+
import { JWTTokenPayload } from '../../core/interfaces/token-payload.interface';
|
|
9
|
+
import { SKIP_MFA_KEY } from '../../core/decorators/skip-mfa.decorator';
|
|
10
|
+
import { PERMISSIONS_KEY } from '../../core/decorators/permissions.decorator';
|
|
11
|
+
import { ROLES_KEY } from '../../core/decorators/role.decorator';
|
|
12
|
+
|
|
13
|
+
// Key for optional auth metadata
|
|
14
|
+
export const OPTIONAL_AUTH_KEY = 'optional_auth';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* NestAuthAuthGuard
|
|
18
|
+
*
|
|
19
|
+
* Handles authentication and authorization for protected routes.
|
|
20
|
+
* Token refresh is handled by RefreshTokenInterceptor (applied globally).
|
|
21
|
+
*
|
|
22
|
+
* This guard verifies:
|
|
23
|
+
* - JWT tokens (Bearer)
|
|
24
|
+
* - API keys
|
|
25
|
+
* - MFA requirements
|
|
26
|
+
* - Roles and permissions
|
|
27
|
+
*
|
|
28
|
+
* Note: For automatic token refresh, enable RefreshTokenInterceptor globally.
|
|
29
|
+
*/
|
|
30
|
+
@Injectable()
|
|
31
|
+
export class NestAuthAuthGuard implements CanActivate {
|
|
32
|
+
constructor(
|
|
33
|
+
private reflector: Reflector,
|
|
34
|
+
private jwtService: JwtService,
|
|
35
|
+
private sessionManager: SessionManagerService,
|
|
36
|
+
private accessKeyService: AccessKeyService,
|
|
37
|
+
) { }
|
|
38
|
+
|
|
39
|
+
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
40
|
+
const request = context.switchToHttp().getRequest<Request>() as any;
|
|
41
|
+
const response = context.switchToHttp().getResponse<Response>();
|
|
42
|
+
|
|
43
|
+
// Check if authentication is optional
|
|
44
|
+
const isOptional = this.reflector.getAllAndOverride<boolean>(OPTIONAL_AUTH_KEY, [
|
|
45
|
+
context.getHandler(),
|
|
46
|
+
context.getClass(),
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
// Initialize request properties
|
|
50
|
+
request.user = null;
|
|
51
|
+
request.session = null;
|
|
52
|
+
request.accessKey = null;
|
|
53
|
+
request.authType = null;
|
|
54
|
+
|
|
55
|
+
const authHeader = request.headers.authorization;
|
|
56
|
+
|
|
57
|
+
// If no auth header
|
|
58
|
+
if (!authHeader) {
|
|
59
|
+
if (isOptional) {
|
|
60
|
+
// Optional auth: allow request to proceed without user data
|
|
61
|
+
return true;
|
|
62
|
+
} else {
|
|
63
|
+
// Required auth: throw error
|
|
64
|
+
throw new UnauthorizedException({
|
|
65
|
+
message: 'No authentication provided',
|
|
66
|
+
code: 'NO_AUTH'
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const [type, token] = authHeader.split(' ');
|
|
72
|
+
if (!type || !token) {
|
|
73
|
+
if (isOptional) {
|
|
74
|
+
return true;
|
|
75
|
+
} else {
|
|
76
|
+
throw new UnauthorizedException({
|
|
77
|
+
message: 'Invalid authentication format',
|
|
78
|
+
code: 'INVALID_AUTH_FORMAT'
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Handle authentication
|
|
84
|
+
let isAuthenticated = false;
|
|
85
|
+
try {
|
|
86
|
+
switch (type.toLowerCase()) {
|
|
87
|
+
case 'bearer':
|
|
88
|
+
isAuthenticated = await this.handleJwtAuth(context, request, response, token, isOptional);
|
|
89
|
+
break;
|
|
90
|
+
case 'apikey':
|
|
91
|
+
isAuthenticated = await this.handleApiKeyAuth(request, token, isOptional);
|
|
92
|
+
break;
|
|
93
|
+
default:
|
|
94
|
+
if (isOptional) {
|
|
95
|
+
// Invalid auth type, but optional - proceed without user data
|
|
96
|
+
return true;
|
|
97
|
+
} else {
|
|
98
|
+
throw new UnauthorizedException({
|
|
99
|
+
message: 'Invalid authentication type',
|
|
100
|
+
code: 'INVALID_AUTH_TYPE'
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (isOptional) {
|
|
106
|
+
// If optional auth fails, silently proceed without user data
|
|
107
|
+
return true;
|
|
108
|
+
} else {
|
|
109
|
+
// If required auth fails, re-throw the error
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// If authentication failed and it's required, stop here
|
|
115
|
+
if (!isAuthenticated && !isOptional) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// After successful authentication, check authorization (roles, permissions)
|
|
120
|
+
// Only check authorization if user is authenticated
|
|
121
|
+
if (isAuthenticated && request.user) {
|
|
122
|
+
await this.checkAuthorization(context, request);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private async handleJwtAuth(context: ExecutionContext, request: any, response: Response, token: string, isOptional: boolean = false): Promise<boolean> {
|
|
129
|
+
try {
|
|
130
|
+
// Verify the JWT token
|
|
131
|
+
const payload = await this.jwtService.verifyToken(token);
|
|
132
|
+
request.user = payload;
|
|
133
|
+
request.authType = 'jwt';
|
|
134
|
+
|
|
135
|
+
// Verify session exists
|
|
136
|
+
const session = await this.sessionManager.getSession(payload.sessionId as string);
|
|
137
|
+
if (!session) {
|
|
138
|
+
if (isOptional) {
|
|
139
|
+
// Session not found but auth is optional - reset user data and continue
|
|
140
|
+
request.user = null;
|
|
141
|
+
request.authType = null;
|
|
142
|
+
return false;
|
|
143
|
+
} else {
|
|
144
|
+
throw new UnauthorizedException({
|
|
145
|
+
message: 'Session not found',
|
|
146
|
+
code: UNAUTHORIZED_EXCEPTION_CODE
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
request.session = session;
|
|
152
|
+
|
|
153
|
+
// Check MFA requirements
|
|
154
|
+
await this.checkMfa(context, payload, isOptional);
|
|
155
|
+
return true;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
// Token verification failed
|
|
158
|
+
// Note: Token refresh is handled by RefreshTokenInterceptor
|
|
159
|
+
if (isOptional) {
|
|
160
|
+
// Auth is optional - continue without user data
|
|
161
|
+
return false;
|
|
162
|
+
} else {
|
|
163
|
+
throw new UnauthorizedException({
|
|
164
|
+
message: 'Invalid or expired token',
|
|
165
|
+
code: UNAUTHORIZED_EXCEPTION_CODE
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private async handleApiKeyAuth(request: any, token: string, isOptional: boolean = false): Promise<boolean> {
|
|
172
|
+
// Split the token into public and private parts
|
|
173
|
+
const [publicKey, privateKey] = token.split('.');
|
|
174
|
+
if (!publicKey || !privateKey) {
|
|
175
|
+
if (isOptional) {
|
|
176
|
+
// Invalid format but auth is optional - continue without user data
|
|
177
|
+
return false;
|
|
178
|
+
} else {
|
|
179
|
+
throw new UnauthorizedException({
|
|
180
|
+
message: 'Invalid API key format',
|
|
181
|
+
code: 'INVALID_API_KEY_FORMAT'
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
// Validate API key pair
|
|
188
|
+
const isValid = await this.accessKeyService.validateAccessKey(publicKey, privateKey);
|
|
189
|
+
if (!isValid) {
|
|
190
|
+
if (isOptional) {
|
|
191
|
+
// Invalid API key but auth is optional - continue without user data
|
|
192
|
+
return false;
|
|
193
|
+
} else {
|
|
194
|
+
throw new UnauthorizedException({
|
|
195
|
+
message: 'Invalid API key',
|
|
196
|
+
code: 'INVALID_API_KEY'
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Get access key details
|
|
202
|
+
const accessKey = await this.accessKeyService.getAccessKey(publicKey);
|
|
203
|
+
|
|
204
|
+
// Update last used timestamp
|
|
205
|
+
await this.accessKeyService.updateAccessKeyLastUsed(publicKey);
|
|
206
|
+
|
|
207
|
+
// Attach user and access key to request
|
|
208
|
+
request.user = accessKey.user;
|
|
209
|
+
request.accessKey = accessKey;
|
|
210
|
+
request.authType = 'api-key';
|
|
211
|
+
|
|
212
|
+
return true;
|
|
213
|
+
} catch (error) {
|
|
214
|
+
if (isOptional) {
|
|
215
|
+
// API key validation failed but auth is optional - continue without user data
|
|
216
|
+
return false;
|
|
217
|
+
} else {
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
private async checkMfa(context: ExecutionContext, payload: JWTTokenPayload, isOptional: boolean = false): Promise<void> {
|
|
225
|
+
// Check if MFA should be skipped
|
|
226
|
+
const skipMfa = this.reflector.getAllAndOverride<boolean>(SKIP_MFA_KEY, [
|
|
227
|
+
context.getHandler(),
|
|
228
|
+
context.getClass(),
|
|
229
|
+
]);
|
|
230
|
+
|
|
231
|
+
// Get MFA status from token
|
|
232
|
+
const isMfaEnabled = payload.isMfaEnabled;
|
|
233
|
+
const isMfaVerified = payload.isMfaVerified;
|
|
234
|
+
|
|
235
|
+
// If MFA is enabled and not verified, and route is not marked to skip MFA, require MFA verification
|
|
236
|
+
if (isMfaEnabled && !isMfaVerified && !skipMfa) {
|
|
237
|
+
if (isOptional) {
|
|
238
|
+
// MFA required but auth is optional - this creates a conflict
|
|
239
|
+
// In this case, we should not set user data since MFA is not verified
|
|
240
|
+
throw new Error('MFA verification required - cannot proceed with optional auth');
|
|
241
|
+
} else {
|
|
242
|
+
throw new UnauthorizedException({
|
|
243
|
+
message: 'Multi-factor authentication is required',
|
|
244
|
+
code: UNAUTHORIZED_EXCEPTION_CODE
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Check authorization (roles, permissions) after successful authentication
|
|
252
|
+
*/
|
|
253
|
+
private async checkAuthorization(context: ExecutionContext, request: Request): Promise<void> {
|
|
254
|
+
// Get required permissions and roles from decorators
|
|
255
|
+
const requiredPermissions = this.getRequiredPermissions(context);
|
|
256
|
+
const requiredRoles = this.getRequiredRoles(context);
|
|
257
|
+
|
|
258
|
+
// If no authorization requirements, allow access
|
|
259
|
+
if (!requiredPermissions.length && !requiredRoles.length) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const user = request.user;
|
|
264
|
+
|
|
265
|
+
// Check if user exists
|
|
266
|
+
if (!user) {
|
|
267
|
+
throw new ForbiddenException('Access denied: User not authenticated');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Check roles if required
|
|
271
|
+
if (requiredRoles.length > 0) {
|
|
272
|
+
this.checkRoles(user, requiredRoles);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Check permissions if required
|
|
276
|
+
if (requiredPermissions.length > 0) {
|
|
277
|
+
this.checkPermissions(user, requiredPermissions);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Get required permissions from decorator
|
|
283
|
+
*/
|
|
284
|
+
private getRequiredPermissions(context: ExecutionContext): string[] {
|
|
285
|
+
let permissions = this.reflector.getAllAndOverride<string[] | string>(
|
|
286
|
+
PERMISSIONS_KEY,
|
|
287
|
+
[context.getHandler(), context.getClass()],
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
if (!permissions) {
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Normalize to array
|
|
295
|
+
return typeof permissions === 'string' ? [permissions] : permissions;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Get required roles from decorator
|
|
300
|
+
*/
|
|
301
|
+
private getRequiredRoles(context: ExecutionContext): string[] {
|
|
302
|
+
let roles = this.reflector.getAllAndOverride<string[] | string>(
|
|
303
|
+
ROLES_KEY,
|
|
304
|
+
[context.getHandler(), context.getClass()],
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
if (!roles) {
|
|
308
|
+
return [];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Normalize to array
|
|
312
|
+
return typeof roles === 'string' ? [roles] : roles;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Check if user has required roles
|
|
317
|
+
*/
|
|
318
|
+
private checkRoles(user: any, requiredRoles: string[]): void {
|
|
319
|
+
if (!user.roles || !Array.isArray(user.roles)) {
|
|
320
|
+
throw new ForbiddenException('Access denied: No roles assigned');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Get active role names
|
|
324
|
+
const userRoleNames = user.roles
|
|
325
|
+
.filter(role => role.isActive)
|
|
326
|
+
.map(role => role.name);
|
|
327
|
+
|
|
328
|
+
// Check if user has all required roles
|
|
329
|
+
const hasAllRoles = requiredRoles.every(role => userRoleNames.includes(role));
|
|
330
|
+
|
|
331
|
+
if (!hasAllRoles) {
|
|
332
|
+
const missingRoles = requiredRoles.filter(role => !userRoleNames.includes(role));
|
|
333
|
+
throw new ForbiddenException(
|
|
334
|
+
`Access denied: Missing required roles: ${missingRoles.join(', ')}`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Check if user has required permissions
|
|
341
|
+
*/
|
|
342
|
+
private checkPermissions(user: any, requiredPermissions: string[]): void {
|
|
343
|
+
if (!user.roles || !Array.isArray(user.roles)) {
|
|
344
|
+
throw new ForbiddenException('Access denied: No roles assigned for permission check');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Get all permissions from user's roles
|
|
348
|
+
const userPermissions = this.getUserPermissions(user.roles);
|
|
349
|
+
|
|
350
|
+
// Check if user has all required permissions
|
|
351
|
+
const hasAllPermissions = requiredPermissions.every(permission =>
|
|
352
|
+
userPermissions.includes(permission)
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
if (!hasAllPermissions) {
|
|
356
|
+
const missingPermissions = requiredPermissions.filter(permission =>
|
|
357
|
+
!userPermissions.includes(permission)
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
throw new ForbiddenException(
|
|
361
|
+
`Access denied: Missing required permissions: ${missingPermissions.join(', ')}`
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Extract all permissions from user's roles
|
|
368
|
+
*/
|
|
369
|
+
private getUserPermissions(roles: any[]): string[] {
|
|
370
|
+
const permissions = new Set<string>();
|
|
371
|
+
|
|
372
|
+
roles.forEach(role => {
|
|
373
|
+
// Skip inactive roles
|
|
374
|
+
if (!role.isActive) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Add permissions from this role
|
|
379
|
+
if (role.permissions && Array.isArray(role.permissions)) {
|
|
380
|
+
role.permissions.forEach(permission => permissions.add(permission));
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
return Array.from(permissions);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
// Guards
|
|
1
2
|
export * from './guards/auth.guard';
|
|
2
3
|
export { OPTIONAL_AUTH_KEY } from './guards/auth.guard';
|
|
4
|
+
|
|
5
|
+
// Interceptors
|
|
6
|
+
export * from './interceptors/refresh-token.interceptor';
|
|
7
|
+
|
|
8
|
+
// Events
|
|
3
9
|
export * from './events/logged-out-all.event';
|
|
4
10
|
export * from './events/logged-out.event';
|
|
5
11
|
export * from './events/password-reset-requested.event';
|
|
@@ -8,18 +14,39 @@ export * from './events/user-2fa-verified.event';
|
|
|
8
14
|
export * from './events/user-logged-in.event';
|
|
9
15
|
export * from './events/user-refresh-token.event';
|
|
10
16
|
export * from './events/user-registered.event';
|
|
17
|
+
|
|
18
|
+
// Services
|
|
11
19
|
export * from './services/auth.service';
|
|
12
20
|
export * from './services/cookie.service';
|
|
13
21
|
export * from './services/mfa.service';
|
|
22
|
+
export * from './services/client-config.service';
|
|
23
|
+
|
|
24
|
+
// Controllers
|
|
14
25
|
export * from './controllers/auth.controller';
|
|
15
26
|
export * from './controllers/mfa.controller';
|
|
27
|
+
|
|
28
|
+
// DTOs
|
|
16
29
|
export * from './dto/requests/login.request.dto';
|
|
17
30
|
export * from './dto/requests/signup.request.dto';
|
|
18
|
-
export * from './dto/
|
|
31
|
+
export * from './dto/credentials/social-credentials.dto';
|
|
32
|
+
export * from './dto/credentials/email-credentials.dto';
|
|
33
|
+
export * from './dto/credentials/phone-credentials.dto';
|
|
19
34
|
export * from './dto/requests/forgot-password.request.dto';
|
|
20
35
|
export * from './dto/requests/reset-password.request.dto';
|
|
36
|
+
export * from './dto/requests/reset-password-with-token.request.dto';
|
|
37
|
+
export * from './dto/requests/verify-forgot-password-otp-request-dto';
|
|
21
38
|
export * from './dto/requests/send-mfa-code.request.dto';
|
|
39
|
+
export * from './dto/requests/change-password.request.dto';
|
|
40
|
+
export * from './dto/requests/toggle-mfa.request.dto';
|
|
22
41
|
export * from './dto/requests/refresh-token.request.dto';
|
|
23
42
|
export * from './dto/requests/verify-2fa.request.dto';
|
|
24
43
|
export * from './dto/requests/verify-totp-setup.request.dto';
|
|
25
44
|
export * from './dto/responses/auth.response.dto';
|
|
45
|
+
export * from './dto/responses/auth-cookie.response.dto';
|
|
46
|
+
export * from './dto/responses/verify-otp.response.dto';
|
|
47
|
+
export * from './dto/responses/mfa-status.response.dto';
|
|
48
|
+
export * from './dto/responses/client-config.response.dto';
|
|
49
|
+
|
|
50
|
+
// Entities
|
|
51
|
+
export * from './entities/otp.entity';
|
|
52
|
+
export * from './entities/mfa-secret.entity';
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
2
|
+
import { Observable, throwError } from 'rxjs';
|
|
3
|
+
import { catchError } from 'rxjs/operators';
|
|
4
|
+
import { Request, Response } from 'express';
|
|
5
|
+
import { AuthService } from '../services/auth.service';
|
|
6
|
+
import { CookieService } from '../services/cookie.service';
|
|
7
|
+
import { JwtService } from '../../core/services/jwt.service';
|
|
8
|
+
import { AuthConfigService } from '../../core/services/auth-config.service';
|
|
9
|
+
import { REFRESH_TOKEN_COOKIE_NAME, UNAUTHORIZED_EXCEPTION_CODE } from '../../auth.constants';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* RefreshTokenInterceptor
|
|
13
|
+
*
|
|
14
|
+
* Automatically handles token refresh when access token is expired.
|
|
15
|
+
* This interceptor runs before guards and catches token expiration errors,
|
|
16
|
+
* attempting to refresh the token transparently.
|
|
17
|
+
*
|
|
18
|
+
* Token delivery method (header vs cookie) respects the `accessTokenType` configuration:
|
|
19
|
+
* - If `accessTokenType: 'header'` (default): Updates Authorization header only
|
|
20
|
+
* - If `accessTokenType: 'cookie'`: Sets tokens in cookies
|
|
21
|
+
*
|
|
22
|
+
* Apply this globally to handle token refresh across your entire application.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // In AppModule or NestAuthModule configuration
|
|
27
|
+
* providers: [
|
|
28
|
+
* {
|
|
29
|
+
* provide: APP_INTERCEPTOR,
|
|
30
|
+
* useClass: RefreshTokenInterceptor,
|
|
31
|
+
* },
|
|
32
|
+
* ]
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
@Injectable()
|
|
36
|
+
export class RefreshTokenInterceptor implements NestInterceptor {
|
|
37
|
+
constructor(
|
|
38
|
+
private readonly authService: AuthService,
|
|
39
|
+
private readonly cookieService: CookieService,
|
|
40
|
+
private readonly jwtService: JwtService,
|
|
41
|
+
private readonly authConfig: AuthConfigService,
|
|
42
|
+
) { }
|
|
43
|
+
|
|
44
|
+
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
|
|
45
|
+
const request = context.switchToHttp().getRequest<Request>();
|
|
46
|
+
const response = context.switchToHttp().getResponse<Response>();
|
|
47
|
+
|
|
48
|
+
// Extract access token from Authorization header
|
|
49
|
+
const authHeader = request.headers.authorization;
|
|
50
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
51
|
+
// No bearer token, proceed normally
|
|
52
|
+
return next.handle();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const accessToken = authHeader.split(' ')[1];
|
|
56
|
+
if (!accessToken) {
|
|
57
|
+
return next.handle();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Try to verify the access token
|
|
61
|
+
try {
|
|
62
|
+
await this.jwtService.verifyToken(accessToken);
|
|
63
|
+
// Token is valid, proceed normally
|
|
64
|
+
return next.handle();
|
|
65
|
+
} catch (error) {
|
|
66
|
+
// Token is invalid or expired, try to refresh
|
|
67
|
+
const refreshToken = this.extractRefreshToken(request);
|
|
68
|
+
|
|
69
|
+
if (!refreshToken) {
|
|
70
|
+
// No refresh token available, let the guard handle it
|
|
71
|
+
return next.handle();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
// Attempt to refresh the token
|
|
76
|
+
const newSession = await this.authService.refreshToken(refreshToken);
|
|
77
|
+
|
|
78
|
+
// Get auth configuration
|
|
79
|
+
const config = this.authConfig.getConfig();
|
|
80
|
+
const useCookies = config.accessTokenType === 'cookie';
|
|
81
|
+
|
|
82
|
+
if (useCookies) {
|
|
83
|
+
// Cookie-based auth: Set tokens in cookies
|
|
84
|
+
this.cookieService.setTokens(response, newSession.accessToken, newSession.refreshToken);
|
|
85
|
+
} else {
|
|
86
|
+
// Header-based auth (default): Update Authorization header only
|
|
87
|
+
request.headers.authorization = `Bearer ${newSession.accessToken}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Proceed with the new token
|
|
91
|
+
return next.handle();
|
|
92
|
+
} catch (refreshError) {
|
|
93
|
+
// Refresh failed, let the guard handle the authentication failure
|
|
94
|
+
return next.handle();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Extract refresh token from cookies or headers
|
|
101
|
+
*/
|
|
102
|
+
private extractRefreshToken(request: Request): string | null {
|
|
103
|
+
// Try to get refresh token from cookies
|
|
104
|
+
const tokenFromCookie = request.cookies?.[REFRESH_TOKEN_COOKIE_NAME];
|
|
105
|
+
if (tokenFromCookie) {
|
|
106
|
+
return tokenFromCookie;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// If not in cookies, try the custom header
|
|
110
|
+
const authHeader = request.headers['x-refresh-token'];
|
|
111
|
+
if (authHeader) {
|
|
112
|
+
return authHeader as string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|