@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.
Files changed (340) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +21 -0
  3. package/README.md +204 -2
  4. package/api/openapi.json +4399 -0
  5. package/api/techelusive-authentication.postman_collection.json +3178 -0
  6. package/dist/auth-options.d.ts +156 -0
  7. package/dist/auth-options.js +3 -0
  8. package/dist/auth-options.js.map +1 -0
  9. package/dist/auth-options.validation.d.ts +9 -0
  10. package/dist/auth-options.validation.js +74 -0
  11. package/dist/auth-options.validation.js.map +1 -0
  12. package/dist/auth.module.d.ts +38 -0
  13. package/dist/auth.module.js +173 -0
  14. package/dist/auth.module.js.map +1 -0
  15. package/dist/common/auth-error.d.ts +16 -0
  16. package/dist/common/auth-error.js +23 -0
  17. package/dist/common/auth-error.js.map +1 -0
  18. package/dist/common/auth-exception.filter.d.ts +24 -0
  19. package/dist/common/auth-exception.filter.js +66 -0
  20. package/dist/common/auth-exception.filter.js.map +1 -0
  21. package/dist/common/crypto/jwt.d.ts +89 -0
  22. package/dist/common/crypto/jwt.js +144 -0
  23. package/dist/common/crypto/jwt.js.map +1 -0
  24. package/dist/common/crypto/random-secrets.d.ts +78 -0
  25. package/dist/common/crypto/random-secrets.js +113 -0
  26. package/dist/common/crypto/random-secrets.js.map +1 -0
  27. package/dist/common/crypto/remote-public-keys.d.ts +49 -0
  28. package/dist/common/crypto/remote-public-keys.js +105 -0
  29. package/dist/common/crypto/remote-public-keys.js.map +1 -0
  30. package/dist/common/crypto/totp.d.ts +68 -0
  31. package/dist/common/crypto/totp.js +148 -0
  32. package/dist/common/crypto/totp.js.map +1 -0
  33. package/dist/common/encryption.service.d.ts +36 -0
  34. package/dist/common/encryption.service.js +111 -0
  35. package/dist/common/encryption.service.js.map +1 -0
  36. package/dist/common/identifiers.d.ts +48 -0
  37. package/dist/common/identifiers.js +89 -0
  38. package/dist/common/identifiers.js.map +1 -0
  39. package/dist/common/network-safety.d.ts +19 -0
  40. package/dist/common/network-safety.js +72 -0
  41. package/dist/common/network-safety.js.map +1 -0
  42. package/dist/common/rate-limiter.service.d.ts +63 -0
  43. package/dist/common/rate-limiter.service.js +158 -0
  44. package/dist/common/rate-limiter.service.js.map +1 -0
  45. package/dist/common/refresh-token-cookie.d.ts +78 -0
  46. package/dist/common/refresh-token-cookie.js +185 -0
  47. package/dist/common/refresh-token-cookie.js.map +1 -0
  48. package/dist/common/request-context.d.ts +14 -0
  49. package/dist/common/request-context.js +22 -0
  50. package/dist/common/request-context.js.map +1 -0
  51. package/dist/common/strict-validation.pipe.d.ts +8 -0
  52. package/dist/common/strict-validation.pipe.js +16 -0
  53. package/dist/common/strict-validation.pipe.js.map +1 -0
  54. package/dist/common/time.d.ts +15 -0
  55. package/dist/common/time.js +34 -0
  56. package/dist/common/time.js.map +1 -0
  57. package/dist/constants.d.ts +1326 -0
  58. package/dist/constants.js +1142 -0
  59. package/dist/constants.js.map +1 -0
  60. package/dist/database/create-auth-tables.migration.d.ts +26 -0
  61. package/dist/database/create-auth-tables.migration.js +291 -0
  62. package/dist/database/create-auth-tables.migration.js.map +1 -0
  63. package/dist/database/email-change-and-retention.migration.d.ts +25 -0
  64. package/dist/database/email-change-and-retention.migration.js +54 -0
  65. package/dist/database/email-change-and-retention.migration.js.map +1 -0
  66. package/dist/database/entities/api-key.entity.d.ts +17 -0
  67. package/dist/database/entities/api-key.entity.js +80 -0
  68. package/dist/database/entities/api-key.entity.js.map +1 -0
  69. package/dist/database/entities/audit-log.entity.d.ts +13 -0
  70. package/dist/database/entities/audit-log.entity.js +64 -0
  71. package/dist/database/entities/audit-log.entity.js.map +1 -0
  72. package/dist/database/entities/backup-code.entity.d.ts +9 -0
  73. package/dist/database/entities/backup-code.entity.js +52 -0
  74. package/dist/database/entities/backup-code.entity.js.map +1 -0
  75. package/dist/database/entities/index.d.ts +43 -0
  76. package/dist/database/entities/index.js +82 -0
  77. package/dist/database/entities/index.js.map +1 -0
  78. package/dist/database/entities/json-object.d.ts +12 -0
  79. package/dist/database/entities/json-object.js +3 -0
  80. package/dist/database/entities/json-object.js.map +1 -0
  81. package/dist/database/entities/link-token.entity.d.ts +15 -0
  82. package/dist/database/entities/link-token.entity.js +64 -0
  83. package/dist/database/entities/link-token.entity.js.map +1 -0
  84. package/dist/database/entities/one-time-code.entity.d.ts +16 -0
  85. package/dist/database/entities/one-time-code.entity.js +69 -0
  86. package/dist/database/entities/one-time-code.entity.js.map +1 -0
  87. package/dist/database/entities/organization-invitation.entity.d.ts +14 -0
  88. package/dist/database/entities/organization-invitation.entity.js +73 -0
  89. package/dist/database/entities/organization-invitation.entity.js.map +1 -0
  90. package/dist/database/entities/organization-member.entity.d.ts +9 -0
  91. package/dist/database/entities/organization-member.entity.js +48 -0
  92. package/dist/database/entities/organization-member.entity.js.map +1 -0
  93. package/dist/database/entities/organization.entity.d.ts +12 -0
  94. package/dist/database/entities/organization.entity.js +58 -0
  95. package/dist/database/entities/organization.entity.js.map +1 -0
  96. package/dist/database/entities/passkey.entity.d.ts +19 -0
  97. package/dist/database/entities/passkey.entity.js +78 -0
  98. package/dist/database/entities/passkey.entity.js.map +1 -0
  99. package/dist/database/entities/password.entity.d.ts +6 -0
  100. package/dist/database/entities/password.entity.js +36 -0
  101. package/dist/database/entities/password.entity.js.map +1 -0
  102. package/dist/database/entities/refresh-token.entity.d.ts +9 -0
  103. package/dist/database/entities/refresh-token.entity.js +53 -0
  104. package/dist/database/entities/refresh-token.entity.js.map +1 -0
  105. package/dist/database/entities/session.entity.d.ts +20 -0
  106. package/dist/database/entities/session.entity.js +87 -0
  107. package/dist/database/entities/session.entity.js.map +1 -0
  108. package/dist/database/entities/settings.entity.d.ts +7 -0
  109. package/dist/database/entities/settings.entity.js +41 -0
  110. package/dist/database/entities/settings.entity.js.map +1 -0
  111. package/dist/database/entities/sign-in-challenge.entity.d.ts +23 -0
  112. package/dist/database/entities/sign-in-challenge.entity.js +80 -0
  113. package/dist/database/entities/sign-in-challenge.entity.js.map +1 -0
  114. package/dist/database/entities/signing-key.entity.d.ts +11 -0
  115. package/dist/database/entities/signing-key.entity.js +54 -0
  116. package/dist/database/entities/signing-key.entity.js.map +1 -0
  117. package/dist/database/entities/social-account.entity.d.ts +13 -0
  118. package/dist/database/entities/social-account.entity.js +54 -0
  119. package/dist/database/entities/social-account.entity.js.map +1 -0
  120. package/dist/database/entities/two-factor-secret.entity.d.ts +10 -0
  121. package/dist/database/entities/two-factor-secret.entity.js +48 -0
  122. package/dist/database/entities/two-factor-secret.entity.js.map +1 -0
  123. package/dist/database/entities/user.entity.d.ts +34 -0
  124. package/dist/database/entities/user.entity.js +129 -0
  125. package/dist/database/entities/user.entity.js.map +1 -0
  126. package/dist/database/entities/webhook-delivery.entity.d.ts +17 -0
  127. package/dist/database/entities/webhook-delivery.entity.js +79 -0
  128. package/dist/database/entities/webhook-delivery.entity.js.map +1 -0
  129. package/dist/database/entities/webhook.entity.d.ts +12 -0
  130. package/dist/database/entities/webhook.entity.js +58 -0
  131. package/dist/database/entities/webhook.entity.js.map +1 -0
  132. package/dist/database/typeorm-row.d.ts +21 -0
  133. package/dist/database/typeorm-row.js +29 -0
  134. package/dist/database/typeorm-row.js.map +1 -0
  135. package/dist/features/account/account.controller.d.ts +259 -0
  136. package/dist/features/account/account.controller.js +372 -0
  137. package/dist/features/account/account.controller.js.map +1 -0
  138. package/dist/features/account/account.dto.d.ts +16 -0
  139. package/dist/features/account/account.dto.js +61 -0
  140. package/dist/features/account/account.dto.js.map +1 -0
  141. package/dist/features/account/data-export.service.d.ts +85 -0
  142. package/dist/features/account/data-export.service.js +125 -0
  143. package/dist/features/account/data-export.service.js.map +1 -0
  144. package/dist/features/account/health.service.d.ts +30 -0
  145. package/dist/features/account/health.service.js +59 -0
  146. package/dist/features/account/health.service.js.map +1 -0
  147. package/dist/features/admin/admin.controller.d.ts +382 -0
  148. package/dist/features/admin/admin.controller.js +623 -0
  149. package/dist/features/admin/admin.controller.js.map +1 -0
  150. package/dist/features/admin/admin.dto.d.ts +61 -0
  151. package/dist/features/admin/admin.dto.js +253 -0
  152. package/dist/features/admin/admin.dto.js.map +1 -0
  153. package/dist/features/admin/admin.service.d.ts +142 -0
  154. package/dist/features/admin/admin.service.js +227 -0
  155. package/dist/features/admin/admin.service.js.map +1 -0
  156. package/dist/features/api-keys/api-keys.service.d.ts +67 -0
  157. package/dist/features/api-keys/api-keys.service.js +144 -0
  158. package/dist/features/api-keys/api-keys.service.js.map +1 -0
  159. package/dist/features/email-change/email-change.controller.d.ts +38 -0
  160. package/dist/features/email-change/email-change.controller.js +85 -0
  161. package/dist/features/email-change/email-change.controller.js.map +1 -0
  162. package/dist/features/email-change/email-change.dto.d.ts +10 -0
  163. package/dist/features/email-change/email-change.dto.js +43 -0
  164. package/dist/features/email-change/email-change.dto.js.map +1 -0
  165. package/dist/features/email-change/email-change.service.d.ts +74 -0
  166. package/dist/features/email-change/email-change.service.js +179 -0
  167. package/dist/features/email-change/email-change.service.js.map +1 -0
  168. package/dist/features/email-links/email-verification.service.d.ts +46 -0
  169. package/dist/features/email-links/email-verification.service.js +94 -0
  170. package/dist/features/email-links/email-verification.service.js.map +1 -0
  171. package/dist/features/email-links/link-tokens.service.d.ts +44 -0
  172. package/dist/features/email-links/link-tokens.service.js +122 -0
  173. package/dist/features/email-links/link-tokens.service.js.map +1 -0
  174. package/dist/features/events/auth-events.service.d.ts +52 -0
  175. package/dist/features/events/auth-events.service.js +117 -0
  176. package/dist/features/events/auth-events.service.js.map +1 -0
  177. package/dist/features/maintenance/data-retention.service.d.ts +60 -0
  178. package/dist/features/maintenance/data-retention.service.js +182 -0
  179. package/dist/features/maintenance/data-retention.service.js.map +1 -0
  180. package/dist/features/notifications/notifications.service.d.ts +40 -0
  181. package/dist/features/notifications/notifications.service.js +94 -0
  182. package/dist/features/notifications/notifications.service.js.map +1 -0
  183. package/dist/features/one-time-codes/one-time-codes.service.d.ts +40 -0
  184. package/dist/features/one-time-codes/one-time-codes.service.js +102 -0
  185. package/dist/features/one-time-codes/one-time-codes.service.js.map +1 -0
  186. package/dist/features/organizations/organizations.controller.d.ts +220 -0
  187. package/dist/features/organizations/organizations.controller.js +337 -0
  188. package/dist/features/organizations/organizations.controller.js.map +1 -0
  189. package/dist/features/organizations/organizations.dto.d.ts +31 -0
  190. package/dist/features/organizations/organizations.dto.js +100 -0
  191. package/dist/features/organizations/organizations.dto.js.map +1 -0
  192. package/dist/features/organizations/organizations.service.d.ts +274 -0
  193. package/dist/features/organizations/organizations.service.js +481 -0
  194. package/dist/features/organizations/organizations.service.js.map +1 -0
  195. package/dist/features/passkeys/passkeys.controller.d.ts +92 -0
  196. package/dist/features/passkeys/passkeys.controller.js +183 -0
  197. package/dist/features/passkeys/passkeys.controller.js.map +1 -0
  198. package/dist/features/passkeys/passkeys.dto.d.ts +13 -0
  199. package/dist/features/passkeys/passkeys.dto.js +50 -0
  200. package/dist/features/passkeys/passkeys.dto.js.map +1 -0
  201. package/dist/features/passkeys/passkeys.service.d.ts +159 -0
  202. package/dist/features/passkeys/passkeys.service.js +350 -0
  203. package/dist/features/passkeys/passkeys.service.js.map +1 -0
  204. package/dist/features/passwordless/passwordless-auth.service.d.ts +152 -0
  205. package/dist/features/passwordless/passwordless-auth.service.js +304 -0
  206. package/dist/features/passwordless/passwordless-auth.service.js.map +1 -0
  207. package/dist/features/passwordless/passwordless.controller.d.ts +75 -0
  208. package/dist/features/passwordless/passwordless.controller.js +163 -0
  209. package/dist/features/passwordless/passwordless.controller.js.map +1 -0
  210. package/dist/features/passwordless/passwordless.dto.d.ts +29 -0
  211. package/dist/features/passwordless/passwordless.dto.js +101 -0
  212. package/dist/features/passwordless/passwordless.dto.js.map +1 -0
  213. package/dist/features/passwords/password-auth.service.d.ts +154 -0
  214. package/dist/features/passwords/password-auth.service.js +317 -0
  215. package/dist/features/passwords/password-auth.service.js.map +1 -0
  216. package/dist/features/passwords/password-policy.service.d.ts +63 -0
  217. package/dist/features/passwords/password-policy.service.js +175 -0
  218. package/dist/features/passwords/password-policy.service.js.map +1 -0
  219. package/dist/features/passwords/password.controller.d.ts +95 -0
  220. package/dist/features/passwords/password.controller.js +193 -0
  221. package/dist/features/passwords/password.controller.js.map +1 -0
  222. package/dist/features/passwords/password.dto.d.ts +36 -0
  223. package/dist/features/passwords/password.dto.js +140 -0
  224. package/dist/features/passwords/password.dto.js.map +1 -0
  225. package/dist/features/sessions/session.service.d.ts +132 -0
  226. package/dist/features/sessions/session.service.js +308 -0
  227. package/dist/features/sessions/session.service.js.map +1 -0
  228. package/dist/features/sessions/session.types.d.ts +34 -0
  229. package/dist/features/sessions/session.types.js +3 -0
  230. package/dist/features/sessions/session.types.js.map +1 -0
  231. package/dist/features/settings/settings.defaults.d.ts +2 -0
  232. package/dist/features/settings/settings.defaults.js +7 -0
  233. package/dist/features/settings/settings.defaults.js.map +1 -0
  234. package/dist/features/settings/settings.service.d.ts +44 -0
  235. package/dist/features/settings/settings.service.js +112 -0
  236. package/dist/features/settings/settings.service.js.map +1 -0
  237. package/dist/features/settings/settings.types.d.ts +133 -0
  238. package/dist/features/settings/settings.types.js +3 -0
  239. package/dist/features/settings/settings.types.js.map +1 -0
  240. package/dist/features/settings/settings.validation.d.ts +33 -0
  241. package/dist/features/settings/settings.validation.js +614 -0
  242. package/dist/features/settings/settings.validation.js.map +1 -0
  243. package/dist/features/sign-in/sign-in-challenges.service.d.ts +54 -0
  244. package/dist/features/sign-in/sign-in-challenges.service.js +104 -0
  245. package/dist/features/sign-in/sign-in-challenges.service.js.map +1 -0
  246. package/dist/features/sign-in/sign-in.service.d.ts +127 -0
  247. package/dist/features/sign-in/sign-in.service.js +248 -0
  248. package/dist/features/sign-in/sign-in.service.js.map +1 -0
  249. package/dist/features/sign-in/sign-in.types.d.ts +22 -0
  250. package/dist/features/sign-in/sign-in.types.js +3 -0
  251. package/dist/features/sign-in/sign-in.types.js.map +1 -0
  252. package/dist/features/signing-keys/jwks.controller.d.ts +17 -0
  253. package/dist/features/signing-keys/jwks.controller.js +51 -0
  254. package/dist/features/signing-keys/jwks.controller.js.map +1 -0
  255. package/dist/features/signing-keys/signing-keys.service.d.ts +67 -0
  256. package/dist/features/signing-keys/signing-keys.service.js +142 -0
  257. package/dist/features/signing-keys/signing-keys.service.js.map +1 -0
  258. package/dist/features/social/social-auth.service.d.ts +100 -0
  259. package/dist/features/social/social-auth.service.js +232 -0
  260. package/dist/features/social/social-auth.service.js.map +1 -0
  261. package/dist/features/social/social-providers.service.d.ts +97 -0
  262. package/dist/features/social/social-providers.service.js +214 -0
  263. package/dist/features/social/social-providers.service.js.map +1 -0
  264. package/dist/features/social/social.controller.d.ts +54 -0
  265. package/dist/features/social/social.controller.js +124 -0
  266. package/dist/features/social/social.controller.js.map +1 -0
  267. package/dist/features/social/social.dto.d.ts +11 -0
  268. package/dist/features/social/social.dto.js +38 -0
  269. package/dist/features/social/social.dto.js.map +1 -0
  270. package/dist/features/two-factor/two-factor.controller.d.ts +84 -0
  271. package/dist/features/two-factor/two-factor.controller.js +174 -0
  272. package/dist/features/two-factor/two-factor.controller.js.map +1 -0
  273. package/dist/features/two-factor/two-factor.dto.d.ts +10 -0
  274. package/dist/features/two-factor/two-factor.dto.js +37 -0
  275. package/dist/features/two-factor/two-factor.dto.js.map +1 -0
  276. package/dist/features/two-factor/two-factor.service.d.ts +171 -0
  277. package/dist/features/two-factor/two-factor.service.js +348 -0
  278. package/dist/features/two-factor/two-factor.service.js.map +1 -0
  279. package/dist/features/users/sign-in-methods.service.d.ts +40 -0
  280. package/dist/features/users/sign-in-methods.service.js +81 -0
  281. package/dist/features/users/sign-in-methods.service.js.map +1 -0
  282. package/dist/features/users/sign-up-rules.d.ts +12 -0
  283. package/dist/features/users/sign-up-rules.js +29 -0
  284. package/dist/features/users/sign-up-rules.js.map +1 -0
  285. package/dist/features/users/users.service.d.ts +246 -0
  286. package/dist/features/users/users.service.js +509 -0
  287. package/dist/features/users/users.service.js.map +1 -0
  288. package/dist/features/users/users.types.d.ts +24 -0
  289. package/dist/features/users/users.types.js +3 -0
  290. package/dist/features/users/users.types.js.map +1 -0
  291. package/dist/features/webhooks/webhook-delivery.worker.d.ts +55 -0
  292. package/dist/features/webhooks/webhook-delivery.worker.js +175 -0
  293. package/dist/features/webhooks/webhook-delivery.worker.js.map +1 -0
  294. package/dist/features/webhooks/webhook-signature.d.ts +28 -0
  295. package/dist/features/webhooks/webhook-signature.js +85 -0
  296. package/dist/features/webhooks/webhook-signature.js.map +1 -0
  297. package/dist/features/webhooks/webhooks.service.d.ts +144 -0
  298. package/dist/features/webhooks/webhooks.service.js +238 -0
  299. package/dist/features/webhooks/webhooks.service.js.map +1 -0
  300. package/dist/guards/auth.decorators.d.ts +65 -0
  301. package/dist/guards/auth.decorators.js +68 -0
  302. package/dist/guards/auth.decorators.js.map +1 -0
  303. package/dist/guards/auth.guard.d.ts +47 -0
  304. package/dist/guards/auth.guard.js +132 -0
  305. package/dist/guards/auth.guard.js.map +1 -0
  306. package/dist/index.d.ts +38 -0
  307. package/dist/index.js +95 -0
  308. package/dist/index.js.map +1 -0
  309. package/dist/integrations/console-email-sender.d.ts +15 -0
  310. package/dist/integrations/console-email-sender.js +26 -0
  311. package/dist/integrations/console-email-sender.js.map +1 -0
  312. package/dist/integrations/msg91-sms-sender.d.ts +28 -0
  313. package/dist/integrations/msg91-sms-sender.js +46 -0
  314. package/dist/integrations/msg91-sms-sender.js.map +1 -0
  315. package/docs/README.md +39 -0
  316. package/docs/admin-api-keys-webhooks.md +147 -0
  317. package/docs/api-reference.md +175 -0
  318. package/docs/architecture.md +119 -0
  319. package/docs/client-integration.md +192 -0
  320. package/docs/code-walkthrough.md +273 -0
  321. package/docs/configuration.md +229 -0
  322. package/docs/endpoints/README.md +151 -0
  323. package/docs/endpoints/account.md +363 -0
  324. package/docs/endpoints/admin.md +422 -0
  325. package/docs/endpoints/email-password.md +261 -0
  326. package/docs/endpoints/organizations.md +192 -0
  327. package/docs/endpoints/passkeys.md +195 -0
  328. package/docs/endpoints/passwordless.md +214 -0
  329. package/docs/endpoints/social.md +116 -0
  330. package/docs/endpoints/two-factor.md +146 -0
  331. package/docs/error-codes.md +100 -0
  332. package/docs/events.md +83 -0
  333. package/docs/getting-started.md +139 -0
  334. package/docs/manual-testing.md +215 -0
  335. package/docs/organizations.md +86 -0
  336. package/docs/production-checklist.md +60 -0
  337. package/docs/protecting-routes.md +147 -0
  338. package/docs/security.md +61 -0
  339. package/docs/sign-in-flows.md +294 -0
  340. package/package.json +92 -4
