@warlock.js/auth 5.28.0 → 5.30.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 (274) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/esm/commands/auth-cleanup-command.d.mts +1 -1
  3. package/esm/commands/auth-cleanup-command.d.mts.map +1 -1
  4. package/esm/commands/auth-cleanup-command.mjs +1 -1
  5. package/esm/commands/auth-cleanup-command.mjs.map +1 -1
  6. package/esm/commands/auth-purge-never-expiring-command.d.mts +1 -1
  7. package/esm/commands/auth-purge-never-expiring-command.d.mts.map +1 -1
  8. package/esm/commands/auth-purge-never-expiring-command.mjs +1 -1
  9. package/esm/commands/auth-purge-never-expiring-command.mjs.map +1 -1
  10. package/esm/commands/jwt-secret-generator-command.d.mts +1 -1
  11. package/esm/commands/jwt-secret-generator-command.d.mts.map +1 -1
  12. package/esm/commands/jwt-secret-generator-command.mjs +1 -1
  13. package/esm/commands/jwt-secret-generator-command.mjs.map +1 -1
  14. package/esm/contracts/auth-contract.d.mts +1 -1
  15. package/esm/contracts/auth-contract.d.mts.map +1 -1
  16. package/esm/contracts/providers.d.mts +1 -1
  17. package/esm/contracts/providers.d.mts.map +1 -1
  18. package/esm/contracts/request-locals.d.mts +1 -1
  19. package/esm/contracts/request-locals.d.mts.map +1 -1
  20. package/esm/contracts/types.d.mts +1 -1
  21. package/esm/contracts/types.d.mts.map +1 -1
  22. package/esm/contracts/types.mjs +1 -1
  23. package/esm/contracts/types.mjs.map +1 -1
  24. package/esm/errors/auth-provider-sdk-missing.error.d.mts +1 -1
  25. package/esm/errors/auth-provider-sdk-missing.error.d.mts.map +1 -1
  26. package/esm/errors/auth-provider-sdk-missing.error.mjs +1 -1
  27. package/esm/errors/auth-provider-sdk-missing.error.mjs.map +1 -1
  28. package/esm/errors/email-not-verified.error.d.mts +1 -1
  29. package/esm/errors/email-not-verified.error.d.mts.map +1 -1
  30. package/esm/errors/email-not-verified.error.mjs +1 -1
  31. package/esm/errors/email-not-verified.error.mjs.map +1 -1
  32. package/esm/errors/invalid-one-time-token.error.d.mts +1 -1
  33. package/esm/errors/invalid-one-time-token.error.d.mts.map +1 -1
  34. package/esm/errors/invalid-one-time-token.error.mjs +1 -1
  35. package/esm/errors/invalid-one-time-token.error.mjs.map +1 -1
  36. package/esm/errors/invalid-passkey.error.d.mts +1 -1
  37. package/esm/errors/invalid-passkey.error.d.mts.map +1 -1
  38. package/esm/errors/invalid-passkey.error.mjs +1 -1
  39. package/esm/errors/invalid-passkey.error.mjs.map +1 -1
  40. package/esm/errors/invalid-provider-callback.error.d.mts +1 -1
  41. package/esm/errors/invalid-provider-callback.error.d.mts.map +1 -1
  42. package/esm/errors/invalid-provider-callback.error.mjs +1 -1
  43. package/esm/errors/invalid-provider-callback.error.mjs.map +1 -1
  44. package/esm/errors/notifications-unavailable.error.d.mts +1 -1
  45. package/esm/errors/notifications-unavailable.error.d.mts.map +1 -1
  46. package/esm/errors/notifications-unavailable.error.mjs +1 -1
  47. package/esm/errors/notifications-unavailable.error.mjs.map +1 -1
  48. package/esm/errors/provider-email-not-verified.error.d.mts +1 -1
  49. package/esm/errors/provider-email-not-verified.error.d.mts.map +1 -1
  50. package/esm/errors/provider-email-not-verified.error.mjs +1 -1
  51. package/esm/errors/provider-email-not-verified.error.mjs.map +1 -1
  52. package/esm/index.d.mts +2 -2
  53. package/esm/index.mjs +2 -2
  54. package/esm/localization/ar.translations.mjs +1 -1
  55. package/esm/localization/ar.translations.mjs.map +1 -1
  56. package/esm/localization/auth-default-translations.d.mts +1 -1
  57. package/esm/localization/auth-default-translations.d.mts.map +1 -1
  58. package/esm/localization/auth-default-translations.mjs +1 -1
  59. package/esm/localization/auth-default-translations.mjs.map +1 -1
  60. package/esm/localization/auth-translations.type.d.mts +1 -1
  61. package/esm/localization/auth-translations.type.d.mts.map +1 -1
  62. package/esm/localization/en.translations.mjs +1 -1
  63. package/esm/localization/en.translations.mjs.map +1 -1
  64. package/esm/localization/init.mjs +1 -1
  65. package/esm/localization/init.mjs.map +1 -1
  66. package/esm/localization/register-auth-translations.d.mts +1 -1
  67. package/esm/localization/register-auth-translations.d.mts.map +1 -1
  68. package/esm/localization/register-auth-translations.mjs +1 -1
  69. package/esm/localization/register-auth-translations.mjs.map +1 -1
  70. package/esm/middleware/auth.middleware.d.mts +1 -1
  71. package/esm/middleware/auth.middleware.d.mts.map +1 -1
  72. package/esm/middleware/auth.middleware.mjs +1 -1
  73. package/esm/middleware/auth.middleware.mjs.map +1 -1
  74. package/esm/middleware/csrf-origin-check.d.mts +1 -1
  75. package/esm/middleware/csrf-origin-check.d.mts.map +1 -1
  76. package/esm/middleware/csrf-origin-check.mjs +1 -1
  77. package/esm/middleware/csrf-origin-check.mjs.map +1 -1
  78. package/esm/middleware/index.d.mts +1 -1
  79. package/esm/middleware/index.mjs +1 -1
  80. package/esm/middleware/localized-login-path.mjs +1 -1
  81. package/esm/middleware/localized-login-path.mjs.map +1 -1
  82. package/esm/middleware/login-throttle.middleware.d.mts +17 -2
  83. package/esm/middleware/login-throttle.middleware.d.mts.map +1 -1
  84. package/esm/middleware/login-throttle.middleware.mjs +84 -6
  85. package/esm/middleware/login-throttle.middleware.mjs.map +1 -1
  86. package/esm/middleware/one-time-token-throttle.middleware.d.mts +1 -1
  87. package/esm/middleware/one-time-token-throttle.middleware.d.mts.map +1 -1
  88. package/esm/middleware/one-time-token-throttle.middleware.mjs +1 -1
  89. package/esm/middleware/one-time-token-throttle.middleware.mjs.map +1 -1
  90. package/esm/middleware/otp-throttle.middleware.d.mts +1 -1
  91. package/esm/middleware/otp-throttle.middleware.d.mts.map +1 -1
  92. package/esm/middleware/otp-throttle.middleware.mjs +1 -1
  93. package/esm/middleware/otp-throttle.middleware.mjs.map +1 -1
  94. package/esm/middleware/require-verified-email.middleware.d.mts +1 -1
  95. package/esm/middleware/require-verified-email.middleware.d.mts.map +1 -1
  96. package/esm/middleware/require-verified-email.middleware.mjs +1 -1
  97. package/esm/middleware/require-verified-email.middleware.mjs.map +1 -1
  98. package/esm/models/access-token/access-token.model.d.mts +27 -35
  99. package/esm/models/access-token/access-token.model.d.mts.map +1 -1
  100. package/esm/models/access-token/access-token.model.mjs +1 -1
  101. package/esm/models/access-token/access-token.model.mjs.map +1 -1
  102. package/esm/models/access-token/family-association.migration.mjs +1 -1
  103. package/esm/models/access-token/family-association.migration.mjs.map +1 -1
  104. package/esm/models/access-token/migration.mjs +1 -1
  105. package/esm/models/access-token/migration.mjs.map +1 -1
  106. package/esm/models/auth-token-family/auth-token-family.model.d.mts +27 -43
  107. package/esm/models/auth-token-family/auth-token-family.model.d.mts.map +1 -1
  108. package/esm/models/auth-token-family/auth-token-family.model.mjs +1 -1
  109. package/esm/models/auth-token-family/auth-token-family.model.mjs.map +1 -1
  110. package/esm/models/auth-token-family/migration.mjs +1 -1
  111. package/esm/models/auth-token-family/migration.mjs.map +1 -1
  112. package/esm/models/auth.model.d.mts +1 -1
  113. package/esm/models/auth.model.d.mts.map +1 -1
  114. package/esm/models/auth.model.mjs +1 -1
  115. package/esm/models/auth.model.mjs.map +1 -1
  116. package/esm/models/index.d.mts +1 -1
  117. package/esm/models/index.d.mts.map +1 -1
  118. package/esm/models/index.mjs +1 -1
  119. package/esm/models/index.mjs.map +1 -1
  120. package/esm/models/one-time-token/migration.mjs +1 -1
  121. package/esm/models/one-time-token/migration.mjs.map +1 -1
  122. package/esm/models/one-time-token/one-time-token.model.d.mts +35 -67
  123. package/esm/models/one-time-token/one-time-token.model.d.mts.map +1 -1
  124. package/esm/models/one-time-token/one-time-token.model.mjs +1 -1
  125. package/esm/models/one-time-token/one-time-token.model.mjs.map +1 -1
  126. package/esm/models/passkey-credential/migration.mjs +1 -1
  127. package/esm/models/passkey-credential/migration.mjs.map +1 -1
  128. package/esm/models/passkey-credential/passkey-credential.model.d.mts +31 -47
  129. package/esm/models/passkey-credential/passkey-credential.model.d.mts.map +1 -1
  130. package/esm/models/passkey-credential/passkey-credential.model.mjs +1 -1
  131. package/esm/models/passkey-credential/passkey-credential.model.mjs.map +1 -1
  132. package/esm/models/provider-account/migration.mjs +1 -1
  133. package/esm/models/provider-account/migration.mjs.map +1 -1
  134. package/esm/models/provider-account/provider-account.model.d.mts +27 -35
  135. package/esm/models/provider-account/provider-account.model.d.mts.map +1 -1
  136. package/esm/models/provider-account/provider-account.model.mjs +1 -1
  137. package/esm/models/provider-account/provider-account.model.mjs.map +1 -1
  138. package/esm/models/refresh-token/migration.mjs +1 -1
  139. package/esm/models/refresh-token/migration.mjs.map +1 -1
  140. package/esm/models/refresh-token/refresh-token.model.d.mts +47 -95
  141. package/esm/models/refresh-token/refresh-token.model.d.mts.map +1 -1
  142. package/esm/models/refresh-token/refresh-token.model.mjs +1 -1
  143. package/esm/models/refresh-token/refresh-token.model.mjs.map +1 -1
  144. package/esm/models/refresh-token/successor-association.migration.mjs +1 -1
  145. package/esm/models/refresh-token/successor-association.migration.mjs.map +1 -1
  146. package/esm/otp/otp.d.mts +1 -1
  147. package/esm/otp/otp.d.mts.map +1 -1
  148. package/esm/otp/otp.mjs +1 -1
  149. package/esm/otp/otp.mjs.map +1 -1
  150. package/esm/passkeys/passkey-authentication.d.mts +1 -1
  151. package/esm/passkeys/passkey-authentication.d.mts.map +1 -1
  152. package/esm/passkeys/passkey-authentication.mjs +1 -1
  153. package/esm/passkeys/passkey-authentication.mjs.map +1 -1
  154. package/esm/passkeys/passkey-challenges.mjs +1 -1
  155. package/esm/passkeys/passkey-challenges.mjs.map +1 -1
  156. package/esm/passkeys/passkey-registration.d.mts +1 -1
  157. package/esm/passkeys/passkey-registration.d.mts.map +1 -1
  158. package/esm/passkeys/passkey-registration.mjs +1 -1
  159. package/esm/passkeys/passkey-registration.mjs.map +1 -1
  160. package/esm/passkeys/simplewebauthn.d.mts +1 -1
  161. package/esm/passkeys/simplewebauthn.d.mts.map +1 -1
  162. package/esm/passkeys/simplewebauthn.mjs +1 -1
  163. package/esm/passkeys/simplewebauthn.mjs.map +1 -1
  164. package/esm/providers/apple-provider.d.mts +1 -1
  165. package/esm/providers/apple-provider.d.mts.map +1 -1
  166. package/esm/providers/apple-provider.mjs +1 -1
  167. package/esm/providers/apple-provider.mjs.map +1 -1
  168. package/esm/providers/discord-provider.d.mts +1 -1
  169. package/esm/providers/discord-provider.d.mts.map +1 -1
  170. package/esm/providers/discord-provider.mjs +1 -1
  171. package/esm/providers/discord-provider.mjs.map +1 -1
  172. package/esm/providers/facebook-provider.d.mts +1 -1
  173. package/esm/providers/facebook-provider.d.mts.map +1 -1
  174. package/esm/providers/facebook-provider.mjs +1 -1
  175. package/esm/providers/facebook-provider.mjs.map +1 -1
  176. package/esm/providers/github-provider.d.mts +1 -1
  177. package/esm/providers/github-provider.d.mts.map +1 -1
  178. package/esm/providers/github-provider.mjs +1 -1
  179. package/esm/providers/github-provider.mjs.map +1 -1
  180. package/esm/providers/google-provider.d.mts +1 -1
  181. package/esm/providers/google-provider.d.mts.map +1 -1
  182. package/esm/providers/google-provider.mjs +1 -1
  183. package/esm/providers/google-provider.mjs.map +1 -1
  184. package/esm/providers/linkedin-provider.d.mts +1 -1
  185. package/esm/providers/linkedin-provider.d.mts.map +1 -1
  186. package/esm/providers/linkedin-provider.mjs +1 -1
  187. package/esm/providers/linkedin-provider.mjs.map +1 -1
  188. package/esm/providers/provider-login.d.mts +1 -1
  189. package/esm/providers/provider-login.d.mts.map +1 -1
  190. package/esm/providers/provider-login.mjs +1 -1
  191. package/esm/providers/provider-login.mjs.map +1 -1
  192. package/esm/providers/provider-state-cookie.mjs +1 -1
  193. package/esm/providers/provider-state-cookie.mjs.map +1 -1
  194. package/esm/providers/resolve-provider-user.mjs +1 -1
  195. package/esm/providers/resolve-provider-user.mjs.map +1 -1
  196. package/esm/providers/x-provider.d.mts +1 -1
  197. package/esm/providers/x-provider.d.mts.map +1 -1
  198. package/esm/providers/x-provider.mjs +1 -1
  199. package/esm/providers/x-provider.mjs.map +1 -1
  200. package/esm/services/auth-config.mjs +1 -1
  201. package/esm/services/auth-config.mjs.map +1 -1
  202. package/esm/services/auth-events.d.mts +1 -1
  203. package/esm/services/auth-events.d.mts.map +1 -1
  204. package/esm/services/auth-events.mjs +1 -1
  205. package/esm/services/auth-events.mjs.map +1 -1
  206. package/esm/services/auth.service.d.mts +1 -1
  207. package/esm/services/auth.service.d.mts.map +1 -1
  208. package/esm/services/auth.service.mjs +1 -1
  209. package/esm/services/auth.service.mjs.map +1 -1
  210. package/esm/services/current-user.d.mts +1 -1
  211. package/esm/services/current-user.d.mts.map +1 -1
  212. package/esm/services/current-user.mjs +1 -1
  213. package/esm/services/current-user.mjs.map +1 -1
  214. package/esm/services/email-verification.d.mts +1 -1
  215. package/esm/services/email-verification.d.mts.map +1 -1
  216. package/esm/services/email-verification.mjs +1 -1
  217. package/esm/services/email-verification.mjs.map +1 -1
  218. package/esm/services/generate-jwt-secret.d.mts +1 -1
  219. package/esm/services/generate-jwt-secret.d.mts.map +1 -1
  220. package/esm/services/generate-jwt-secret.mjs +1 -1
  221. package/esm/services/generate-jwt-secret.mjs.map +1 -1
  222. package/esm/services/jwt.d.mts +1 -1
  223. package/esm/services/jwt.d.mts.map +1 -1
  224. package/esm/services/jwt.mjs +1 -1
  225. package/esm/services/jwt.mjs.map +1 -1
  226. package/esm/services/one-time-tokens.d.mts +1 -1
  227. package/esm/services/one-time-tokens.d.mts.map +1 -1
  228. package/esm/services/one-time-tokens.mjs +1 -1
  229. package/esm/services/one-time-tokens.mjs.map +1 -1
  230. package/esm/services/optional-peer.mjs +1 -1
  231. package/esm/services/optional-peer.mjs.map +1 -1
  232. package/esm/services/password-reset.d.mts +1 -1
  233. package/esm/services/password-reset.d.mts.map +1 -1
  234. package/esm/services/password-reset.mjs +1 -1
  235. package/esm/services/password-reset.mjs.map +1 -1
  236. package/esm/services/resolve-request-user.d.mts +1 -1
  237. package/esm/services/resolve-request-user.d.mts.map +1 -1
  238. package/esm/services/resolve-request-user.mjs +1 -1
  239. package/esm/services/resolve-request-user.mjs.map +1 -1
  240. package/esm/services/token-family-operation.mjs +1 -1
  241. package/esm/services/token-family-operation.mjs.map +1 -1
  242. package/esm/services/token-notifications.mjs +1 -1
  243. package/esm/services/token-notifications.mjs.map +1 -1
  244. package/esm/session/page-session.d.mts +1 -1
  245. package/esm/session/page-session.d.mts.map +1 -1
  246. package/esm/session/page-session.mjs +1 -1
  247. package/esm/session/page-session.mjs.map +1 -1
  248. package/esm/utils/auth-error-codes.d.mts +1 -1
  249. package/esm/utils/auth-error-codes.d.mts.map +1 -1
  250. package/esm/utils/auth-error-codes.mjs +1 -1
  251. package/esm/utils/auth-error-codes.mjs.map +1 -1
  252. package/esm/utils/safe-equal.d.mts +1 -1
  253. package/esm/utils/safe-equal.d.mts.map +1 -1
  254. package/esm/utils/safe-equal.mjs +1 -1
  255. package/esm/utils/safe-equal.mjs.map +1 -1
  256. package/esm/utils/token-expiry.d.mts +1 -1
  257. package/esm/utils/token-expiry.d.mts.map +1 -1
  258. package/esm/utils/token-expiry.mjs +1 -1
  259. package/esm/utils/token-expiry.mjs.map +1 -1
  260. package/llms-full.txt +76 -74
  261. package/llms.txt +10 -10
  262. package/package.json +10 -9
  263. package/skills/auth-basics/SKILL.md +10 -10
  264. package/skills/customize-token-storage/SKILL.md +5 -5
  265. package/skills/customize-user-type/SKILL.md +5 -5
  266. package/skills/handle-login-and-logout/SKILL.md +5 -5
  267. package/skills/login-with-providers/SKILL.md +4 -4
  268. package/skills/manage-tokens/SKILL.md +6 -6
  269. package/skills/overview/SKILL.md +12 -12
  270. package/skills/protect-routes/SKILL.md +7 -7
  271. package/skills/register-user/SKILL.md +7 -7
  272. package/skills/run-auth-commands/SKILL.md +4 -4
  273. package/skills/throttle-login-attempts/SKILL.md +7 -5
  274. package/skills/verify-email-and-reset-password/SKILL.md +4 -4
