@techelusive/nest-auth 0.0.0-stage → 0.2.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/CHANGELOG.md +64 -0
- package/LICENSE +21 -0
- package/README.md +204 -2
- package/api/openapi.json +4399 -0
- package/api/techelusive-authentication.postman_collection.json +3178 -0
- package/dist/auth-options.d.ts +156 -0
- package/dist/auth-options.js +3 -0
- package/dist/auth-options.js.map +1 -0
- package/dist/auth-options.validation.d.ts +9 -0
- package/dist/auth-options.validation.js +74 -0
- package/dist/auth-options.validation.js.map +1 -0
- package/dist/auth.module.d.ts +38 -0
- package/dist/auth.module.js +173 -0
- package/dist/auth.module.js.map +1 -0
- package/dist/common/auth-error.d.ts +16 -0
- package/dist/common/auth-error.js +23 -0
- package/dist/common/auth-error.js.map +1 -0
- package/dist/common/auth-exception.filter.d.ts +24 -0
- package/dist/common/auth-exception.filter.js +66 -0
- package/dist/common/auth-exception.filter.js.map +1 -0
- package/dist/common/crypto/jwt.d.ts +89 -0
- package/dist/common/crypto/jwt.js +144 -0
- package/dist/common/crypto/jwt.js.map +1 -0
- package/dist/common/crypto/random-secrets.d.ts +78 -0
- package/dist/common/crypto/random-secrets.js +113 -0
- package/dist/common/crypto/random-secrets.js.map +1 -0
- package/dist/common/crypto/remote-public-keys.d.ts +49 -0
- package/dist/common/crypto/remote-public-keys.js +105 -0
- package/dist/common/crypto/remote-public-keys.js.map +1 -0
- package/dist/common/crypto/totp.d.ts +68 -0
- package/dist/common/crypto/totp.js +148 -0
- package/dist/common/crypto/totp.js.map +1 -0
- package/dist/common/encryption.service.d.ts +36 -0
- package/dist/common/encryption.service.js +111 -0
- package/dist/common/encryption.service.js.map +1 -0
- package/dist/common/identifiers.d.ts +48 -0
- package/dist/common/identifiers.js +89 -0
- package/dist/common/identifiers.js.map +1 -0
- package/dist/common/network-safety.d.ts +19 -0
- package/dist/common/network-safety.js +72 -0
- package/dist/common/network-safety.js.map +1 -0
- package/dist/common/rate-limiter.service.d.ts +63 -0
- package/dist/common/rate-limiter.service.js +158 -0
- package/dist/common/rate-limiter.service.js.map +1 -0
- package/dist/common/refresh-token-cookie.d.ts +78 -0
- package/dist/common/refresh-token-cookie.js +185 -0
- package/dist/common/refresh-token-cookie.js.map +1 -0
- package/dist/common/request-context.d.ts +14 -0
- package/dist/common/request-context.js +22 -0
- package/dist/common/request-context.js.map +1 -0
- package/dist/common/strict-validation.pipe.d.ts +8 -0
- package/dist/common/strict-validation.pipe.js +16 -0
- package/dist/common/strict-validation.pipe.js.map +1 -0
- package/dist/common/time.d.ts +15 -0
- package/dist/common/time.js +34 -0
- package/dist/common/time.js.map +1 -0
- package/dist/constants.d.ts +1326 -0
- package/dist/constants.js +1142 -0
- package/dist/constants.js.map +1 -0
- package/dist/database/create-auth-tables.migration.d.ts +26 -0
- package/dist/database/create-auth-tables.migration.js +291 -0
- package/dist/database/create-auth-tables.migration.js.map +1 -0
- package/dist/database/email-change-and-retention.migration.d.ts +25 -0
- package/dist/database/email-change-and-retention.migration.js +54 -0
- package/dist/database/email-change-and-retention.migration.js.map +1 -0
- package/dist/database/entities/api-key.entity.d.ts +17 -0
- package/dist/database/entities/api-key.entity.js +80 -0
- package/dist/database/entities/api-key.entity.js.map +1 -0
- package/dist/database/entities/audit-log.entity.d.ts +13 -0
- package/dist/database/entities/audit-log.entity.js +64 -0
- package/dist/database/entities/audit-log.entity.js.map +1 -0
- package/dist/database/entities/backup-code.entity.d.ts +9 -0
- package/dist/database/entities/backup-code.entity.js +52 -0
- package/dist/database/entities/backup-code.entity.js.map +1 -0
- package/dist/database/entities/index.d.ts +43 -0
- package/dist/database/entities/index.js +82 -0
- package/dist/database/entities/index.js.map +1 -0
- package/dist/database/entities/json-object.d.ts +12 -0
- package/dist/database/entities/json-object.js +3 -0
- package/dist/database/entities/json-object.js.map +1 -0
- package/dist/database/entities/link-token.entity.d.ts +15 -0
- package/dist/database/entities/link-token.entity.js +64 -0
- package/dist/database/entities/link-token.entity.js.map +1 -0
- package/dist/database/entities/one-time-code.entity.d.ts +16 -0
- package/dist/database/entities/one-time-code.entity.js +69 -0
- package/dist/database/entities/one-time-code.entity.js.map +1 -0
- package/dist/database/entities/organization-invitation.entity.d.ts +14 -0
- package/dist/database/entities/organization-invitation.entity.js +73 -0
- package/dist/database/entities/organization-invitation.entity.js.map +1 -0
- package/dist/database/entities/organization-member.entity.d.ts +9 -0
- package/dist/database/entities/organization-member.entity.js +48 -0
- package/dist/database/entities/organization-member.entity.js.map +1 -0
- package/dist/database/entities/organization.entity.d.ts +12 -0
- package/dist/database/entities/organization.entity.js +58 -0
- package/dist/database/entities/organization.entity.js.map +1 -0
- package/dist/database/entities/passkey.entity.d.ts +19 -0
- package/dist/database/entities/passkey.entity.js +78 -0
- package/dist/database/entities/passkey.entity.js.map +1 -0
- package/dist/database/entities/password.entity.d.ts +6 -0
- package/dist/database/entities/password.entity.js +36 -0
- package/dist/database/entities/password.entity.js.map +1 -0
- package/dist/database/entities/refresh-token.entity.d.ts +9 -0
- package/dist/database/entities/refresh-token.entity.js +53 -0
- package/dist/database/entities/refresh-token.entity.js.map +1 -0
- package/dist/database/entities/session.entity.d.ts +20 -0
- package/dist/database/entities/session.entity.js +87 -0
- package/dist/database/entities/session.entity.js.map +1 -0
- package/dist/database/entities/settings.entity.d.ts +7 -0
- package/dist/database/entities/settings.entity.js +41 -0
- package/dist/database/entities/settings.entity.js.map +1 -0
- package/dist/database/entities/sign-in-challenge.entity.d.ts +23 -0
- package/dist/database/entities/sign-in-challenge.entity.js +80 -0
- package/dist/database/entities/sign-in-challenge.entity.js.map +1 -0
- package/dist/database/entities/signing-key.entity.d.ts +11 -0
- package/dist/database/entities/signing-key.entity.js +54 -0
- package/dist/database/entities/signing-key.entity.js.map +1 -0
- package/dist/database/entities/social-account.entity.d.ts +13 -0
- package/dist/database/entities/social-account.entity.js +54 -0
- package/dist/database/entities/social-account.entity.js.map +1 -0
- package/dist/database/entities/two-factor-secret.entity.d.ts +10 -0
- package/dist/database/entities/two-factor-secret.entity.js +48 -0
- package/dist/database/entities/two-factor-secret.entity.js.map +1 -0
- package/dist/database/entities/user.entity.d.ts +34 -0
- package/dist/database/entities/user.entity.js +129 -0
- package/dist/database/entities/user.entity.js.map +1 -0
- package/dist/database/entities/webhook-delivery.entity.d.ts +17 -0
- package/dist/database/entities/webhook-delivery.entity.js +79 -0
- package/dist/database/entities/webhook-delivery.entity.js.map +1 -0
- package/dist/database/entities/webhook.entity.d.ts +12 -0
- package/dist/database/entities/webhook.entity.js +58 -0
- package/dist/database/entities/webhook.entity.js.map +1 -0
- package/dist/database/typeorm-row.d.ts +21 -0
- package/dist/database/typeorm-row.js +29 -0
- package/dist/database/typeorm-row.js.map +1 -0
- package/dist/features/account/account.controller.d.ts +259 -0
- package/dist/features/account/account.controller.js +372 -0
- package/dist/features/account/account.controller.js.map +1 -0
- package/dist/features/account/account.dto.d.ts +16 -0
- package/dist/features/account/account.dto.js +61 -0
- package/dist/features/account/account.dto.js.map +1 -0
- package/dist/features/account/data-export.service.d.ts +85 -0
- package/dist/features/account/data-export.service.js +125 -0
- package/dist/features/account/data-export.service.js.map +1 -0
- package/dist/features/account/health.service.d.ts +30 -0
- package/dist/features/account/health.service.js +59 -0
- package/dist/features/account/health.service.js.map +1 -0
- package/dist/features/admin/admin.controller.d.ts +382 -0
- package/dist/features/admin/admin.controller.js +623 -0
- package/dist/features/admin/admin.controller.js.map +1 -0
- package/dist/features/admin/admin.dto.d.ts +61 -0
- package/dist/features/admin/admin.dto.js +253 -0
- package/dist/features/admin/admin.dto.js.map +1 -0
- package/dist/features/admin/admin.service.d.ts +142 -0
- package/dist/features/admin/admin.service.js +227 -0
- package/dist/features/admin/admin.service.js.map +1 -0
- package/dist/features/api-keys/api-keys.service.d.ts +67 -0
- package/dist/features/api-keys/api-keys.service.js +144 -0
- package/dist/features/api-keys/api-keys.service.js.map +1 -0
- package/dist/features/email-change/email-change.controller.d.ts +38 -0
- package/dist/features/email-change/email-change.controller.js +85 -0
- package/dist/features/email-change/email-change.controller.js.map +1 -0
- package/dist/features/email-change/email-change.dto.d.ts +10 -0
- package/dist/features/email-change/email-change.dto.js +43 -0
- package/dist/features/email-change/email-change.dto.js.map +1 -0
- package/dist/features/email-change/email-change.service.d.ts +74 -0
- package/dist/features/email-change/email-change.service.js +179 -0
- package/dist/features/email-change/email-change.service.js.map +1 -0
- package/dist/features/email-links/email-verification.service.d.ts +46 -0
- package/dist/features/email-links/email-verification.service.js +94 -0
- package/dist/features/email-links/email-verification.service.js.map +1 -0
- package/dist/features/email-links/link-tokens.service.d.ts +44 -0
- package/dist/features/email-links/link-tokens.service.js +122 -0
- package/dist/features/email-links/link-tokens.service.js.map +1 -0
- package/dist/features/events/auth-events.service.d.ts +52 -0
- package/dist/features/events/auth-events.service.js +117 -0
- package/dist/features/events/auth-events.service.js.map +1 -0
- package/dist/features/maintenance/data-retention.service.d.ts +60 -0
- package/dist/features/maintenance/data-retention.service.js +182 -0
- package/dist/features/maintenance/data-retention.service.js.map +1 -0
- package/dist/features/notifications/notifications.service.d.ts +40 -0
- package/dist/features/notifications/notifications.service.js +94 -0
- package/dist/features/notifications/notifications.service.js.map +1 -0
- package/dist/features/one-time-codes/one-time-codes.service.d.ts +40 -0
- package/dist/features/one-time-codes/one-time-codes.service.js +102 -0
- package/dist/features/one-time-codes/one-time-codes.service.js.map +1 -0
- package/dist/features/organizations/organizations.controller.d.ts +220 -0
- package/dist/features/organizations/organizations.controller.js +337 -0
- package/dist/features/organizations/organizations.controller.js.map +1 -0
- package/dist/features/organizations/organizations.dto.d.ts +31 -0
- package/dist/features/organizations/organizations.dto.js +100 -0
- package/dist/features/organizations/organizations.dto.js.map +1 -0
- package/dist/features/organizations/organizations.service.d.ts +274 -0
- package/dist/features/organizations/organizations.service.js +481 -0
- package/dist/features/organizations/organizations.service.js.map +1 -0
- package/dist/features/passkeys/passkeys.controller.d.ts +92 -0
- package/dist/features/passkeys/passkeys.controller.js +183 -0
- package/dist/features/passkeys/passkeys.controller.js.map +1 -0
- package/dist/features/passkeys/passkeys.dto.d.ts +13 -0
- package/dist/features/passkeys/passkeys.dto.js +50 -0
- package/dist/features/passkeys/passkeys.dto.js.map +1 -0
- package/dist/features/passkeys/passkeys.service.d.ts +159 -0
- package/dist/features/passkeys/passkeys.service.js +350 -0
- package/dist/features/passkeys/passkeys.service.js.map +1 -0
- package/dist/features/passwordless/passwordless-auth.service.d.ts +152 -0
- package/dist/features/passwordless/passwordless-auth.service.js +304 -0
- package/dist/features/passwordless/passwordless-auth.service.js.map +1 -0
- package/dist/features/passwordless/passwordless.controller.d.ts +75 -0
- package/dist/features/passwordless/passwordless.controller.js +163 -0
- package/dist/features/passwordless/passwordless.controller.js.map +1 -0
- package/dist/features/passwordless/passwordless.dto.d.ts +29 -0
- package/dist/features/passwordless/passwordless.dto.js +101 -0
- package/dist/features/passwordless/passwordless.dto.js.map +1 -0
- package/dist/features/passwords/password-auth.service.d.ts +154 -0
- package/dist/features/passwords/password-auth.service.js +317 -0
- package/dist/features/passwords/password-auth.service.js.map +1 -0
- package/dist/features/passwords/password-policy.service.d.ts +63 -0
- package/dist/features/passwords/password-policy.service.js +175 -0
- package/dist/features/passwords/password-policy.service.js.map +1 -0
- package/dist/features/passwords/password.controller.d.ts +95 -0
- package/dist/features/passwords/password.controller.js +193 -0
- package/dist/features/passwords/password.controller.js.map +1 -0
- package/dist/features/passwords/password.dto.d.ts +36 -0
- package/dist/features/passwords/password.dto.js +140 -0
- package/dist/features/passwords/password.dto.js.map +1 -0
- package/dist/features/sessions/session.service.d.ts +132 -0
- package/dist/features/sessions/session.service.js +308 -0
- package/dist/features/sessions/session.service.js.map +1 -0
- package/dist/features/sessions/session.types.d.ts +34 -0
- package/dist/features/sessions/session.types.js +3 -0
- package/dist/features/sessions/session.types.js.map +1 -0
- package/dist/features/settings/settings.defaults.d.ts +2 -0
- package/dist/features/settings/settings.defaults.js +7 -0
- package/dist/features/settings/settings.defaults.js.map +1 -0
- package/dist/features/settings/settings.service.d.ts +44 -0
- package/dist/features/settings/settings.service.js +112 -0
- package/dist/features/settings/settings.service.js.map +1 -0
- package/dist/features/settings/settings.types.d.ts +133 -0
- package/dist/features/settings/settings.types.js +3 -0
- package/dist/features/settings/settings.types.js.map +1 -0
- package/dist/features/settings/settings.validation.d.ts +33 -0
- package/dist/features/settings/settings.validation.js +614 -0
- package/dist/features/settings/settings.validation.js.map +1 -0
- package/dist/features/sign-in/sign-in-challenges.service.d.ts +54 -0
- package/dist/features/sign-in/sign-in-challenges.service.js +104 -0
- package/dist/features/sign-in/sign-in-challenges.service.js.map +1 -0
- package/dist/features/sign-in/sign-in.service.d.ts +127 -0
- package/dist/features/sign-in/sign-in.service.js +248 -0
- package/dist/features/sign-in/sign-in.service.js.map +1 -0
- package/dist/features/sign-in/sign-in.types.d.ts +22 -0
- package/dist/features/sign-in/sign-in.types.js +3 -0
- package/dist/features/sign-in/sign-in.types.js.map +1 -0
- package/dist/features/signing-keys/jwks.controller.d.ts +17 -0
- package/dist/features/signing-keys/jwks.controller.js +51 -0
- package/dist/features/signing-keys/jwks.controller.js.map +1 -0
- package/dist/features/signing-keys/signing-keys.service.d.ts +67 -0
- package/dist/features/signing-keys/signing-keys.service.js +142 -0
- package/dist/features/signing-keys/signing-keys.service.js.map +1 -0
- package/dist/features/social/social-auth.service.d.ts +100 -0
- package/dist/features/social/social-auth.service.js +232 -0
- package/dist/features/social/social-auth.service.js.map +1 -0
- package/dist/features/social/social-providers.service.d.ts +97 -0
- package/dist/features/social/social-providers.service.js +214 -0
- package/dist/features/social/social-providers.service.js.map +1 -0
- package/dist/features/social/social.controller.d.ts +54 -0
- package/dist/features/social/social.controller.js +124 -0
- package/dist/features/social/social.controller.js.map +1 -0
- package/dist/features/social/social.dto.d.ts +11 -0
- package/dist/features/social/social.dto.js +38 -0
- package/dist/features/social/social.dto.js.map +1 -0
- package/dist/features/two-factor/two-factor.controller.d.ts +84 -0
- package/dist/features/two-factor/two-factor.controller.js +174 -0
- package/dist/features/two-factor/two-factor.controller.js.map +1 -0
- package/dist/features/two-factor/two-factor.dto.d.ts +10 -0
- package/dist/features/two-factor/two-factor.dto.js +37 -0
- package/dist/features/two-factor/two-factor.dto.js.map +1 -0
- package/dist/features/two-factor/two-factor.service.d.ts +171 -0
- package/dist/features/two-factor/two-factor.service.js +348 -0
- package/dist/features/two-factor/two-factor.service.js.map +1 -0
- package/dist/features/users/sign-in-methods.service.d.ts +40 -0
- package/dist/features/users/sign-in-methods.service.js +81 -0
- package/dist/features/users/sign-in-methods.service.js.map +1 -0
- package/dist/features/users/sign-up-rules.d.ts +12 -0
- package/dist/features/users/sign-up-rules.js +29 -0
- package/dist/features/users/sign-up-rules.js.map +1 -0
- package/dist/features/users/users.service.d.ts +246 -0
- package/dist/features/users/users.service.js +509 -0
- package/dist/features/users/users.service.js.map +1 -0
- package/dist/features/users/users.types.d.ts +24 -0
- package/dist/features/users/users.types.js +3 -0
- package/dist/features/users/users.types.js.map +1 -0
- package/dist/features/webhooks/webhook-delivery.worker.d.ts +55 -0
- package/dist/features/webhooks/webhook-delivery.worker.js +175 -0
- package/dist/features/webhooks/webhook-delivery.worker.js.map +1 -0
- package/dist/features/webhooks/webhook-signature.d.ts +28 -0
- package/dist/features/webhooks/webhook-signature.js +85 -0
- package/dist/features/webhooks/webhook-signature.js.map +1 -0
- package/dist/features/webhooks/webhooks.service.d.ts +144 -0
- package/dist/features/webhooks/webhooks.service.js +238 -0
- package/dist/features/webhooks/webhooks.service.js.map +1 -0
- package/dist/guards/auth.decorators.d.ts +65 -0
- package/dist/guards/auth.decorators.js +68 -0
- package/dist/guards/auth.decorators.js.map +1 -0
- package/dist/guards/auth.guard.d.ts +47 -0
- package/dist/guards/auth.guard.js +132 -0
- package/dist/guards/auth.guard.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/console-email-sender.d.ts +15 -0
- package/dist/integrations/console-email-sender.js +26 -0
- package/dist/integrations/console-email-sender.js.map +1 -0
- package/dist/integrations/msg91-sms-sender.d.ts +28 -0
- package/dist/integrations/msg91-sms-sender.js +46 -0
- package/dist/integrations/msg91-sms-sender.js.map +1 -0
- package/docs/README.md +39 -0
- package/docs/admin-api-keys-webhooks.md +147 -0
- package/docs/api-reference.md +175 -0
- package/docs/architecture.md +119 -0
- package/docs/client-integration.md +192 -0
- package/docs/code-walkthrough.md +273 -0
- package/docs/configuration.md +229 -0
- package/docs/endpoints/README.md +151 -0
- package/docs/endpoints/account.md +363 -0
- package/docs/endpoints/admin.md +422 -0
- package/docs/endpoints/email-password.md +261 -0
- package/docs/endpoints/organizations.md +192 -0
- package/docs/endpoints/passkeys.md +195 -0
- package/docs/endpoints/passwordless.md +214 -0
- package/docs/endpoints/social.md +116 -0
- package/docs/endpoints/two-factor.md +146 -0
- package/docs/error-codes.md +100 -0
- package/docs/events.md +83 -0
- package/docs/getting-started.md +139 -0
- package/docs/manual-testing.md +215 -0
- package/docs/organizations.md +86 -0
- package/docs/production-checklist.md +60 -0
- package/docs/protecting-routes.md +147 -0
- package/docs/security.md +61 -0
- package/docs/sign-in-flows.md +294 -0
- package/package.json +92 -4
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# Admin
|
|
2
|
+
|
|
3
|
+
Every route needs a signed-in user holding one of `settings.admin.adminRoles` (default `["admin"]`), and the session is checked live. Other users get `403 FORBIDDEN`. Concepts are explained in [Admin, API keys and webhooks](../admin-api-keys-webhooks.md).
|
|
4
|
+
|
|
5
|
+
## Paged lists
|
|
6
|
+
|
|
7
|
+
List endpoints accept `?page=1&pageSize=50` (page size 1–200, default 50) and return:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{ "success": true, "users": [], "total": 1234, "page": 1, "pageSize": 50 }
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Users
|
|
16
|
+
|
|
17
|
+
### GET /auth/admin/users
|
|
18
|
+
|
|
19
|
+
| Query | Type | Notes |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `search` | string | matches email, phone, first or last name (partial, case-insensitive) |
|
|
22
|
+
| `status` | `PENDING_VERIFICATION` \| `ACTIVE` \| `SUSPENDED` \| `DEACTIVATED` \| `DELETED` | deleted users are hidden unless asked for |
|
|
23
|
+
| `role` | string | e.g. `seller` |
|
|
24
|
+
| `page`, `pageSize` | number | |
|
|
25
|
+
|
|
26
|
+
```http
|
|
27
|
+
GET /auth/admin/users?search=asha&status=ACTIVE&page=1&pageSize=20
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Response `200`**
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{ "success": true, "users": [{ "id": "5f0c...", "email": "asha@example.com", "status": "ACTIVE", "...": "user object" }], "total": 1, "page": 1, "pageSize": 20 }
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### GET /auth/admin/users/:userId
|
|
37
|
+
|
|
38
|
+
**Response `200`**
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"success": true,
|
|
43
|
+
"user": { "id": "5f0c...", "...": "user object" },
|
|
44
|
+
"suspensionReason": null,
|
|
45
|
+
"statusChangedAt": "2026-10-01T09:05:00.000Z",
|
|
46
|
+
"termsAcceptedAt": "2026-10-01T09:00:00.000Z",
|
|
47
|
+
"privacyPolicyAcceptedAt": "2026-10-01T09:00:00.000Z",
|
|
48
|
+
"signInMethods": { "hasPassword": true, "canUseEmailCode": false, "canUsePhoneCode": false, "socialAccounts": [], "passkeyCount": 0 },
|
|
49
|
+
"sessions": [
|
|
50
|
+
{ "id": "8c1e...", "signInMethod": "password", "ipAddress": "203.0.113.10", "userAgent": "Mozilla/5.0 ...", "createdAt": "2026-10-20T06:30:00.000Z", "lastUsedAt": "2026-10-20T07:10:00.000Z" }
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Errors: `404 NOT_FOUND` (also for deleted users).
|
|
56
|
+
|
|
57
|
+
### PATCH /auth/admin/users/:userId
|
|
58
|
+
|
|
59
|
+
**Request** (all optional):
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{ "firstName": "Asha", "lastName": "Rao", "metadata": { "kycStatus": "approved" } }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Response `200`:** `{ "success": true, "user": { ... } }`
|
|
66
|
+
|
|
67
|
+
### PUT /auth/admin/users/:userId/roles
|
|
68
|
+
|
|
69
|
+
Replaces the user's roles. The change appears in the user's next access token.
|
|
70
|
+
|
|
71
|
+
**Request**
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{ "roles": ["user", "seller"] }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Each role starts with a letter and uses letters, digits, `_`, `:` or `-`, up to 50 characters, with at most 20 roles.
|
|
78
|
+
|
|
79
|
+
**Response `200`:** `{ "success": true, "user": { ... } }`
|
|
80
|
+
|
|
81
|
+
### POST /auth/admin/users/:userId/suspend
|
|
82
|
+
|
|
83
|
+
Blocks the account and signs it out everywhere. The reason is visible to admins only.
|
|
84
|
+
|
|
85
|
+
**Request**
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{ "reason": "Chargeback fraud, support ticket 4411" }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`reason` is required, up to 500 characters.
|
|
92
|
+
|
|
93
|
+
**Response `200`:** `{ "success": true, "user": { "status": "SUSPENDED", ... } }`
|
|
94
|
+
|
|
95
|
+
### POST /auth/admin/users/:userId/unsuspend
|
|
96
|
+
|
|
97
|
+
No body. The account returns to `ACTIVE`, or to `PENDING_VERIFICATION` if verification is still owed. **Response `200`:** `{ "success": true, "user": { ... } }`
|
|
98
|
+
|
|
99
|
+
### POST /auth/admin/users/:userId/verify-email
|
|
100
|
+
|
|
101
|
+
No body. Marks the email verified (e.g. after a support check) and activates the account if nothing else is pending. **Response `200`:** `{ "success": true, "user": { ... } }`
|
|
102
|
+
|
|
103
|
+
### POST /auth/admin/users/:userId/reset-2fa
|
|
104
|
+
|
|
105
|
+
No body. Turns off two-factor for a user who lost their phone and backup codes. Confirm their identity first. **Response `200`:** `{ "success": true }`
|
|
106
|
+
|
|
107
|
+
### POST /auth/admin/users/:userId/logout-all
|
|
108
|
+
|
|
109
|
+
No body. **Response `200`:** `{ "success": true, "endedSessions": 2 }`
|
|
110
|
+
|
|
111
|
+
### DELETE /auth/admin/users/:userId
|
|
112
|
+
|
|
113
|
+
No body. Deletes the account permanently (personal data wiped). **Response `200`:** `{ "success": true }`
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Settings
|
|
118
|
+
|
|
119
|
+
### GET /auth/admin/settings
|
|
120
|
+
|
|
121
|
+
**Response `200`:** the settings in force (every section; see [Configuration](../configuration.md#reference)).
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"success": true,
|
|
126
|
+
"settings": {
|
|
127
|
+
"registration": { "enabled": true, "defaultRoles": ["user"], "requireFirstAndLastName": true, "requirePhoneNumber": false, "requireTermsAcceptance": true, "requirePrivacyPolicyAcceptance": true, "allowedEmailDomains": [] },
|
|
128
|
+
"activation": { "requireVerifiedEmail": true, "requireVerifiedPhone": false },
|
|
129
|
+
"password": { "enabled": true, "minimumLength": 10, "requireUppercaseLetter": false, "requireLowercaseLetter": false, "requireNumber": false, "requireSymbol": false, "rejectBreachedPasswords": true, "notifyOnChange": true },
|
|
130
|
+
"emailVerification": { "linkExpiresInHours": 24 },
|
|
131
|
+
"passwordReset": { "linkExpiresInMinutes": 60 },
|
|
132
|
+
"emailChange": { "linkExpiresInMinutes": 60 },
|
|
133
|
+
"emailOtp": { "enabled": false, "codeLength": 6, "expiresInMinutes": 10, "resendAfterSeconds": 60, "allowSignUp": true },
|
|
134
|
+
"magicLink": { "enabled": false, "expiresInMinutes": 15, "allowSignUp": true },
|
|
135
|
+
"phoneOtp": { "enabled": false, "codeLength": 6, "expiresInMinutes": 10, "resendAfterSeconds": 60, "allowSignUp": true, "allowedCountryCodes": [] },
|
|
136
|
+
"google": { "enabled": false, "clientIds": [] },
|
|
137
|
+
"apple": { "enabled": false, "clientIds": [] },
|
|
138
|
+
"facebook": { "enabled": false, "appId": "" },
|
|
139
|
+
"passkeys": { "enabled": false },
|
|
140
|
+
"twoFactor": { "enabled": true, "challengeExpiresInMinutes": 5 },
|
|
141
|
+
"organizations": { "enabled": false, "allowUsersToCreate": true, "invitationExpiresInDays": 7 },
|
|
142
|
+
"tokens": { "accessTokenMinutes": 15, "refreshTokenDays": 30, "sessionDays": 90 },
|
|
143
|
+
"admin": { "adminRoles": ["admin"] },
|
|
144
|
+
"security": { "notifyOnNewSignIn": false },
|
|
145
|
+
"retention": { "enabled": true, "expiredRecordDays": 7, "webhookDeliveryDays": 30, "auditLogDays": 365 }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### PATCH /auth/admin/settings
|
|
151
|
+
|
|
152
|
+
Changes only the fields you send. Changes reach every server within 10 seconds.
|
|
153
|
+
|
|
154
|
+
**Request**
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{ "emailOtp": { "enabled": true }, "phoneOtp": { "enabled": true, "allowedCountryCodes": ["+91"] } }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Response `200`:** `{ "success": true, "settings": { ...settings in force } }`
|
|
161
|
+
|
|
162
|
+
**Errors**
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"success": false,
|
|
167
|
+
"code": "INVALID_SETTINGS",
|
|
168
|
+
"message": "Some settings are not valid.",
|
|
169
|
+
"problems": ["tokens.accessTokenMinutes must not be greater than 60", "google.clientIds is required when Google is enabled"]
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### DELETE /auth/admin/settings
|
|
174
|
+
|
|
175
|
+
No body. Discards all admin changes; the settings from code apply again. **Response `200`:** `{ "success": true, "settings": { ... } }`
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Security and operations
|
|
180
|
+
|
|
181
|
+
### GET /auth/admin/audit-log
|
|
182
|
+
|
|
183
|
+
| Query | Type |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `userId` | uuid |
|
|
186
|
+
| `eventName` | string, e.g. `user.sign_in_failed` |
|
|
187
|
+
| `page`, `pageSize` | number |
|
|
188
|
+
|
|
189
|
+
**Response `200`**
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"success": true,
|
|
194
|
+
"entries": [
|
|
195
|
+
{
|
|
196
|
+
"id": "e1f2...",
|
|
197
|
+
"userId": "5f0c...",
|
|
198
|
+
"performedBy": null,
|
|
199
|
+
"eventName": "user.sign_in_failed",
|
|
200
|
+
"ipAddress": "203.0.113.10",
|
|
201
|
+
"userAgent": "Mozilla/5.0 ...",
|
|
202
|
+
"details": { "signInMethod": "password", "reason": "wrong_email_or_password" },
|
|
203
|
+
"createdAt": "2026-10-20T06:29:00.000Z"
|
|
204
|
+
}
|
|
205
|
+
],
|
|
206
|
+
"total": 1,
|
|
207
|
+
"page": 1,
|
|
208
|
+
"pageSize": 50
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### GET /auth/admin/stats
|
|
213
|
+
|
|
214
|
+
Numbers for an admin dashboard or monitoring. The last-24-hours counts come from the audit log, so they cover every server.
|
|
215
|
+
|
|
216
|
+
**Response `200`**
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"success": true,
|
|
221
|
+
"usersByStatus": { "PENDING_VERIFICATION": 0, "ACTIVE": 1, "SUSPENDED": 0, "DEACTIVATED": 0, "DELETED": 0 },
|
|
222
|
+
"activeSessions": 1,
|
|
223
|
+
"last24Hours": { "signIns": 1, "failedSignIns": 0, "newUsers": 1, "refreshTokenReuses": 0, "passwordResetsRequested": 0 },
|
|
224
|
+
"pendingWebhookDeliveries": 0,
|
|
225
|
+
"generatedAt": "2026-10-20T09:36:59.812Z"
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Worth alerting on: a jump in `failedSignIns` (password guessing), any `refreshTokenReuses` (a token may have been stolen), and `pendingWebhookDeliveries` that keeps growing (a receiver is down).
|
|
230
|
+
|
|
231
|
+
### POST /auth/admin/maintenance/cleanup
|
|
232
|
+
|
|
233
|
+
No body. Runs the [data-retention cleanup](../configuration.md#data-retention) now (it also runs every hour on each server, even when you never call this). Works even when `retention.enabled` is false, so you can trigger it from your own scheduler instead.
|
|
234
|
+
|
|
235
|
+
**Response `200`:** rows removed per step.
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{
|
|
239
|
+
"success": true,
|
|
240
|
+
"removed": { "endedSessions": 12, "expiredRefreshTokens": 40, "linkTokens": 3, "oneTimeCodes": 25, "signInChallenges": 2, "organizationInvitations": 0, "webhookDeliveries": 130, "auditLog": 0 }
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### POST /auth/admin/signing-keys/rotate
|
|
245
|
+
|
|
246
|
+
No body. New tokens are signed with a new key; tokens signed by the old key keep working until they expire. **Response `200`:** `{ "success": true }`
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## API keys
|
|
251
|
+
|
|
252
|
+
### API key object
|
|
253
|
+
|
|
254
|
+
```json
|
|
255
|
+
{
|
|
256
|
+
"id": "b7c8...",
|
|
257
|
+
"name": "Partner: QuickBooks sync",
|
|
258
|
+
"keyPreview": "ak_3Fx9Lm",
|
|
259
|
+
"scopes": ["orders:read"],
|
|
260
|
+
"organizationId": null,
|
|
261
|
+
"createdByUserId": "5f0c...",
|
|
262
|
+
"createdAt": "2026-10-20T06:30:00.000Z",
|
|
263
|
+
"lastUsedAt": null,
|
|
264
|
+
"expiresAt": "2027-06-30T00:00:00.000Z",
|
|
265
|
+
"revokedAt": null
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### GET /auth/admin/api-keys
|
|
270
|
+
|
|
271
|
+
**Response `200`:** `{ "success": true, "apiKeys": [ ...API key objects ] }` (the key itself is never returned again).
|
|
272
|
+
|
|
273
|
+
### POST /auth/admin/api-keys
|
|
274
|
+
|
|
275
|
+
**Request**
|
|
276
|
+
|
|
277
|
+
```json
|
|
278
|
+
{ "name": "Partner: QuickBooks sync", "scopes": ["orders:read", "invoices:write"], "organizationId": null, "expiresAt": "2027-06-30T00:00:00Z" }
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
| Field | Type | Required | Rules |
|
|
282
|
+
|---|---|---|---|
|
|
283
|
+
| `name` | string | yes | up to 100 characters |
|
|
284
|
+
| `scopes` | string[] | yes | up to 50, like `orders:read` (lowercase) |
|
|
285
|
+
| `organizationId` | uuid | no | ties the key to one organization |
|
|
286
|
+
| `expiresAt` | ISO date string | no | |
|
|
287
|
+
|
|
288
|
+
**Response `201`.** `apiKey` is shown **only here**; store it in the calling server's secret manager:
|
|
289
|
+
|
|
290
|
+
```json
|
|
291
|
+
{
|
|
292
|
+
"success": true,
|
|
293
|
+
"apiKey": "ak_3Fx9LmQ2x4bWZkY2V0ZXN0dG9rZW5leGFtcGxlMTIzNDU",
|
|
294
|
+
"details": { "id": "b7c8...", "name": "Partner: QuickBooks sync", "keyPreview": "ak_3Fx9Lm", "...": "API key object" }
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### DELETE /auth/admin/api-keys/:apiKeyId
|
|
299
|
+
|
|
300
|
+
No body. Revokes immediately. **Response `200`:** `{ "success": true }`. Errors: `404 NOT_FOUND`.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Webhooks
|
|
305
|
+
|
|
306
|
+
### Webhook object
|
|
307
|
+
|
|
308
|
+
```json
|
|
309
|
+
{
|
|
310
|
+
"id": "d4e5...",
|
|
311
|
+
"url": "https://hooks.myapp.com/auth",
|
|
312
|
+
"eventNames": ["user.created", "user.deleted"],
|
|
313
|
+
"isEnabled": true,
|
|
314
|
+
"description": "CRM sync",
|
|
315
|
+
"createdAt": "2026-10-20T06:30:00.000Z"
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### GET /auth/admin/webhooks
|
|
320
|
+
|
|
321
|
+
**Response `200`:** `{ "success": true, "webhooks": [ ...webhook objects ] }`
|
|
322
|
+
|
|
323
|
+
### POST /auth/admin/webhooks
|
|
324
|
+
|
|
325
|
+
**Request**
|
|
326
|
+
|
|
327
|
+
```json
|
|
328
|
+
{ "url": "https://hooks.myapp.com/auth", "eventNames": ["user.created", "user.deleted"], "description": "CRM sync", "isEnabled": true }
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
| Field | Type | Required | Rules |
|
|
332
|
+
|---|---|---|---|
|
|
333
|
+
| `url` | string | yes | public https URL, up to 2048 characters |
|
|
334
|
+
| `eventNames` | string[] | no | [event names](../events.md); empty = all events |
|
|
335
|
+
| `description` | string | no | up to 200 characters |
|
|
336
|
+
| `isEnabled` | boolean | no | default `true` |
|
|
337
|
+
|
|
338
|
+
**Response `201`.** `signingSecret` is shown **only here**:
|
|
339
|
+
|
|
340
|
+
```json
|
|
341
|
+
{ "success": true, "webhook": { "id": "d4e5...", "...": "webhook object" }, "signingSecret": "whsec_c2VjcmV0ZXhhbXBsZTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI" }
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
**Errors**
|
|
345
|
+
|
|
346
|
+
| Status | `code` | When |
|
|
347
|
+
|---|---|---|
|
|
348
|
+
| 400 | `UNSAFE_WEBHOOK_URL` | Not https, has credentials, private/loopback address, or doesn't resolve (`problem` says which) |
|
|
349
|
+
| 400 | `VALIDATION_ERROR` | Unknown event names, or more than 50 webhooks |
|
|
350
|
+
|
|
351
|
+
```json
|
|
352
|
+
{ "success": false, "code": "UNSAFE_WEBHOOK_URL", "message": "Webhook URLs must be public https addresses.", "problem": "URL points to a private network address" }
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### PATCH /auth/admin/webhooks/:webhookId
|
|
356
|
+
|
|
357
|
+
Same fields as create, all optional. **Response `200`:** `{ "success": true, "webhook": { ... } }`
|
|
358
|
+
|
|
359
|
+
### DELETE /auth/admin/webhooks/:webhookId
|
|
360
|
+
|
|
361
|
+
**Response `200`:** `{ "success": true }`
|
|
362
|
+
|
|
363
|
+
### POST /auth/admin/webhooks/:webhookId/rotate-secret
|
|
364
|
+
|
|
365
|
+
No body. The old secret stops working at once. **Response `200`:** `{ "success": true, "signingSecret": "whsec_..." }`
|
|
366
|
+
|
|
367
|
+
### POST /auth/admin/webhooks/:webhookId/test
|
|
368
|
+
|
|
369
|
+
No body. Queues a `webhook.test` delivery. **Response `200`:** `{ "success": true }`
|
|
370
|
+
|
|
371
|
+
### GET /auth/admin/webhooks/:webhookId/deliveries
|
|
372
|
+
|
|
373
|
+
Paged, newest first.
|
|
374
|
+
|
|
375
|
+
**Response `200`**
|
|
376
|
+
|
|
377
|
+
```json
|
|
378
|
+
{
|
|
379
|
+
"success": true,
|
|
380
|
+
"deliveries": [
|
|
381
|
+
{
|
|
382
|
+
"id": "7d0b...",
|
|
383
|
+
"webhookId": "d4e5...",
|
|
384
|
+
"eventName": "user.created",
|
|
385
|
+
"payload": { "name": "user.created", "userId": "5f0c...", "data": { "status": "ACTIVE" }, "occurredAt": "2026-10-20T06:30:00.000Z" },
|
|
386
|
+
"status": "failed",
|
|
387
|
+
"attemptCount": 8,
|
|
388
|
+
"nextAttemptAt": "2026-10-23T06:30:00.000Z",
|
|
389
|
+
"lastResponseStatus": 500,
|
|
390
|
+
"lastError": "HTTP 500",
|
|
391
|
+
"createdAt": "2026-10-20T06:30:00.000Z",
|
|
392
|
+
"deliveredAt": null
|
|
393
|
+
}
|
|
394
|
+
],
|
|
395
|
+
"total": 1,
|
|
396
|
+
"page": 1,
|
|
397
|
+
"pageSize": 50
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
`status` is `pending`, `delivered` or `failed`.
|
|
402
|
+
|
|
403
|
+
### POST /auth/admin/webhooks/:webhookId/deliveries/:deliveryId/retry
|
|
404
|
+
|
|
405
|
+
No body. Sends again right away. **Response `200`:** `{ "success": true }`
|
|
406
|
+
|
|
407
|
+
### What your webhook receives
|
|
408
|
+
|
|
409
|
+
```http
|
|
410
|
+
POST https://hooks.myapp.com/auth
|
|
411
|
+
Content-Type: application/json
|
|
412
|
+
User-Agent: techelusive-nest-auth-webhooks/1.0
|
|
413
|
+
X-Techelusive-Event: user.created
|
|
414
|
+
X-Techelusive-Delivery: 7d0b...
|
|
415
|
+
X-Techelusive-Signature: t=1792600000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
```json
|
|
419
|
+
{ "id": "7d0b...", "name": "user.created", "userId": "5f0c...", "data": { "status": "ACTIVE" }, "occurredAt": "2026-10-20T06:30:00.000Z" }
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Reply with any `2xx` within 10 seconds. To verify the signature, see [Admin, API keys and webhooks](../admin-api-keys-webhooks.md#verifying-the-signature-receiving-side).
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Email + password
|
|
2
|
+
|
|
3
|
+
Turned on by default (`password.enabled`). Every endpoint here returns `403 SIGN_IN_METHOD_DISABLED` when it is off. Shared formats, the sign-in result and the user object are described in [Endpoints](README.md).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## POST /auth/register
|
|
8
|
+
|
|
9
|
+
Creates an account.
|
|
10
|
+
|
|
11
|
+
| | |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Auth | Public |
|
|
14
|
+
| Rate limit | 10 per IP per hour |
|
|
15
|
+
| Settings used | `registration.*`, `activation.*`, `password.*` |
|
|
16
|
+
|
|
17
|
+
**Request**
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"email": "asha@example.com",
|
|
22
|
+
"password": "correct horse battery",
|
|
23
|
+
"firstName": "Asha",
|
|
24
|
+
"lastName": "Rao",
|
|
25
|
+
"phoneNumber": "+919876543210",
|
|
26
|
+
"acceptTerms": true,
|
|
27
|
+
"acceptPrivacyPolicy": true
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| Field | Type | Required | Rules |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `email` | string | yes | email format |
|
|
34
|
+
| `password` | string | yes | password rules from the settings |
|
|
35
|
+
| `firstName` | string | when `registration.requireFirstAndLastName` | up to 100 characters |
|
|
36
|
+
| `lastName` | string | when `registration.requireFirstAndLastName` | up to 100 characters |
|
|
37
|
+
| `phoneNumber` | string | when `registration.requirePhoneNumber` | phone format |
|
|
38
|
+
| `acceptTerms` | boolean | must be `true` when `registration.requireTermsAcceptance` | |
|
|
39
|
+
| `acceptPrivacyPolicy` | boolean | must be `true` when `registration.requirePrivacyPolicyAcceptance` | |
|
|
40
|
+
|
|
41
|
+
**Response `201`, verification needed** (default settings):
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"success": true,
|
|
46
|
+
"status": "verification_required",
|
|
47
|
+
"message": "Your account has been created. Please verify your details to continue.",
|
|
48
|
+
"pendingVerifications": ["email"]
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
A verification email is sent. If the email is **already registered**, the response is exactly the same and no account is created; this protects users' privacy.
|
|
53
|
+
|
|
54
|
+
**Response `201`, no verification needed** (when the settings require none): the [sign-in result](README.md#sign-in-result).
|
|
55
|
+
|
|
56
|
+
**Errors**
|
|
57
|
+
|
|
58
|
+
| Status | `code` | When |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| 400 | `INVALID_EMAIL` | Not an email address |
|
|
61
|
+
| 400 | `INVALID_PHONE` | Phone number not in international form |
|
|
62
|
+
| 400 | `INVALID_PASSWORD` | Breaks a rule. `requirements` lists them, e.g. `["at least 10 characters"]`. Same code, different message, when the password is in a data breach |
|
|
63
|
+
| 400 | `VALIDATION_ERROR` | Names missing: `problems: ["firstName and lastName are required"]` |
|
|
64
|
+
| 400 | `TERMS_NOT_ACCEPTED` / `PRIVACY_POLICY_NOT_ACCEPTED` | Consent missing |
|
|
65
|
+
| 400 | `EMAIL_DOMAIN_NOT_ALLOWED` | `registration.allowedEmailDomains` excludes the domain |
|
|
66
|
+
| 403 | `SIGN_UP_CLOSED` | `registration.enabled` is `false` |
|
|
67
|
+
| 409 | `ACCOUNT_ALREADY_EXISTS` | The phone number belongs to another account |
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"success": false,
|
|
72
|
+
"code": "INVALID_PASSWORD",
|
|
73
|
+
"message": "This password does not meet the password rules.",
|
|
74
|
+
"requirements": ["at least 10 characters", "a number"]
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## POST /auth/login
|
|
81
|
+
|
|
82
|
+
Signs in with email and password.
|
|
83
|
+
|
|
84
|
+
| | |
|
|
85
|
+
|---|---|
|
|
86
|
+
| Auth | Public |
|
|
87
|
+
| Rate limit | 30 per IP and 10 per email per 15 minutes |
|
|
88
|
+
|
|
89
|
+
**Request**
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{ "email": "asha@example.com", "password": "correct horse battery" }
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
| Field | Type | Required |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `email` | string | yes |
|
|
98
|
+
| `password` | string | yes |
|
|
99
|
+
|
|
100
|
+
**Response `200`:** the [sign-in result](README.md#sign-in-result) (`signed_in` or `two_factor_required`).
|
|
101
|
+
|
|
102
|
+
**Errors**
|
|
103
|
+
|
|
104
|
+
| Status | `code` | When |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| 401 | `INVALID_CREDENTIALS` | Wrong email **or** password (deliberately the same) |
|
|
107
|
+
| 403 | `ACCOUNT_NOT_VERIFIED` / `ACCOUNT_DEACTIVATED` / `ACCOUNT_SUSPENDED` | See [sign-in result](README.md#sign-in-result) |
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{ "success": false, "code": "INVALID_CREDENTIALS", "message": "Invalid email or password." }
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## POST /auth/email/send-verification
|
|
116
|
+
|
|
117
|
+
Sends (or re-sends) the verification link. Answers the same whether or not the email has an account.
|
|
118
|
+
|
|
119
|
+
| | |
|
|
120
|
+
|---|---|
|
|
121
|
+
| Auth | Public |
|
|
122
|
+
| Rate limit | 10 per IP and 3 per email per hour |
|
|
123
|
+
|
|
124
|
+
**Request**
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{ "email": "asha@example.com" }
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Response `200`**
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{ "success": true, "message": "If this email needs verifying, a verification link is on its way." }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## POST /auth/email/verify
|
|
139
|
+
|
|
140
|
+
Uses the token from the verification link. If nothing else is pending, the account becomes `ACTIVE`.
|
|
141
|
+
|
|
142
|
+
| | |
|
|
143
|
+
|---|---|
|
|
144
|
+
| Auth | Public |
|
|
145
|
+
|
|
146
|
+
**Request**
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{ "token": "ev_Q2x4bWZkY2V0ZXN0dG9rZW5leGFtcGxlMTIzNDU2Nzg5MDE" }
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Response `200`**
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"success": true,
|
|
157
|
+
"message": "Your email has been verified.",
|
|
158
|
+
"status": "ACTIVE",
|
|
159
|
+
"pendingVerifications": []
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
If the settings also require a verified phone, `status` stays `PENDING_VERIFICATION` and `pendingVerifications` is `["phone"]`.
|
|
164
|
+
|
|
165
|
+
**Errors**
|
|
166
|
+
|
|
167
|
+
| Status | `code` | When |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| 400 | `INVALID_TOKEN` | Unknown, used, expired (`emailVerification.linkExpiresInHours`, 24 by default), or the account's email has changed since |
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## POST /auth/password/forgot
|
|
174
|
+
|
|
175
|
+
Emails a password reset link. Answers the same whether or not the email has an account.
|
|
176
|
+
|
|
177
|
+
| | |
|
|
178
|
+
|---|---|
|
|
179
|
+
| Auth | Public |
|
|
180
|
+
| Rate limit | 10 per IP and 3 per email per hour |
|
|
181
|
+
|
|
182
|
+
**Request**
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{ "email": "asha@example.com" }
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Response `200`**
|
|
189
|
+
|
|
190
|
+
```json
|
|
191
|
+
{ "success": true, "message": "If an account exists for this email, a password reset link is on its way." }
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## POST /auth/password/reset
|
|
197
|
+
|
|
198
|
+
Sets a new password using the token from the reset link (valid `passwordReset.linkExpiresInMinutes`, 60 by default). Signs the user out on every device and marks the email verified.
|
|
199
|
+
|
|
200
|
+
| | |
|
|
201
|
+
|---|---|
|
|
202
|
+
| Auth | Public |
|
|
203
|
+
|
|
204
|
+
**Request**
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{ "token": "pr_Q2x4bWZkY2V0ZXN0dG9rZW5leGFtcGxlMTIzNDU2Nzg5MDE", "newPassword": "a brand new passphrase" }
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
| Field | Type | Required | Rules |
|
|
211
|
+
|---|---|---|---|
|
|
212
|
+
| `token` | string | yes | token from the link |
|
|
213
|
+
| `newPassword` | string | yes | password rules |
|
|
214
|
+
|
|
215
|
+
**Response `200`**
|
|
216
|
+
|
|
217
|
+
```json
|
|
218
|
+
{ "success": true, "message": "Your password has been reset. Please sign in with your new password." }
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Errors**
|
|
222
|
+
|
|
223
|
+
| Status | `code` | When |
|
|
224
|
+
|---|---|---|
|
|
225
|
+
| 400 | `INVALID_PASSWORD` | Breaks a rule (`requirements`) |
|
|
226
|
+
| 400 | `INVALID_TOKEN` | Link unknown, used or expired |
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## POST /auth/password/change
|
|
231
|
+
|
|
232
|
+
Changes the password of the signed-in user. Other devices are signed out; this one stays signed in. Users without a password (signed up with Google etc.) leave out `currentPassword` to set one.
|
|
233
|
+
|
|
234
|
+
| | |
|
|
235
|
+
|---|---|
|
|
236
|
+
| Auth | User (`Authorization: Bearer ...`) |
|
|
237
|
+
| Rate limit | 5 per user per 15 minutes |
|
|
238
|
+
|
|
239
|
+
**Request**
|
|
240
|
+
|
|
241
|
+
```json
|
|
242
|
+
{ "currentPassword": "correct horse battery", "newPassword": "a brand new passphrase" }
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
| Field | Type | Required |
|
|
246
|
+
|---|---|---|
|
|
247
|
+
| `currentPassword` | string | yes, if the account has a password |
|
|
248
|
+
| `newPassword` | string | yes |
|
|
249
|
+
|
|
250
|
+
**Response `200`**
|
|
251
|
+
|
|
252
|
+
```json
|
|
253
|
+
{ "success": true, "message": "Your password has been changed. Other devices have been signed out." }
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Errors**
|
|
257
|
+
|
|
258
|
+
| Status | `code` | When |
|
|
259
|
+
|---|---|---|
|
|
260
|
+
| 401 | `INVALID_CREDENTIALS` | `currentPassword` is wrong |
|
|
261
|
+
| 400 | `INVALID_PASSWORD` | Breaks a rule, or `requirements: ["different from your current password"]` |
|