@@ -0,0 +1,116 @@
1
+ # Social sign-in: Google, Apple, Facebook
2
+
3
+ The app signs the user in with the provider's own SDK, then sends the provider's token here. `:provider` is `google`, `apple` or `facebook`; any other value returns `404 NOT_FOUND`. Which token to send is explained in [Sign-in flows](../sign-in-flows.md#google-apple-and-facebook). Shared formats, the sign-in result and the user object are described in [Endpoints](README.md).
4
+
5
+ ---
6
+
7
+ ## POST /auth/social/:provider
8
+
9
+ Signs in, or signs up if the email is new.
10
+
11
+ | | |
12
+ |---|---|
13
+ | Auth | Public |
14
+ | Rate limit | 30 per IP per 15 minutes |
15
+ | Settings used | `google` / `apple` / `facebook` (enabled + client ids), `registration.*` |
16
+
17
+ **Request**
18
+
19
+ ```http
20
+ POST /auth/social/google
21
+ ```
22
+
23
+ ```json
24
+ {
25
+ "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20i...",
26
+ "nonce": "b1f3c0d2e4a5",
27
+ "firstName": "Asha",
28
+ "lastName": "Rao",
29
+ "acceptTerms": true,
30
+ "acceptPrivacyPolicy": true
31
+ }
32
+ ```
33
+
34
+ | Field | Type | Required | Notes |
35
+ |---|---|---|---|
36
+ | `token` | string | yes | Google/Apple: ID token. Facebook: access token. Up to 8192 characters |
37
+ | `nonce` | string | no | The **raw** nonce your app used with the provider; required if the token contains one. Up to 256 characters |
38
+ | `firstName`, `lastName`, `acceptTerms`, `acceptPrivacyPolicy` | | only for new accounts | Apple sends the name only once, to your app, so pass it here |
39
+
40
+ **Response `200`:** the [sign-in result](README.md#sign-in-result).
41
+
42
+ **Errors**
43
+
44
+ | Status | `code` | When |
45
+ |---|---|---|
46
+ | 401 | `INVALID_SOCIAL_TOKEN` | Bad signature, expired, issued to another app, wrong nonce, or Facebook rejected it |
47
+ | 409 | `ACCOUNT_EXISTS_WITH_OTHER_METHOD` | The provider didn't verify the email (always the case for Facebook) and an account already has it. Sign in normally, then link |
48
+ | 400 | `VALIDATION_ERROR` | New account: `missingSignUpDetails`, which includes `"email"` if Facebook gave no email |
49
+ | 400 | `EMAIL_DOMAIN_NOT_ALLOWED` | |
50
+ | 403 | `SIGN_IN_METHOD_DISABLED` | Provider turned off |
51
+ | 403 | `SIGN_UP_CLOSED` | |
52
+ | 501 | `NOT_CONFIGURED` | No client ids (Google/Apple) or app secret (Facebook) on the server |
53
+
54
+ ```json
55
+ {
56
+ "success": false,
57
+ "code": "ACCOUNT_EXISTS_WITH_OTHER_METHOD",
58
+ "message": "An account with this email already exists. Sign in your usual way, then link this account from your profile."
59
+ }
60
+ ```
61
+
62
+ ---
63
+
64
+ ## POST /auth/social/:provider/link
65
+
66
+ Connects a provider account to the signed-in user, e.g. from a "Connected accounts" screen.
67
+
68
+ | | |
69
+ |---|---|
70
+ | Auth | User, session checked live |
71
+
72
+ **Request**
73
+
74
+ ```json
75
+ { "token": "eyJhbGciOiJSUzI1NiIs...", "nonce": "b1f3c0d2e4a5" }
76
+ ```
77
+
78
+ **Response `200`**
79
+
80
+ ```json
81
+ { "success": true }
82
+ ```
83
+
84
+ Linking an account that is already linked to **this** user also returns success.
85
+
86
+ **Errors**
87
+
88
+ | Status | `code` | When |
89
+ |---|---|---|
90
+ | 409 | `SOCIAL_ACCOUNT_IN_USE` | Linked to another user |
91
+ | 401 | `INVALID_SOCIAL_TOKEN` | |
92
+
93
+ ---
94
+
95
+ ## DELETE /auth/social/:provider
96
+
97
+ Disconnects a provider.
98
+
99
+ | | |
100
+ |---|---|
101
+ | Auth | User, session checked live |
102
+
103
+ **Request:** no body.
104
+
105
+ **Response `200`**
106
+
107
+ ```json
108
+ { "success": true }
109
+ ```
110
+
111
+ **Errors**
112
+
113
+ | Status | `code` | When |
114
+ |---|---|---|
115
+ | 404 | `NOT_FOUND` | That provider isn't linked |
116
+ | 409 | `LAST_SIGN_IN_METHOD` | It's the user's only way to sign in |
@@ -0,0 +1,146 @@
1
+ # Two-factor authentication
2
+
3
+ Authenticator-app codes (TOTP) plus 10 single-use backup codes. Needs `twoFactor.enabled` (on by default); otherwise `403 FEATURE_DISABLED`. All code-checking endpoints share a limit of 10 attempts per user per 15 minutes. Shared formats, the sign-in result and the user object are described in [Endpoints](README.md).
4
+
5
+ ---
6
+
7
+ ## GET /auth/2fa
8
+
9
+ | | |
10
+ |---|---|
11
+ | Auth | User |
12
+
13
+ **Response `200`**
14
+
15
+ ```json
16
+ { "success": true, "isEnabled": true, "remainingBackupCodes": 8 }
17
+ ```
18
+
19
+ ---
20
+
21
+ ## POST /auth/2fa/setup
22
+
23
+ Step 1: creates a secret. Nothing changes for the user until step 2.
24
+
25
+ | | |
26
+ |---|---|
27
+ | Auth | User, session checked live |
28
+
29
+ **Request:** no body.
30
+
31
+ **Response `200`**
32
+
33
+ ```json
34
+ {
35
+ "success": true,
36
+ "secret": "JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP",
37
+ "authenticatorAppUrl": "otpauth://totp/MyApp%3Aasha%40example.com?secret=JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP&issuer=MyApp&algorithm=SHA1&digits=6&period=30"
38
+ }
39
+ ```
40
+
41
+ Show `authenticatorAppUrl` as a QR code, with `secret` underneath for typing by hand.
42
+
43
+ **Errors:** `409 TWO_FACTOR_ALREADY_ENABLED`.
44
+
45
+ ---
46
+
47
+ ## POST /auth/2fa/enable
48
+
49
+ Step 2: confirms with the first code from the app. Turns 2FA on, signs out other devices, and returns backup codes. **Show the backup codes once** and ask the user to save them.
50
+
51
+ | | |
52
+ |---|---|
53
+ | Auth | User, session checked live |
54
+
55
+ **Request**
56
+
57
+ ```json
58
+ { "code": "123456" }
59
+ ```
60
+
61
+ **Response `200`**
62
+
63
+ ```json
64
+ {
65
+ "success": true,
66
+ "backupCodes": ["k7m2-x9p4", "h3nq-8v2w", "p5tz-r6c9", "b2wx-m7k3", "s9qf-4h8n", "z3vc-t5p2", "m8kr-q2x6", "w4nh-c9t7", "f6pb-y3m5", "r2xs-k8w4"]
67
+ }
68
+ ```
69
+
70
+ **Errors**
71
+
72
+ | Status | `code` | When |
73
+ |---|---|---|
74
+ | 401 | `INVALID_OTP` | Wrong code |
75
+ | 409 | `TWO_FACTOR_SETUP_NOT_STARTED` | Call `/auth/2fa/setup` first |
76
+ | 409 | `TWO_FACTOR_ALREADY_ENABLED` | |
77
+
78
+ ---
79
+
80
+ ## POST /auth/2fa/verify
81
+
82
+ The second step of sign-in, after a sign-in returned `two_factor_required`. Accepts an authenticator code **or** a backup code (each backup code works once).
83
+
84
+ | | |
85
+ |---|---|
86
+ | Auth | Public |
87
+
88
+ **Request**
89
+
90
+ ```json
91
+ { "challengeToken": "ch_Zm9vYmFyZXhhbXBsZWNoYWxsZW5nZXRva2VuMTIzNDU2Nzg", "code": "123456" }
92
+ ```
93
+
94
+ | Field | Type | Required | Notes |
95
+ |---|---|---|---|
96
+ | `challengeToken` | string | yes | from the sign-in response; valid 5 minutes |
97
+ | `code` | string | yes | `"123456"` or a backup code such as `"k7m2-x9p4"` (dash, spaces and capitals are ignored) |
98
+
99
+ **Response `200`:** the [sign-in result](README.md#sign-in-result) with `status: "signed_in"`.
100
+
101
+ **Errors**
102
+
103
+ | Status | `code` | When |
104
+ |---|---|---|
105
+ | 401 | `INVALID_OTP` | Wrong code (the challenge allows 5 wrong tries) |
106
+ | 400 | `INVALID_TOKEN` | Challenge unknown, used, expired, or too many wrong tries: sign in again |
107
+
108
+ ---
109
+
110
+ ## POST /auth/2fa/disable
111
+
112
+ Turns 2FA off. Needs a current authenticator code or a backup code.
113
+
114
+ | | |
115
+ |---|---|
116
+ | Auth | User, session checked live |
117
+
118
+ **Request**
119
+
120
+ ```json
121
+ { "code": "123456" }
122
+ ```
123
+
124
+ **Response `200`:** `{ "success": true }`
125
+
126
+ **Errors:** `401 INVALID_OTP`, `409 TWO_FACTOR_NOT_ENABLED`.
127
+
128
+ ---
129
+
130
+ ## POST /auth/2fa/backup-codes
131
+
132
+ Replaces all backup codes with 10 new ones. Needs a current code.
133
+
134
+ | | |
135
+ |---|---|
136
+ | Auth | User, session checked live |
137
+
138
+ **Request**
139
+
140
+ ```json
141
+ { "code": "123456" }
142
+ ```
143
+
144
+ **Response `200`:** `{ "success": true, "backupCodes": ["...10 codes..."] }`
145
+
146
+ **Errors:** `401 INVALID_OTP`, `409 TWO_FACTOR_NOT_ENABLED`.
@@ -0,0 +1,100 @@
1
+ # Error codes
2
+
3
+ Every error has this shape:
4
+
5
+ ```json
6
+ { "success": false, "code": "INVALID_OTP", "message": "This code is incorrect.", "attemptsLeft": 3 }
7
+ ```
8
+
9
+ - **`code`** is stable. Write your app logic against it.
10
+ - **`message`** is safe to show to users, but may be reworded between versions. Translate by `code` if your app is multilingual.
11
+ - **Extra fields** appear on some errors, as listed below.
12
+
13
+ The error list is defined in `AUTH_ERRORS` in [`src/constants.ts`](../src/constants.ts) and exported, so TypeScript clients can import it.
14
+
15
+ ## 400: the request is wrong
16
+
17
+ | Code | Meaning | Extra fields |
18
+ |---|---|---|
19
+ | `VALIDATION_ERROR` | Missing, wrong-type or unknown fields. | `problems` (from the body checks) or `missingSignUpDetails` (a new account needs these: `firstName`, `lastName`, `acceptTerms`, `acceptPrivacyPolicy`, `email`) |
20
+ | `INVALID_EMAIL` | Not an email address. | |
21
+ | `INVALID_PHONE` | Not an international number (`+` and country code). | |
22
+ | `INVALID_PASSWORD` | Breaks the password rules, or appeared in a data breach (different message). | `requirements` (e.g. `["at least 10 characters"]`) |
23
+ | `TERMS_NOT_ACCEPTED` | `acceptTerms` must be `true`. | |
24
+ | `PRIVACY_POLICY_NOT_ACCEPTED` | `acceptPrivacyPolicy` must be `true`. | |
25
+ | `EMAIL_DOMAIN_NOT_ALLOWED` | `registration.allowedEmailDomains` excludes this email. | |
26
+ | `PHONE_COUNTRY_NOT_ALLOWED` | `phoneOtp.allowedCountryCodes` excludes this number. | |
27
+ | `INVALID_OTP` | Wrong email/SMS code. | `attemptsLeft` |
28
+ | `OTP_EXPIRED` | No usable code: expired, used, too many wrong tries, or never sent. Ask for a new one. | |
29
+ | `INVALID_TOKEN` | A link token (verify email, reset password, magic link, email change, invitation) or challenge token is invalid, expired or used. | |
30
+ | `EMAIL_UNCHANGED` | `POST /auth/email/change` with the account's current email. | |
31
+ | `INVALID_SETTINGS` | Admin settings change rejected. | `problems` |
32
+ | `UNSAFE_WEBHOOK_URL` | Webhook URL is not public https. | `problem` |
33
+
34
+ ## 401: who are you?
35
+
36
+ | Code | Meaning | What the client should do |
37
+ |---|---|---|
38
+ | `UNAUTHORIZED` | No access token on a protected route. | Go to sign-in |
39
+ | `INVALID_TOKEN` | Access token expired or invalid, **or** refresh token invalid. | On an API call: refresh once and retry. On `/auth/refresh`: go to sign-in |
40
+ | `INVALID_CREDENTIALS` | Wrong email or password (always the same for both). | Show the message |
41
+ | `INVALID_OTP` | Wrong 2FA code at `/auth/2fa/verify`. | Let the user retry |
42
+ | `INVALID_API_KEY` | Missing, wrong, revoked or expired API key. | Fix the server's configuration |
43
+ | `INVALID_SOCIAL_TOKEN` | Google/Apple/Facebook token could not be verified (expired, wrong app, wrong nonce). | Sign in with the provider again |
44
+ | `INVALID_PASSKEY` | Passkey signature could not be verified, or the passkey is unknown. | Try again or use another method |
45
+
46
+ ## 403: not allowed
47
+
48
+ | Code | Meaning | Extra fields |
49
+ |---|---|---|
50
+ | `ACCOUNT_NOT_VERIFIED` | Verification still owed. | `pendingVerifications`, `email?`, `phoneNumber?` |
51
+ | `ACCOUNT_DEACTIVATED` | The user deactivated the account. | `reactivationToken`, `expiresIn` |
52
+ | `ACCOUNT_SUSPENDED` | An admin suspended the account. | |
53
+ | `FORBIDDEN` | Missing role, organization role or API-key scope; or a cookie refresh from a website not in `refreshTokenCookie.allowedOrigins`. | |
54
+ | `RECENT_SIGN_IN_REQUIRED` | Changing the email of an account without a password needs a sign-in from the last 10 minutes. Sign in again, then retry. | |
55
+ | `SIGN_UP_CLOSED` | Sign-up is off (`registration.enabled`, or that method's `allowSignUp`). | |
56
+ | `SIGN_IN_METHOD_DISABLED` | That sign-in method is turned off. | |
57
+ | `FEATURE_DISABLED` | Organizations or 2FA are turned off. | |
58
+
59
+ ## 404
60
+
61
+ | Code | Meaning |
62
+ |---|---|
63
+ | `NOT_FOUND` | Unknown id, or an organization you are not a member of (deliberately the same, so outsiders can't probe). |
64
+
65
+ ## 409: conflicts with current state
66
+
67
+ | Code | Meaning |
68
+ |---|---|
69
+ | `ACCOUNT_ALREADY_EXISTS` | Phone number already used by another account, or a sign-up race. |
70
+ | `ACCOUNT_EXISTS_WITH_OTHER_METHOD` | Social sign-in with an unverified email that belongs to an existing account. Sign in normally and link from settings. |
71
+ | `SOCIAL_ACCOUNT_IN_USE` | This Google/Apple/Facebook account is linked to another user. |
72
+ | `LAST_SIGN_IN_METHOD` | Removing this would leave no way to sign in. |
73
+ | `TWO_FACTOR_ALREADY_ENABLED` / `TWO_FACTOR_NOT_ENABLED` / `TWO_FACTOR_SETUP_NOT_STARTED` | 2FA state does not allow this step. |
74
+ | `ORGANIZATION_SLUG_TAKEN` | |
75
+ | `ALREADY_MEMBER` | |
76
+ | `LAST_OWNER` | An organization must keep at least one owner. |
77
+ | `ACCOUNT_NOT_DEACTIVATED` | Reactivation of an account that isn't deactivated. |
78
+ | `EMAIL_IN_USE` | Confirming an email change, but another account took the address in the meantime. |
79
+ | `CONFLICT` | Any other conflict raised by your own code. |
80
+
81
+ ## 429, 5xx
82
+
83
+ | Code | Meaning | Extra fields |
84
+ |---|---|---|
85
+ | `TOO_MANY_REQUESTS` | Rate limit, or a new code asked for within `resendAfterSeconds` (60 by default). Also sent as a `Retry-After` header. | `retryAfterSeconds` |
86
+ | `NOT_CONFIGURED` (501) | Feature turned on in settings but not set up in code (no `smsSender`, no Google client id, no `passkeys` option...). | |
87
+ | `INTERNAL_SERVER_ERROR` (500) | Unexpected failure (details only in the server log), or an email/SMS could not be sent. | |
88
+
89
+ ## Using errors in your own code
90
+
91
+ `AuthModule` installs its error formatter app-wide, so your controllers get the same format. Throw library errors by their definition:
92
+
93
+ ```ts
94
+ import { AUTH_ERRORS, AuthError } from '@techelusive/nest-auth';
95
+
96
+ throw new AuthError(AUTH_ERRORS.forbidden);
97
+ throw new AuthError(AUTH_ERRORS.validationFailed, { problems: [PICKUP_TIME_MUST_BE_IN_FUTURE] }); // your own constant
98
+ ```
99
+
100
+ Any NestJS `HttpException` you throw is formatted too, with a code based on its status (`NOT_FOUND`, `CONFLICT`...).
package/docs/events.md ADDED
@@ -0,0 +1,83 @@
1
+ # Events
2
+
3
+ Every important action produces an event. Each event goes to three places, in this order:
4
+
5
+ 1. **The audit log** (`auth_audit_logs`, visible at `GET /auth/admin/audit-log`)
6
+ 2. **Your `onEvent` handler** (in-process)
7
+ 3. **Webhooks** subscribed to it (delivered in the background)
8
+
9
+ A failure in any of these is logged and **never** breaks the action that caused the event.
10
+
11
+ ```ts
12
+ AuthModule.forRoot({
13
+ useFactory: (profiles: ProfilesService) => ({
14
+ // ...
15
+ onEvent: async (event) => {
16
+ if (event.name === 'user.created') await profiles.createEmptyProfile(event.userId!);
17
+ if (event.name === 'user.deleted') await profiles.deleteEverythingFor(event.userId!);
18
+ },
19
+ }),
20
+ inject: [ProfilesService],
21
+ });
22
+ ```
23
+
24
+ `onEvent` runs inside the request, so keep it quick. Hand slow work to a queue.
25
+
26
+ ## Event shape
27
+
28
+ ```ts
29
+ interface AuthEvent {
30
+ name: AuthEventName; // e.g. "user.created"
31
+ userId: string | null; // the user it is about
32
+ data: Record<string, unknown>;// details; never passwords, tokens or codes
33
+ occurredAt: string; // ISO time
34
+ }
35
+ ```
36
+
37
+ ## All events
38
+
39
+ | Event | When | `data` |
40
+ |---|---|---|
41
+ | `user.created` | New account (any method) | `status` |
42
+ | `user.activated` | `PENDING_VERIFICATION` → `ACTIVE` | |
43
+ | `user.updated` | Profile changed | `changedFields` |
44
+ | `user.email_verified` | Email verified | |
45
+ | `user.email_change_requested` | `POST /auth/email/change` accepted (also when the address was taken, so it can't be told apart) | `newEmail` (masked) |
46
+ | `user.email_changed` | Email change confirmed | `previousEmail`, `newEmail` (both masked) |
47
+ | `user.phone_verified` | Phone verified | |
48
+ | `user.onboarding_completed` | Your app called `completeOnboarding` | |
49
+ | `user.roles_changed` | Admin changed roles | `previousRoles`, `roles` |
50
+ | `user.signed_in` | Successful sign-in | `signInMethod`, `usedTwoFactor`, `sessionId`, `isNewDevice` |
51
+ | `user.sign_in_failed` | Wrong password/code, blocked account | `signInMethod`, `reason` |
52
+ | `user.signed_out` | Sign-out (one device or all) | `sessionId` or `everywhere`, `endedSessions` |
53
+ | `user.password_changed` | Change, reset, first set, or removal of an unverified password | `how` |
54
+ | `user.password_reset_requested` | Reset email sent | |
55
+ | `user.two_factor_enabled` / `user.two_factor_disabled` | 2FA turned on / off (also admin reset) | `resetByAdmin?` |
56
+ | `user.passkey_added` / `user.passkey_removed` | | `passkeyId` |
57
+ | `user.social_account_linked` / `user.social_account_unlinked` | | `provider` |
58
+ | `user.suspended` | Admin suspended | `reason` |
59
+ | `user.deactivated` / `user.reactivated` | User paused / resumed (or admin lifted a suspension) | |
60
+ | `user.deleted` | Account deleted | |
61
+ | `session.revoked` | A session ended | `sessionId`, `reason` |
62
+ | `session.refresh_token_reused` | **Security:** a used refresh token came back; the session was ended | `sessionId` |
63
+ | `organization.created` / `organization.updated` / `organization.deleted` | | `organizationId` |
64
+ | `organization.member_added` / `organization.member_removed` | | `organizationId`, `role?` |
65
+ | `organization.member_role_changed` | | `organizationId`, `previousRole`, `role` |
66
+ | `organization.invitation_sent` | | `organizationId`, `role` |
67
+ | `api_key.created` / `api_key.revoked` | | `apiKeyId`, `name?`, `scopes?` |
68
+ | `settings.changed` | Admin changed or reset settings | `changedSections` or `reset` |
69
+
70
+ The event names are exported as `AUTH_EVENTS`:
71
+
72
+ ```ts
73
+ import { AUTH_EVENTS } from '@techelusive/nest-auth';
74
+ if (event.name === AUTH_EVENTS.refreshTokenReused) alertSecurityTeam(event);
75
+ ```
76
+
77
+ ## Recording your own audit entries
78
+
79
+ ```ts
80
+ constructor(private readonly authEvents: AuthEventsService) {}
81
+
82
+ await this.authEvents.record({ name: AUTH_EVENTS.userUpdated, userId, request, details: { changedFields: ['payoutAccount'] } });
83
+ ```
@@ -0,0 +1,139 @@
1
+ # Getting started
2
+
3
+ This guide adds email + password authentication to an existing NestJS app. Other sign-in methods are switched on with one setting each, see [Configuration](configuration.md).
4
+
5
+ ## 1. Install
6
+
7
+ ```bash
8
+ npm install @techelusive/nest-auth
9
+ # Peer dependencies (most NestJS + TypeORM apps already have them):
10
+ npm install @nestjs/common @nestjs/core @nestjs/platform-express typeorm pg \
11
+ class-validator class-transformer reflect-metadata rxjs
12
+ # Optional: shared rate limits across servers
13
+ npm install ioredis
14
+ ```
15
+
16
+ ## 2. Add the auth tables to your database
17
+
18
+ The library brings its own TypeORM entities and one migration that creates 20 tables, all prefixed `auth_`. They live in your existing database next to your own tables.
19
+
20
+ ```ts
21
+ // src/data-source.ts
22
+ import { DataSource } from 'typeorm';
23
+ import { AUTH_ENTITIES, AUTH_MIGRATIONS } from '@techelusive/nest-auth';
24
+
25
+ export const appDataSource = new DataSource({
26
+ type: 'postgres',
27
+ url: process.env.DATABASE_URL,
28
+ entities: [...AUTH_ENTITIES, /* your entities */],
29
+ migrations: [...AUTH_MIGRATIONS, /* your migrations */],
30
+ synchronize: false,
31
+ });
32
+ ```
33
+
34
+ Run the migration:
35
+
36
+ ```bash
37
+ npm run build
38
+ npx typeorm migration:run -d dist/data-source.js
39
+ ```
40
+
41
+ > Never use `synchronize: true` with these tables. The migration creates constraints and indexes that `synchronize` does not know about.
42
+
43
+ ## 3. Create an encryption key (development)
44
+
45
+ The library encrypts its token-signing key, 2FA secrets and webhook secrets before storing them. In development, use a local key:
46
+
47
+ ```bash
48
+ openssl rand -base64 32
49
+ # put the result in .env as LOCAL_ENCRYPTION_KEY
50
+ ```
51
+
52
+ In production, use AWS KMS instead (see [Production checklist](production-checklist.md)). A local key is refused when `NODE_ENV=production`.
53
+
54
+ ## 4. Import the module
55
+
56
+ ```ts
57
+ // src/app.module.ts
58
+ import { Module } from '@nestjs/common';
59
+ import { AuthModule, ConsoleEmailSender } from '@techelusive/nest-auth';
60
+ import { appDataSource } from './data-source';
61
+
62
+ @Module({
63
+ imports: [
64
+ AuthModule.forRoot({
65
+ useFactory: async () => ({
66
+ dataSource: appDataSource.isInitialized ? appDataSource : await appDataSource.initialize(),
67
+ issuer: 'http://localhost:3000', // your API's public URL
68
+ appName: 'MyApp',
69
+ encryption: { localKey: process.env.LOCAL_ENCRYPTION_KEY! },
70
+ emailSender: new ConsoleEmailSender(), // prints emails to the console in development
71
+ settings: {
72
+ registration: { defaultRoles: ['user'] },
73
+ },
74
+ }),
75
+ }),
76
+ ],
77
+ })
78
+ export class AppModule {}
79
+ ```
80
+
81
+ If your app already uses `@nestjs/typeorm`, inject its `DataSource` instead:
82
+
83
+ ```ts
84
+ AuthModule.forRoot({
85
+ imports: [TypeOrmModule],
86
+ inject: [DataSource],
87
+ useFactory: (dataSource: DataSource) => ({ dataSource, /* ... */ }),
88
+ })
89
+ ```
90
+
91
+ ## 5. Trust your proxy
92
+
93
+ Rate limits, the device list and the audit log use the client's IP address. Behind a load balancer (AWS ALB, Nginx, Cloudflare), tell Express to trust one proxy hop:
94
+
95
+ ```ts
96
+ // src/main.ts
97
+ const app = await NestFactory.create<NestExpressApplication>(AppModule);
98
+ app.set('trust proxy', 1);
99
+ await app.listen(3000);
100
+ ```
101
+
102
+ ## 6. Try it
103
+
104
+ ```bash
105
+ # Register
106
+ curl -X POST localhost:3000/auth/register -H 'Content-Type: application/json' -d '{
107
+ "email": "asha@example.com", "password": "correct horse battery",
108
+ "firstName": "Asha", "lastName": "Rao", "acceptTerms": true, "acceptPrivacyPolicy": true
109
+ }'
110
+ # -> { "success": true, "status": "verification_required", "pendingVerifications": ["email"], ... }
111
+ ```
112
+
113
+ The console prints the verification email, which contains a `token` (`ev_...`). Your web page would read it from the link:
114
+
115
+ ```bash
116
+ curl -X POST localhost:3000/auth/email/verify -H 'Content-Type: application/json' -d '{ "token": "ev_..." }'
117
+
118
+ # Sign in
119
+ curl -X POST localhost:3000/auth/login -H 'Content-Type: application/json' \
120
+ -d '{ "email": "asha@example.com", "password": "correct horse battery" }'
121
+ # -> { "success": true, "status": "signed_in", "accessToken": "eyJ...", "refreshToken": "rt_...", "user": {...} }
122
+
123
+ # Call a protected route
124
+ curl localhost:3000/auth/me -H 'Authorization: Bearer eyJ...'
125
+ ```
126
+
127
+ ## 7. What changed in your app
128
+
129
+ - **Every route is now protected.** A request without a valid access token gets `401 UNAUTHORIZED`. Open public routes with `@Public()`, see [Protecting routes](protecting-routes.md). To opt in route by route instead, pass `protectAllRoutes: false`.
130
+ - **One error format everywhere.** All errors, including your own, look like `{ "success": false, "code": "...", "message": "..." }`.
131
+ - **New endpoints:** `/auth/*` and `/.well-known/jwks.json`, see [API reference](api-reference.md).
132
+ - **Background webhook worker:** it runs every 5 seconds and does nothing until you add a webhook.
133
+
134
+ ## Next steps
135
+
136
+ - Turn on more sign-in methods: [Configuration](configuration.md)
137
+ - Build your screens: [Sign-in flows](sign-in-flows.md), [Client integration](client-integration.md)
138
+ - Send real emails: write an `EmailSender` (see [Configuration → Email](configuration.md#email-sender))
139
+ - Before launch: [Production checklist](production-checklist.md)