@@ -17,13 +17,13 @@ npm install @warlock.js/auth
17
17
 
18
18
  ## Foundations
19
19
 
20
- 1. **Users extend `Auth`.** Your `User`, `Admin`, etc. extend the shared base model that knows how to issue tokens and verify passwords. Multiple user types coexist (see [`@warlock.js/auth/customize-user-type/SKILL.md`](@warlock.js/auth/customize-user-type/SKILL.md)).
20
+ 1. **Users extend `Auth`.** Your `User`, `Admin`, etc. extend the shared base model that knows how to issue tokens and verify passwords. Multiple user types coexist (see the `customize-user-type` topic).
21
21
  2. **`auth.userType.<name>` config maps a user-type slug to the model class.** The middleware uses this to hydrate the right model from a token.
22
22
  3. **Tokens persist.** Both `AccessToken` and `RefreshToken` are Cascade models — issuing a token writes a row; logout / revoke deletes or marks-revoked. Stateless JWT verification + stateful revocation list.
23
23
  4. **`authMiddleware` gates or resolves routes.** Use `authMiddleware("user")` for a typed hard gate, `authMiddleware()` for the configured/default user type, or `authMiddleware({ source: "cookie", key: "token", optional: true })` for a public route that receives a valid user when present. The object form can set a page-local login redirect. Legacy `authMiddleware(userType, "cookie:name")` remains valid.
24
24
  5. **`authService.login(Model, credentials, deviceInfo?)` is the full happy path.** Verifies credentials, creates token pair (access + refresh), emits events, returns `{ user, tokens }`.
25
25
  6. **Refresh-token rotation is on by default.** Each refresh consumes the old token and issues new ones from the same "family" — replay detection revokes the family.
26
- 7. **JWT secret lives in the env.** Generate with `warlock jwt.generate` (see [`@warlock.js/auth/run-auth-commands/SKILL.md`](@warlock.js/auth/run-auth-commands/SKILL.md)).
26
+ 7. **JWT secret lives in the env.** Generate with `warlock jwt.generate` (see the `run-auth-commands` topic).
27
27
 
28
28
  ## Minimal wire-up
29
29
 
@@ -105,16 +105,16 @@ Two values that look right and are not:
105
105
 
106
106
  | If the task is about… | Load |
107
107
  | --- | --- |
108
- | Gating routes with `authMiddleware(allowedUserType)`, any-authenticated vs typed access | [`@warlock.js/auth/protect-routes/SKILL.md`](@warlock.js/auth/protect-routes/SKILL.md) |
109
- | `authService.login(...)`, `attemptLogin`, full credentials-to-tokens flow + logout | [`@warlock.js/auth/handle-login-and-logout/SKILL.md`](@warlock.js/auth/handle-login-and-logout/SKILL.md) |
110
- | Token lifecycle — `generateAccessToken`, `createRefreshToken`, rotation, family revocation, max-per-user | [`@warlock.js/auth/manage-tokens/SKILL.md`](@warlock.js/auth/manage-tokens/SKILL.md) |
111
- | Register a new user + issue tokens in one flow | [`@warlock.js/auth/register-user/SKILL.md`](@warlock.js/auth/register-user/SKILL.md) |
112
- | Multi-user-type apps (`user`, `admin`, `client`), `config.auth.userType.<name>` mapping | [`@warlock.js/auth/customize-user-type/SKILL.md`](@warlock.js/auth/customize-user-type/SKILL.md) |
113
- | `warlock jwt.generate` + `warlock auth.cleanup` CLI commands | [`@warlock.js/auth/run-auth-commands/SKILL.md`](@warlock.js/auth/run-auth-commands/SKILL.md) |
108
+ | Gating routes with `authMiddleware(allowedUserType)`, any-authenticated vs typed access | The `protect-routes` topic |
109
+ | `authService.login(...)`, `attemptLogin`, full credentials-to-tokens flow + logout | The `handle-login-and-logout` topic |
110
+ | Token lifecycle — `generateAccessToken`, `createRefreshToken`, rotation, family revocation, max-per-user | The `manage-tokens` topic |
111
+ | Register a new user + issue tokens in one flow | The `register-user` topic |
112
+ | Multi-user-type apps (`user`, `admin`, `client`), `config.auth.userType.<name>` mapping | The `customize-user-type` topic |
113
+ | `warlock jwt.generate` + `warlock auth.cleanup` CLI commands | The `run-auth-commands` topic |
114
114
 
115
115
  ## Things NOT to do
116
116
 
117
117
  - Don't write your own JWT signing logic — use `authService` / `jwt` from this package so signature/secret/expiry stay consistent.
118
118
  - Don't store the JWT secret in the model layer or anywhere user-modifiable. It lives in `.env` only.
119
- - Don't return the raw `User` from a login endpoint without shaping output. Configure `static toJsonColumns` or `static resource` (see [`@warlock.js/cascade/define-model/SKILL.md`](@warlock.js/cascade/define-model/SKILL.md)).
120
- - Don't run `auth.cleanup` from app boot. Schedule it (cron, scheduler) as a periodic task — see [`@warlock.js/scheduler/scheduler-basics/SKILL.md`](@warlock.js/scheduler/scheduler-basics/SKILL.md).
119
+ - Don't return the raw `User` from a login endpoint without shaping output. Configure `static toJsonColumns` or `static resource` (see the `define-model` topic of the `warlock-js-cascade` skill).
120
+ - Don't run `auth.cleanup` from app boot. Schedule it (cron, scheduler) as a periodic task — see the `scheduler-basics` topic of the `warlock-js-scheduler` skill.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: customize-token-storage
3
- description: 'Override the persisted AccessToken / RefreshToken models to add columns (multi-tenant `organization_id`, device metadata), rename, or change storage — without forking the package. Extend the model + `schema.extend(...)`, register it under `config.auth.accessToken.model` / `config.auth.refreshToken.model`, override `issue()` to populate the new column, and add a migration. Triggers: `accessToken.model`, `refreshToken.model`, `AccessToken.issue`, `RefreshToken.issue`, `accessTokenSchema`, `refreshTokenSchema`, "add a column to the token table", "multi-tenant tokens", "organization_id on access token", "override the token model", "custom token storage"; typical import `import { AccessToken, accessTokenSchema } from "@warlock.js/auth"`. Skip: multiple user TYPES (not token storage) — `@warlock.js/auth/customize-user-type/SKILL.md`; the token lifecycle API — `@warlock.js/auth/manage-tokens/SKILL.md`; the config blocks themselves — `@warlock.js/auth/auth-basics/SKILL.md`.'
3
+ description: 'Override the persisted AccessToken / RefreshToken models to add columns (multi-tenant `organization_id`, device metadata), rename, or change storage — without forking the package. Extend the model + `schema.extend(...)`, register it under `config.auth.accessToken.model` / `config.auth.refreshToken.model`, override `issue()` to populate the new column, and add a migration. Triggers: `accessToken.model`, `refreshToken.model`, `AccessToken.issue`, `RefreshToken.issue`, `accessTokenSchema`, `refreshTokenSchema`, "add a column to the token table", "multi-tenant tokens", "organization_id on access token", "override the token model", "custom token storage"; typical import `import { AccessToken, accessTokenSchema } from "@warlock.js/auth"`. Skip: multiple user TYPES (not token storage) — the `customize-user-type` topic; the token lifecycle API — the `manage-tokens` topic; the config blocks themselves — the `auth-basics` topic.'
4
4
  ---
5
5
 
6
6
  # Customize token storage
@@ -110,7 +110,7 @@ The new column needs a real database column. Add it to your token-table migratio
110
110
  this.uuid("organization_id").references("organizations").onDelete("cascade").index();
111
111
  ```
112
112
 
113
- See [`@warlock.js/cascade/write-migration/SKILL.md`](@warlock.js/cascade/write-migration/SKILL.md) for the migration mechanics.
113
+ See the `write-migration` topic of the `warlock-js-cascade` skill for the migration mechanics.
114
114
 
115
115
  ## Why all three — the strict-mode trap
116
116
 
@@ -155,6 +155,6 @@ If you rename a column, override the statics **and these getters** so they map t
155
155
 
156
156
  ## See also
157
157
 
158
- - [`@warlock.js/auth/customize-user-type/SKILL.md`](@warlock.js/auth/customize-user-type/SKILL.md) — multiple user *types* (a different axis from token *storage*).
159
- - [`@warlock.js/auth/manage-tokens/SKILL.md`](@warlock.js/auth/manage-tokens/SKILL.md) — the token lifecycle your statics power.
160
- - [`@warlock.js/cascade/define-model/SKILL.md`](@warlock.js/cascade/define-model/SKILL.md) — extending models and schemas.
158
+ - The `customize-user-type` topic — multiple user *types* (a different axis from token *storage*).
159
+ - The `manage-tokens` topic — the token lifecycle your statics power.
160
+ - The `define-model` topic of the `warlock-js-cascade` skill — extending models and schemas.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: customize-user-type
3
- description: 'Support multiple user types (user / admin / client / staff) in one auth system — each Auth subclass overrides userType, config.auth.userType.<slug> maps slug to model class, authMiddleware(''admin'') gates per type. Triggers: `Auth`, `userType`, `config.auth.userType`, `Authenticable`, `@RegisterModel`, `confirmPassword`; "add admins and users", "multiple user types", "separate client and vendor personas", "per-type login"; typical import `import { Auth } from "@warlock.js/auth"`. Skip: `authMiddleware` semantics — `@warlock.js/auth/protect-routes/SKILL.md`; login flow — `@warlock.js/auth/handle-login-and-logout/SKILL.md`; RBAC libs `casl`, `accesscontrol`, `rbac`.'
3
+ description: 'Support multiple user types (user / admin / client / staff) in one auth system — each Auth subclass overrides userType, config.auth.userType.<slug> maps slug to model class, authMiddleware(''admin'') gates per type. Triggers: `Auth`, `userType`, `config.auth.userType`, `Authenticable`, `@RegisterModel`, `confirmPassword`; "add admins and users", "multiple user types", "separate client and vendor personas", "per-type login"; typical import `import { Auth } from "@warlock.js/auth"`. Skip: `authMiddleware` semantics — the `protect-routes` topic; login flow — the `handle-login-and-logout` topic; RBAC libs `casl`, `accesscontrol`, `rbac`.'
4
4
  ---
5
5
 
6
6
  # Customize user type (multi-user-type auth)
@@ -103,7 +103,7 @@ router.get("/back-office", backOfficeController, { middleware: [authMiddleware([
103
103
  router.get("/dashboard", dashboardController, { middleware: [authMiddleware([])] }); // any logged-in
104
104
  ```
105
105
 
106
- See [`@warlock.js/auth/protect-routes/SKILL.md`](@warlock.js/auth/protect-routes/SKILL.md).
106
+ See the `protect-routes` topic.
107
107
 
108
108
  ## Login per user type — pass the right Model
109
109
 
@@ -163,6 +163,6 @@ abstract class Auth<TSchema> extends Model<TSchema> implements Authenticable {
163
163
 
164
164
  ## See also
165
165
 
166
- - [`@warlock.js/auth/protect-routes/SKILL.md`](@warlock.js/auth/protect-routes/SKILL.md) — `authMiddleware` semantics
167
- - [`@warlock.js/auth/handle-login-and-logout/SKILL.md`](@warlock.js/auth/handle-login-and-logout/SKILL.md) — passing the right Model to `login`
168
- - [`@warlock.js/cascade/define-model/SKILL.md`](@warlock.js/cascade/define-model/SKILL.md) — `@RegisterModel`, models in general
166
+ - The `protect-routes` topic — `authMiddleware` semantics
167
+ - The `handle-login-and-logout` topic — passing the right Model to `login`
168
+ - The `define-model` topic of the `warlock-js-cascade` skill — `@RegisterModel`, models in general
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: handle-login-and-logout
3
- description: 'Run the full login flow via authService.login(Model, credentials, deviceInfo?) — verify password, create access + refresh token pair, fire events. Logout via authService.logout(user, accessToken?, refreshToken?) revokes tokens. Triggers: `authService.login`, `authService.logout`, `authService.attemptLogin`, `authService.refreshTokens`, `authService.revokeAllTokens`, `authEvents`; "build a login endpoint", "POST /login controller", "logout from all devices", "verify credentials and issue tokens"; typical import `import { authService, authEvents } from "@warlock.js/auth"`. Skip: token internals — `@warlock.js/auth/manage-tokens/SKILL.md`; sign-up — `@warlock.js/auth/register-user/SKILL.md`; competing libs `passport-local`, `next-auth` credentials.'
3
+ description: 'Run the full login flow via authService.login(Model, credentials, deviceInfo?) — verify password, create access + refresh token pair, fire events. Logout via authService.logout(user, accessToken?, refreshToken?) revokes tokens. Triggers: `authService.login`, `authService.logout`, `authService.attemptLogin`, `authService.refreshTokens`, `authService.revokeAllTokens`, `authEvents`; "build a login endpoint", "POST /login controller", "logout from all devices", "verify credentials and issue tokens"; typical import `import { authService, authEvents } from "@warlock.js/auth"`. Skip: token internals — the `manage-tokens` topic; sign-up — the `register-user` topic; competing libs `passport-local`, `next-auth` credentials.'
4
4
  ---
5
5
 
6
6
  # Login + logout
@@ -152,7 +152,7 @@ export const refreshController: RequestHandler = async ({ request, response }) =
152
152
  };
153
153
  ```
154
154
 
155
- Returns a new token pair or `null` (token expired, revoked, or replay-detected). With rotation enabled (default), the old refresh token is consumed; the new pair stays in the same "family." Replay → revoke the whole family. See [`@warlock.js/auth/manage-tokens/SKILL.md`](@warlock.js/auth/manage-tokens/SKILL.md).
155
+ Returns a new token pair or `null` (token expired, revoked, or replay-detected). With rotation enabled (default), the old refresh token is consumed; the new pair stays in the same "family." Replay → revoke the whole family. See the `manage-tokens` topic.
156
156
 
157
157
  ## Auth events
158
158
 
@@ -189,9 +189,9 @@ Full event list: `login.attempt`, `login.success`, `login.failed`, `logout`, `lo
189
189
 
190
190
  ## See also
191
191
 
192
- - [`@warlock.js/auth/manage-tokens/SKILL.md`](@warlock.js/auth/manage-tokens/SKILL.md) — token lifecycle, rotation, family revocation
193
- - [`@warlock.js/auth/register-user/SKILL.md`](@warlock.js/auth/register-user/SKILL.md) — sign-up that issues tokens after creation
194
- - [`@warlock.js/auth/protect-routes/SKILL.md`](@warlock.js/auth/protect-routes/SKILL.md) — where the access token gets consumed
192
+ - The `manage-tokens` topic — token lifecycle, rotation, family revocation
193
+ - The `register-user` topic — sign-up that issues tokens after creation
194
+ - The `protect-routes` topic — where the access token gets consumed
195
195
 
196
196
  ## Browser sessions for Web pages
197
197
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: login-with-providers
3
- description: 'Log in without a password — Google (OIDC code + PKCE + state + nonce, id_token verified with `jose`), GitHub, Discord, LinkedIn, Apple (`form_post` callback), Facebook and X, passkeys (WebAuthn via `@simplewebauthn/server`) and phone one-time codes (delivered through a `@warlock.js/notifications` channel). Every method ends in `authService.completeLogin(user)`, the same tokens, rows and events as password login. `startProviderLogin`, `completeProviderLogin`, `generatePasskeyRegistrationOptions`, `verifyPasskeyRegistration`, `generatePasskeyAuthenticationOptions`, `verifyPasskeyAuthentication`, `requestOtp`, `verifyOtp`, `otpRequestThrottleMiddleware`, `otpVerifyThrottleMiddleware`, `AuthProvider`. Triggers: "login with Google", "sign in with Google", "login with GitHub", "Sign in with Apple", "login with Discord", "login with LinkedIn", "login with Facebook", "login with X", `auth.providers.github`, "OAuth", "OIDC", "passkeys", "WebAuthn", "passwordless", "SMS code login", "WhatsApp OTP", "phone login", `warlock add auth-google`, `warlock add auth-passkeys`, `AuthProviderSdkMissingError`, `InvalidProviderCallbackError`, `ProviderEmailNotVerifiedError`, `InvalidPasskeyError`, `EC009`, `EC010`, `EC011`, `auth.providers`, `auth.passkeys`, `auth.otp`; typical import `import { completeProviderLogin, verifyOtp } from "@warlock.js/auth"`. Skip: password login — `@warlock.js/auth/handle-login-and-logout/SKILL.md`; email tokens — `@warlock.js/auth/verify-email-and-reset-password/SKILL.md`; defining an SMS channel — `@warlock.js/notifications/define-channel/SKILL.md`.'
3
+ description: 'Log in without a password — Google (OIDC code + PKCE + state + nonce, id_token verified with `jose`), GitHub, Discord, LinkedIn, Apple (`form_post` callback), Facebook and X, passkeys (WebAuthn via `@simplewebauthn/server`) and phone one-time codes (delivered through a `@warlock.js/notifications` channel). Every method ends in `authService.completeLogin(user)`, the same tokens, rows and events as password login. `startProviderLogin`, `completeProviderLogin`, `generatePasskeyRegistrationOptions`, `verifyPasskeyRegistration`, `generatePasskeyAuthenticationOptions`, `verifyPasskeyAuthentication`, `requestOtp`, `verifyOtp`, `otpRequestThrottleMiddleware`, `otpVerifyThrottleMiddleware`, `AuthProvider`. Triggers: "login with Google", "sign in with Google", "login with GitHub", "Sign in with Apple", "login with Discord", "login with LinkedIn", "login with Facebook", "login with X", `auth.providers.github`, "OAuth", "OIDC", "passkeys", "WebAuthn", "passwordless", "SMS code login", "WhatsApp OTP", "phone login", `warlock add auth-google`, `warlock add auth-passkeys`, `AuthProviderSdkMissingError`, `InvalidProviderCallbackError`, `ProviderEmailNotVerifiedError`, `InvalidPasskeyError`, `EC009`, `EC010`, `EC011`, `auth.providers`, `auth.passkeys`, `auth.otp`; typical import `import { completeProviderLogin, verifyOtp } from "@warlock.js/auth"`. Skip: password login — the `handle-login-and-logout` topic; email tokens — the `verify-email-and-reset-password` topic; defining an SMS channel — the `define-channel` topic of the `warlock-js-notifications` skill.'
4
4
  ---
5
5
 
6
6
  # Login with an OAuth provider, passkeys, or a phone code
@@ -278,6 +278,6 @@ router.post("/auth/otp/verify", async ({ request, response }) => {
278
278
 
279
279
  ## See also
280
280
 
281
- - [`@warlock.js/auth/handle-login-and-logout/SKILL.md`](@warlock.js/auth/handle-login-and-logout/SKILL.md): password login and `setAuthCookie`
282
- - [`@warlock.js/auth/throttle-login-attempts/SKILL.md`](@warlock.js/auth/throttle-login-attempts/SKILL.md): the throttle the OTP presets wrap
283
- - [`@warlock.js/notifications/define-channel/SKILL.md`](@warlock.js/notifications/define-channel/SKILL.md): an SMS/WhatsApp channel
281
+ - The `handle-login-and-logout` topic: password login and `setAuthCookie`
282
+ - The `throttle-login-attempts` topic: the throttle the OTP presets wrap
283
+ - The `define-channel` topic of the `warlock-js-notifications` skill: an SMS/WhatsApp channel
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: manage-tokens
3
- description: 'Token lifecycle — generateAccessToken, createRefreshToken, createTokenPair, refreshTokens (with rotation + replay detection), revokeAllTokens, revokeTokenFamily, cleanupExpiredTokens, getActiveSessions. Triggers: `createTokenPair`, `refreshTokens`, `revokeTokenFamily`, `cleanupExpiredTokens`, `getActiveSessions`, `jwt.generate`, `jwt.verify`, `AccessToken`, `RefreshToken`; "rotate refresh tokens", "detect token replay", "logout from all devices", "list active sessions", "clean up expired tokens"; typical import `import { authService, jwt } from "@warlock.js/auth"`. Skip: login flow — `@warlock.js/auth/handle-login-and-logout/SKILL.md`; CLI cleanup — `@warlock.js/auth/run-auth-commands/SKILL.md`; competing libs `jsonwebtoken`, `jose`, `fast-jwt`.'
3
+ description: 'Token lifecycle — generateAccessToken, createRefreshToken, createTokenPair, refreshTokens (with rotation + replay detection), revokeAllTokens, revokeTokenFamily, cleanupExpiredTokens, getActiveSessions. Triggers: `createTokenPair`, `refreshTokens`, `revokeTokenFamily`, `cleanupExpiredTokens`, `getActiveSessions`, `jwt.generate`, `jwt.verify`, `AccessToken`, `RefreshToken`; "rotate refresh tokens", "detect token replay", "logout from all devices", "list active sessions", "clean up expired tokens"; typical import `import { authService, jwt } from "@warlock.js/auth"`. Skip: login flow — the `handle-login-and-logout` topic; CLI cleanup — the `run-auth-commands` topic; competing libs `jsonwebtoken`, `jose`, `fast-jwt`.'
4
4
  ---
5
5
 
6
6
  # Manage tokens
@@ -155,7 +155,7 @@ scheduler.addJob(
155
155
  );
156
156
  ```
157
157
 
158
- Or use the bundled CLI command — see [`@warlock.js/auth/run-auth-commands/SKILL.md`](@warlock.js/auth/run-auth-commands/SKILL.md).
158
+ Or use the bundled CLI command — see the `run-auth-commands` topic.
159
159
 
160
160
  ## JWT helpers
161
161
 
@@ -175,7 +175,7 @@ const decodedRefresh = await jwt.verifyRefreshToken(refreshToken);
175
175
 
176
176
  **`jwt.verify` / `jwt.verifyRefreshToken` require an `exp` claim** (since 4.12.0) and reject a token without one. There is no deadline to check on such a token, so verification would otherwise succeed indefinitely. `requiredClaims` is additive — `jwt.verify(token, { requiredClaims: ["iat"] })` requires `iat` **and** `exp`; you cannot opt out of `exp`. If you want a token that effectively never expires, use `expiresIn: NO_EXPIRATION` (`"100y"`), which stamps a real `exp` about a century out.
177
177
 
178
- If tokens minted before 4.12.0 may lack an `exp`, see `warlock auth.purge-never-expiring` in [`@warlock.js/auth/run-auth-commands/SKILL.md`](@warlock.js/auth/run-auth-commands/SKILL.md) — they are still in your token tables and no date-based cleanup can reach them.
178
+ If tokens minted before 4.12.0 may lack an `exp`, see `warlock auth.purge-never-expiring` in the `run-auth-commands` topic — they are still in your token tables and no date-based cleanup can reach them.
179
179
 
180
180
  `authService.generateAccessToken` / `createRefreshToken` read `config.auth.accessToken.expiresIn` / `config.auth.refreshToken.expiresIn`, validate them, and throw naming the key if the value is not a positive `ms` duration — before anything is signed, persisted, or capped.
181
181
 
@@ -191,6 +191,6 @@ The package signs access and refresh tokens with independent secrets — `config
191
191
 
192
192
  ## See also
193
193
 
194
- - [`@warlock.js/auth/handle-login-and-logout/SKILL.md`](@warlock.js/auth/handle-login-and-logout/SKILL.md) — full login/logout flow that uses these primitives
195
- - [`@warlock.js/auth/run-auth-commands/SKILL.md`](@warlock.js/auth/run-auth-commands/SKILL.md) — the bundled cleanup command
196
- - [`@warlock.js/scheduler/scheduler-basics/SKILL.md`](@warlock.js/scheduler/scheduler-basics/SKILL.md) — scheduling cleanup
194
+ - The `handle-login-and-logout` topic — full login/logout flow that uses these primitives
195
+ - The `run-auth-commands` topic — the bundled cleanup command
196
+ - The `scheduler-basics` topic of the `warlock-js-scheduler` skill — scheduling cleanup
@@ -29,35 +29,35 @@ Nine task skills. Most apps need `auth-basics` + `protect-routes` + `handle-logi
29
29
 
30
30
  ### Foundations
31
31
 
32
- #### [`auth-basics`](@warlock.js/auth/auth-basics/SKILL.md)
32
+ #### `auth-basics`
33
33
  Start here. The `Auth` base model, `authMiddleware` gate, `authService` (login/logout/refresh), AccessToken + RefreshToken persistence, multi-user-type support.
34
34
 
35
35
  ### The flows
36
36
 
37
- #### [`handle-login-and-logout`](@warlock.js/auth/handle-login-and-logout/SKILL.md)
37
+ #### `handle-login-and-logout`
38
38
  `authService.login(Model, credentials, deviceInfo?)` — verify password, issue the token pair, fire events. `authService.logout(user, accessToken?, refreshToken?)` — revoke tokens. For your `POST /login` and `POST /logout` controllers.
39
39
 
40
- #### [`register-user`](@warlock.js/auth/register-user/SKILL.md)
40
+ #### `register-user`
41
41
  Sign up a new user and issue the first token pair — `User.create({ ...password: await hashPassword(plain) })` then `authService.createTokenPair(user)`. For `POST /register`.
42
42
 
43
- #### [`protect-routes`](@warlock.js/auth/protect-routes/SKILL.md)
43
+ #### `protect-routes`
44
44
  `authMiddleware` object and legacy overloads: typed/default hard gates, optional resolution, credential source, and page-local redirects. Sets `request.locals.user` + `request.decodedAccessToken` when a user resolves.
45
45
 
46
46
  ### Going deeper
47
47
 
48
- #### [`manage-tokens`](@warlock.js/auth/manage-tokens/SKILL.md)
48
+ #### `manage-tokens`
49
49
  The token lifecycle — `generateAccessToken`, `createRefreshToken`, `createTokenPair`, `refreshTokens` (rotation + replay detection), `revokeAllTokens`, `revokeTokenFamily`, `cleanupExpiredTokens`, `getActiveSessions`. For custom login/registration, token revocation, "logout everywhere", and scheduled cleanup.
50
50
 
51
- #### [`customize-user-type`](@warlock.js/auth/customize-user-type/SKILL.md)
51
+ #### `customize-user-type`
52
52
  Support multiple user types in one system — each `Auth` subclass overrides `userType`, `config.auth.userType.<slug>` maps the slug to a model class, `authMiddleware("admin")` / `authMiddleware(["admin", "staff"])` gates per type.
53
53
 
54
- #### [`customize-token-storage`](@warlock.js/auth/customize-token-storage/SKILL.md)
54
+ #### `customize-token-storage`
55
55
  Override the persisted `AccessToken` / `RefreshToken` models to add columns (multi-tenant `organization_id`), rename, or change storage — extend the model + schema and register it under `config.auth.accessToken.model` / `config.auth.refreshToken.model`.
56
56
 
57
- #### [`throttle-login-attempts`](@warlock.js/auth/throttle-login-attempts/SKILL.md)
57
+ #### `throttle-login-attempts`
58
58
  Brute-force / credential-stuffing protection — `loginThrottleMiddleware()` counts only failed logins, resets on success, locks per-account + per-IP after a threshold, and rejects pre-controller with 429. Cache-backed, fails open on a cache outage.
59
59
 
60
- #### [`run-auth-commands`](@warlock.js/auth/run-auth-commands/SKILL.md)
60
+ #### `run-auth-commands`
61
61
  Two CLI commands — `warlock jwt.generate` (strong JWT secret → `.env`) and `warlock auth.cleanup` (remove expired refresh tokens). Register via `registerJWTSecretGeneratorCommand()` and `registerAuthCleanupCommand()`.
62
62
 
63
63
  ## What this package deliberately doesn't do
@@ -69,6 +69,6 @@ Two CLI commands — `warlock jwt.generate` (strong JWT secret → `.env`) and `
69
69
 
70
70
  ## See also
71
71
 
72
- - [`@warlock.js/core/warlock-conventions/SKILL.md`](@warlock.js/core/warlock-conventions/SKILL.md) — the framework auth runs inside (routing, middleware, config).
73
- - [`@warlock.js/cascade/cascade-basics/SKILL.md`](@warlock.js/cascade/cascade-basics/SKILL.md) — the ORM behind the `Auth`, `AccessToken`, and `RefreshToken` models.
74
- - `mongez-agent-kit-authoring-skills` (load via agent-kit sync) — how this `overview/SKILL.md` becomes `.claude/skills/warlock-js-auth-overview/`.
72
+ - The `warlock-conventions` topic of the `warlock-js-core` skill — the framework auth runs inside (routing, middleware, config).
73
+ - The `cascade-basics` topic of the `warlock-js-cascade` skill — the ORM behind the `Auth`, `AccessToken`, and `RefreshToken` models.
74
+ - `mongez-agent-kit-authoring-skills` (load via agent-kit sync) — how this `overview` topic becomes `.claude/skills/warlock-js-auth/overview.md`.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: protect-routes
3
- description: 'Gate HTTP routes via authMiddleware(allowedUserType) — the argument is required and a valid token is always required: [] allows any authenticated user, a user-type restricts to those types. Sets request.locals.user + request.decodedAccessToken on success, 401 on failure. Triggers: `authMiddleware`, `request.locals.user`, `request.decodedAccessToken`, `AuthErrorCodes`, `MissingAccessToken`, `InvalidAccessToken`; "how do I protect a route", "restrict route by user type", "require any logged-in user"; typical import `import { authMiddleware } from "@warlock.js/auth"`. Skip: multi-user-type config — `@warlock.js/auth/customize-user-type/SKILL.md`; issuing the token — `@warlock.js/auth/handle-login-and-logout/SKILL.md`; competing libs `passport`, `express-jwt`, `next-auth` middleware.'
3
+ description: 'Gate HTTP routes via authMiddleware(allowedUserType) — the argument is required and a valid token is always required: [] allows any authenticated user, a user-type restricts to those types. Sets request.locals.user + request.decodedAccessToken on success, 401 on failure. Triggers: `authMiddleware`, `request.locals.user`, `request.decodedAccessToken`, `AuthErrorCodes`, `MissingAccessToken`, `InvalidAccessToken`; "how do I protect a route", "restrict route by user type", "require any logged-in user"; typical import `import { authMiddleware } from "@warlock.js/auth"`. Skip: multi-user-type config — the `customize-user-type` topic; issuing the token — the `handle-login-and-logout` topic; competing libs `passport`, `express-jwt`, `next-auth` middleware.'
4
4
  ---
5
5
 
6
6
  # Gate routes with `authMiddleware`
@@ -49,7 +49,7 @@ router.get("/staff", staffController, {
49
49
  });
50
50
  ```
51
51
 
52
- The `userType` slug must match a key in `config.auth.userType.<name>` — see [`@warlock.js/auth/customize-user-type/SKILL.md`](@warlock.js/auth/customize-user-type/SKILL.md).
52
+ The `userType` slug must match a key in `config.auth.userType.<name>` — see the `customize-user-type` topic.
53
53
 
54
54
  ## What the middleware does
55
55
 
@@ -172,7 +172,7 @@ The middleware uses the framework's `response.unauthorized({...})` shape. To ove
172
172
 
173
173
  That last one is the difference between a role check and an authorization model: without it, an account-creation endpoint gated on `authMiddleware("admin")` is a privilege-escalation path.
174
174
 
175
- Install [`@warlock.js/access`](@warlock.js/access/overview/SKILL.md) for that. It layers RBAC plus per-permission ABAC policies over the same authenticated user:
175
+ Install `@warlock.js/access` (the `overview` topic of the `warlock-js-access` skill) for that. It layers RBAC plus per-permission ABAC policies over the same authenticated user:
176
176
 
177
177
  ```ts
178
178
  import { router, type RequestHandler } from "@warlock.js/core";
@@ -297,7 +297,7 @@ This is an Origin check, not a double-submit CSRF token — cheaper, and closes
297
297
 
298
298
  ## See also
299
299
 
300
- - [`@warlock.js/auth/customize-user-type/SKILL.md`](@warlock.js/auth/customize-user-type/SKILL.md) — config and multi-user-type semantics
301
- - [`@warlock.js/auth/handle-login-and-logout/SKILL.md`](@warlock.js/auth/handle-login-and-logout/SKILL.md) — where the access token gets issued in the first place
302
- - [`@warlock.js/auth/throttle-login-attempts/SKILL.md`](@warlock.js/auth/throttle-login-attempts/SKILL.md) — brute-force throttle to stack in front of the login route
303
- - [`@warlock.js/access/overview/SKILL.md`](@warlock.js/access/overview/SKILL.md) — permissions, roles, and who-may-act-on-whom policies, when user-type gating isn't enough
300
+ - The `customize-user-type` topic — config and multi-user-type semantics
301
+ - The `handle-login-and-logout` topic — where the access token gets issued in the first place
302
+ - The `throttle-login-attempts` topic — brute-force throttle to stack in front of the login route
303
+ - The `overview` topic of the `warlock-js-access` skill — permissions, roles, and who-may-act-on-whom policies, when user-type gating isn't enough
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: register-user
3
- description: 'Sign up a new user and issue the initial token pair — User.create({...password: await hashPassword(plain)}) then authService.createTokenPair(user). Triggers: `User.create`, `hashPassword`, `verifyPassword`, `authService.createTokenPair`, `toJsonColumns`, `strongPassword`, `authEvents`; "build a register endpoint", "POST /register controller", "sign up a new user", "hash password on signup", "email verification flow"; typical import `import { authService } from "@warlock.js/auth"; import { hashPassword } from "@warlock.js/core"`. Skip: login — `@warlock.js/auth/handle-login-and-logout/SKILL.md`; token internals — `@warlock.js/auth/manage-tokens/SKILL.md`; competing libs `bcrypt`, `bcryptjs`, `argon2`.'
3
+ description: 'Sign up a new user and issue the initial token pair — User.create({...password: await hashPassword(plain)}) then authService.createTokenPair(user). Triggers: `User.create`, `hashPassword`, `verifyPassword`, `authService.createTokenPair`, `toJsonColumns`, `strongPassword`, `authEvents`; "build a register endpoint", "POST /register controller", "sign up a new user", "hash password on signup", "email verification flow"; typical import `import { authService } from "@warlock.js/auth"; import { hashPassword } from "@warlock.js/core"`. Skip: login — the `handle-login-and-logout` topic; token internals — the `manage-tokens` topic; competing libs `bcrypt`, `bcryptjs`, `argon2`.'
4
4
  ---
5
5
 
6
6
  # Register-and-issue-tokens flow
@@ -58,7 +58,7 @@ export const registerController: RequestHandler = async ({ request, response })
58
58
  };
59
59
  ```
60
60
 
61
- That's the whole flow. `User.create({...})` runs the schema validation (including `.email()`, `.min()`, etc. on each field), so you don't need a separate validation pass — see [`@warlock.js/seal/handle-seal-errors/SKILL.md`](@warlock.js/seal/handle-seal-errors/SKILL.md) for catching validation failures.
61
+ That's the whole flow. `User.create({...})` runs the schema validation (including `.email()`, `.min()`, etc. on each field), so you don't need a separate validation pass — see the `handle-seal-errors` topic of the `warlock-js-seal` skill for catching validation failures.
62
62
 
63
63
  ## Hash the password on the way in
64
64
 
@@ -114,7 +114,7 @@ const tokens = await authService.createTokenPair(user);
114
114
  return response.successCreate({ user, tokens });
115
115
  ```
116
116
 
117
- Gate routes that need a confirmed address with `requireVerifiedEmail()` after `authMiddleware`. See [`@warlock.js/auth/verify-email-and-reset-password/SKILL.md`](@warlock.js/auth/verify-email-and-reset-password/SKILL.md).
117
+ Gate routes that need a confirmed address with `requireVerifiedEmail()` after `authMiddleware`. See the `verify-email-and-reset-password` topic.
118
118
 
119
119
  ## Side effects via auth events
120
120
 
@@ -138,10 +138,10 @@ Cleaner alternative: emit your own `user.registered` event from the controller a
138
138
  - Don't pass the plain password to `User.create()`. `await hashPassword(plain)` first.
139
139
  - Don't return the user without `toJsonColumns` / `resource` shaping — the password hash will leak otherwise.
140
140
  - Don't issue tokens before validating the user shape. `User.create` runs validation; let it throw on bad input before tokens get created.
141
- - Don't run "send welcome email" inline in the controller. Push it to a queue or run it after-commit via the outbox pattern — see [`@warlock.js/cascade/manage-transactions/SKILL.md`](@warlock.js/cascade/manage-transactions/SKILL.md).
141
+ - Don't run "send welcome email" inline in the controller. Push it to a queue or run it after-commit via the outbox pattern — see the `manage-transactions` topic of the `warlock-js-cascade` skill.
142
142
 
143
143
  ## See also
144
144
 
145
- - [`@warlock.js/auth/handle-login-and-logout/SKILL.md`](@warlock.js/auth/handle-login-and-logout/SKILL.md) — login flow (same `createTokenPair` step)
146
- - [`@warlock.js/auth/manage-tokens/SKILL.md`](@warlock.js/auth/manage-tokens/SKILL.md) — token issuance internals
147
- - [`@warlock.js/cascade/define-model/SKILL.md`](@warlock.js/cascade/define-model/SKILL.md) — `toJsonColumns` / `resource` for public output
145
+ - The `handle-login-and-logout` topic — login flow (same `createTokenPair` step)
146
+ - The `manage-tokens` topic — token issuance internals
147
+ - The `define-model` topic of the `warlock-js-cascade` skill — `toJsonColumns` / `resource` for public output
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: run-auth-commands
3
- description: 'Three bundled CLI commands — warlock jwt.generate (creates strong JWT secret + writes to .env), warlock auth.cleanup (removes expired refresh tokens), and warlock auth.purge-never-expiring (finds and revokes token rows that can never expire). Register via registerJWTSecretGeneratorCommand(), registerAuthCleanupCommand() and registerAuthPurgeNeverExpiringCommand(). Triggers: `registerJWTSecretGeneratorCommand`, `registerAuthCleanupCommand`, `registerAuthPurgeNeverExpiringCommand`, `warlock jwt.generate`, `warlock auth.cleanup`, `warlock auth.purge-never-expiring`, `cleanupExpiredTokens`, `purgeNeverExpiringTokens`, `command`; "token never expires", "no exp claim", "Invalid Date expires_at"; "generate JWT secret", "bootstrap .env JWT_SECRET", "cron job for expired tokens", "schedule auth cleanup"; typical import `import { registerJWTSecretGeneratorCommand, registerAuthCleanupCommand, registerAuthPurgeNeverExpiringCommand } from "@warlock.js/auth"`. Skip: programmatic cleanup — `@warlock.js/auth/manage-tokens/SKILL.md`; in-process scheduling — `@warlock.js/scheduler/scheduler-basics/SKILL.md`; competing tools `dotenv-cli`, `node-cron`.'
3
+ description: 'Three bundled CLI commands — warlock jwt.generate (creates strong JWT secret + writes to .env), warlock auth.cleanup (removes expired refresh tokens), and warlock auth.purge-never-expiring (finds and revokes token rows that can never expire). Register via registerJWTSecretGeneratorCommand(), registerAuthCleanupCommand() and registerAuthPurgeNeverExpiringCommand(). Triggers: `registerJWTSecretGeneratorCommand`, `registerAuthCleanupCommand`, `registerAuthPurgeNeverExpiringCommand`, `warlock jwt.generate`, `warlock auth.cleanup`, `warlock auth.purge-never-expiring`, `cleanupExpiredTokens`, `purgeNeverExpiringTokens`, `command`; "token never expires", "no exp claim", "Invalid Date expires_at"; "generate JWT secret", "bootstrap .env JWT_SECRET", "cron job for expired tokens", "schedule auth cleanup"; typical import `import { registerJWTSecretGeneratorCommand, registerAuthCleanupCommand, registerAuthPurgeNeverExpiringCommand } from "@warlock.js/auth"`. Skip: programmatic cleanup — the `manage-tokens` topic; in-process scheduling — the `scheduler-basics` topic of the `warlock-js-scheduler` skill; competing tools `dotenv-cli`, `node-cron`.'
4
4
  ---
5
5
 
6
6
  # Run auth commands
@@ -66,7 +66,7 @@ scheduler.addJob(
66
66
  scheduler.start();
67
67
  ```
68
68
 
69
- In-process — no shell call. See [`@warlock.js/scheduler/scheduler-basics/SKILL.md`](@warlock.js/scheduler/scheduler-basics/SKILL.md).
69
+ In-process — no shell call. See the `scheduler-basics` topic of the `warlock-js-scheduler` skill.
70
70
 
71
71
  ### Via system cron
72
72
 
@@ -155,5 +155,5 @@ Register it the same way as the bundled commands — call the factory inside `de
155
155
 
156
156
  ## See also
157
157
 
158
- - [`@warlock.js/auth/manage-tokens/SKILL.md`](@warlock.js/auth/manage-tokens/SKILL.md) — `cleanupExpiredTokens` internals
159
- - [`@warlock.js/scheduler/scheduler-basics/SKILL.md`](@warlock.js/scheduler/scheduler-basics/SKILL.md) — in-process scheduling
158
+ - The `manage-tokens` topic — `cleanupExpiredTokens` internals
159
+ - The `scheduler-basics` topic of the `warlock-js-scheduler` skill — in-process scheduling
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: throttle-login-attempts
3
- description: 'Brute-force / credential-stuffing protection via `loginThrottleMiddleware` — a failure-aware route gate that counts only failed logins (resets on success), locks per-account and per-source after a threshold, and rejects pre-controller with 429 so the DB lookup and bcrypt verify are skipped. Cache-backed (shared across replicas), fixed-window, fails open on a cache outage. Triggers: `loginThrottleMiddleware`, `AuthErrorCodes.TooManyAttempts`, `EC004`, "rate limit login", "brute force protection", "lock account after failed logins", "throttle login attempts", "too many login attempts 429"; typical import `import { loginThrottleMiddleware } from "@warlock.js/auth"`. Skip: generic per-route request rate limiting that counts every request (use core `middleware.rateLimit`); gating a route by auth — `@warlock.js/auth/protect-routes/SKILL.md`; issuing tokens — `@warlock.js/auth/handle-login-and-logout/SKILL.md`.'
3
+ description: 'Brute-force / credential-stuffing protection via `loginThrottleMiddleware` — a failure-aware route gate that counts only failed logins (resets on success), locks per-account and per-source after a threshold, and rejects pre-controller with 429 so the DB lookup and bcrypt verify are skipped. Cache-backed (shared across replicas), fixed-window, fails open on a cache outage. Triggers: `loginThrottleMiddleware`, `AuthErrorCodes.TooManyAttempts`, `EC004`, "rate limit login", "brute force protection", "lock account after failed logins", "throttle login attempts", "too many login attempts 429"; typical import `import { loginThrottleMiddleware } from "@warlock.js/auth"`. Skip: generic per-route request rate limiting that counts every request (use core `middleware.rateLimit`); gating a route by auth — the `protect-routes` topic; issuing tokens — the `handle-login-and-logout` topic.'
4
4
  ---
5
5
 
6
6
  # Throttle login attempts with `loginThrottleMiddleware`
@@ -106,12 +106,14 @@ They compose. For a hard ceiling on request volume *and* failure-aware account l
106
106
  - **Needs an initialised cache driver.** Storage is `@warlock.js/cache` (a peer dep, transitively present via core). If the driver isn't configured at runtime, the middleware **fails open** — it logs and lets the request through, because a throttle outage must never become an auth outage. That also means: no cache, no protection. Verify your cache config in production.
107
107
  - **Account lockout can be weaponised.** An attacker who knows a victim's email can lock them out by spamming failures. The per-IP counter mitigates this (the attacker's IP locks too), but for purely anonymous endpoints prefer `by: ["ip"]`. For high-value accounts, consider a CAPTCHA step instead of a hard lock.
108
108
  - **Counts are atomic and exact across servers (redis/pg).** Each failure does a create-only `cache.set(key, 0, { ttl: window })` (only the first failure opens the window and sets the TTL) followed by an atomic `cache.increment(key)`, so concurrent failures on different servers are never lost. The memory cache driver is per-process — counts and locks are then per-process, so use redis/pg when running more than one instance.
109
- - **Fixed window, not sliding.** The window is anchored at the first failure and does not extend on each subsequent one — predictable lockout timing. The lock key is independent and always lasts `lockoutDuration`.
109
+ - **Account and IP keys are hashed.** The built-in extractor keys both by an HMAC of the trimmed, lower-cased value (`email.<hmac>`, `ip.<hmac>`), keyed from `auth.accessToken.secret`, so cache logs never show the address or IP and a list of known emails cannot reverse the key. Without a configured secret it falls back to SHA-256. A custom `identify` is used as is — hash personal values yourself (`throttleIdentifierHash(kind, value)` is exported).
110
+ - **Fixed window, not sliding.** The window is anchored at the first failure and does not extend on each subsequent one — predictable lockout timing. The lock key is independent and always lasts `lockoutDuration`: the lock stores its own deadline, so even a sliding-expiry driver (`memoryExtended`) cannot extend it.
111
+ - **Needs a real cache driver.** The `null` driver stores nothing, so the throttle never locks; it warns once when that happens. On Redis, any version from 6 works.
110
112
  - **Defense-in-depth, not a WAF.** This is application-layer. It won't stop a volumetric L3/L4 flood — pair it with an edge/CDN rate limit for that.
111
113
  - **Don't call it per-request.** Like every middleware, call it once at route definition; it returns the function that runs per request.
112
114
 
113
115
  ## See also
114
116
 
115
- - [`@warlock.js/auth/protect-routes/SKILL.md`](@warlock.js/auth/protect-routes/SKILL.md) — gate a route behind a valid token (`authMiddleware`); stack the throttle in front of it on login routes.
116
- - [`@warlock.js/auth/handle-login-and-logout/SKILL.md`](@warlock.js/auth/handle-login-and-logout/SKILL.md) — the login flow whose failures this middleware counts.
117
- - [`@warlock.js/core/use-middleware/SKILL.md`](@warlock.js/core/use-middleware/SKILL.md) — `middleware.rateLimit` and the built-in middleware suite.
117
+ - The `protect-routes` topic — gate a route behind a valid token (`authMiddleware`); stack the throttle in front of it on login routes.
118
+ - The `handle-login-and-logout` topic — the login flow whose failures this middleware counts.
119
+ - The `use-middleware` topic of the `warlock-js-core` skill — `middleware.rateLimit` and the built-in middleware suite.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: verify-email-and-reset-password
3
- description: 'Email verification and password reset with hashed, single-use, expiring, purpose-bound tokens delivered through `@warlock.js/notifications` — `sendEmailVerification(user)`, `verifyEmail(token)`, `requestPasswordReset(Model, email)`, `resetPassword(token, newPassword)`, the `requireVerifiedEmail()` guard, and the `tokenIssueThrottleMiddleware` / `tokenConsumeThrottleMiddleware` presets. Reset revokes every access token, refresh token and cookie session; a reset request answers the same for unknown emails. Triggers: `sendEmailVerification`, `verifyEmail`, `requestPasswordReset`, `resetPassword`, `requireVerifiedEmail`, `isEmailVerified`, `OneTimeToken`, `InvalidOneTimeTokenError`, `EmailNotVerifiedError`, `NotificationsUnavailableError`, `EC007`, `EC008`, `auth.verification`, `auth.passwordReset`; "verify email", "confirm email address", "forgot password", "reset password link", "block unverified users", "resend verification email"; typical import `import { requestPasswordReset, resetPassword } from "@warlock.js/auth"`. Skip: sign-up itself — `@warlock.js/auth/register-user/SKILL.md`; login throttling — `@warlock.js/auth/throttle-login-attempts/SKILL.md`; defining notifications — `@warlock.js/notifications/define-notification/SKILL.md`.'
3
+ description: 'Email verification and password reset with hashed, single-use, expiring, purpose-bound tokens delivered through `@warlock.js/notifications` — `sendEmailVerification(user)`, `verifyEmail(token)`, `requestPasswordReset(Model, email)`, `resetPassword(token, newPassword)`, the `requireVerifiedEmail()` guard, and the `tokenIssueThrottleMiddleware` / `tokenConsumeThrottleMiddleware` presets. Reset revokes every access token, refresh token and cookie session; a reset request answers the same for unknown emails. Triggers: `sendEmailVerification`, `verifyEmail`, `requestPasswordReset`, `resetPassword`, `requireVerifiedEmail`, `isEmailVerified`, `OneTimeToken`, `InvalidOneTimeTokenError`, `EmailNotVerifiedError`, `NotificationsUnavailableError`, `EC007`, `EC008`, `auth.verification`, `auth.passwordReset`; "verify email", "confirm email address", "forgot password", "reset password link", "block unverified users", "resend verification email"; typical import `import { requestPasswordReset, resetPassword } from "@warlock.js/auth"`. Skip: sign-up itself — the `register-user` topic; login throttling — the `throttle-login-attempts` topic; defining notifications — the `define-notification` topic of the `warlock-js-notifications` skill.'
4
4
  ---
5
5
 
6
6
  # Verify email + reset password
@@ -132,6 +132,6 @@ The default notifications are `defineNotification` objects (`type: "auth.email-v
132
132
 
133
133
  ## See also
134
134
 
135
- - [`@warlock.js/auth/register-user/SKILL.md`](@warlock.js/auth/register-user/SKILL.md) — where `sendEmailVerification` is usually called
136
- - [`@warlock.js/auth/throttle-login-attempts/SKILL.md`](@warlock.js/auth/throttle-login-attempts/SKILL.md) — the underlying throttle
137
- - [`@warlock.js/notifications/configure-notifications/SKILL.md`](@warlock.js/notifications/configure-notifications/SKILL.md) — mail channel setup
135
+ - The `register-user` topic — where `sendEmailVerification` is usually called
136
+ - The `throttle-login-attempts` topic — the underlying throttle
137
+ - The `configure-notifications` topic of the `warlock-js-notifications` skill — mail channel setup