rst-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 (77) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/CODE_OF_CONDUCT.md +73 -0
  3. package/CONTRIBUTING.md +35 -0
  4. package/LICENSE +21 -0
  5. package/README.md +307 -2
  6. package/SECURITY.md +13 -0
  7. package/dist/accounts.d.ts +41 -0
  8. package/dist/accounts.d.ts.map +1 -0
  9. package/dist/accounts.js +169 -0
  10. package/dist/accounts.js.map +1 -0
  11. package/dist/config.d.ts +63 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +196 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/errors.d.ts +16 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +57 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/express/index.d.ts +74 -0
  20. package/dist/express/index.d.ts.map +1 -0
  21. package/dist/express/index.js +185 -0
  22. package/dist/express/index.js.map +1 -0
  23. package/dist/index.d.ts +24 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +27 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/memory-refresh-token-store.d.ts +15 -0
  28. package/dist/memory-refresh-token-store.d.ts.map +1 -0
  29. package/dist/memory-refresh-token-store.js +75 -0
  30. package/dist/memory-refresh-token-store.js.map +1 -0
  31. package/dist/password.d.ts +7 -0
  32. package/dist/password.d.ts.map +1 -0
  33. package/dist/password.js +36 -0
  34. package/dist/password.js.map +1 -0
  35. package/dist/refresh-store.d.ts +48 -0
  36. package/dist/refresh-store.d.ts.map +1 -0
  37. package/dist/refresh-store.js +2 -0
  38. package/dist/refresh-store.js.map +1 -0
  39. package/dist/refresh.d.ts +27 -0
  40. package/dist/refresh.d.ts.map +1 -0
  41. package/dist/refresh.js +93 -0
  42. package/dist/refresh.js.map +1 -0
  43. package/dist/testing/index.d.ts +3 -0
  44. package/dist/testing/index.d.ts.map +1 -0
  45. package/dist/testing/index.js +2 -0
  46. package/dist/testing/index.js.map +1 -0
  47. package/dist/testing/refresh-store-conformance.d.ts +11 -0
  48. package/dist/testing/refresh-store-conformance.d.ts.map +1 -0
  49. package/dist/testing/refresh-store-conformance.js +110 -0
  50. package/dist/testing/refresh-store-conformance.js.map +1 -0
  51. package/dist/tokens.d.ts +15 -0
  52. package/dist/tokens.d.ts.map +1 -0
  53. package/dist/tokens.js +90 -0
  54. package/dist/tokens.js.map +1 -0
  55. package/dist/validation.d.ts +7 -0
  56. package/dist/validation.d.ts.map +1 -0
  57. package/dist/validation.js +2 -0
  58. package/dist/validation.js.map +1 -0
  59. package/dist/zod/index.d.ts +5 -0
  60. package/dist/zod/index.d.ts.map +1 -0
  61. package/dist/zod/index.js +22 -0
  62. package/dist/zod/index.js.map +1 -0
  63. package/docs/access-tokens.md +15 -0
  64. package/docs/accounts.md +68 -0
  65. package/docs/before-first-release.md +31 -0
  66. package/docs/claims.md +42 -0
  67. package/docs/configuration.md +38 -0
  68. package/docs/cookies-vs-bearer.md +82 -0
  69. package/docs/error-handling.md +15 -0
  70. package/docs/installation.md +39 -0
  71. package/docs/middleware.md +24 -0
  72. package/docs/migration.md +17 -0
  73. package/docs/passwords.md +23 -0
  74. package/docs/refresh-tokens.md +47 -0
  75. package/docs/security.md +16 -0
  76. package/docs/validation.md +24 -0
  77. package/package.json +91 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ Notable changes to rst-auth are recorded here.
4
+
5
+ ## Unreleased
6
+
7
+ - Added optional `auth.accounts.register()` and `auth.accounts.login()` helpers that use an app-provided model and lookup callback while keeping database ownership in the app.
8
+ - Bumped package metadata to 0.2.0 for the expanded API; existing low-level password, token, and refresh APIs remain available.
9
+ - Added a standalone HTML/CSS/JavaScript documentation site and GitHub Pages deployment workflow.
10
+ - Added a browser-based auth flow demo to the Express example.
11
+ - Added a TypeScript Express API example that is installed from an npm pack tarball.
12
+ - Added usage, security, migration, contribution, reporting, and first-release documentation.
13
+ - Added Node 22/24 CI checks and example integration tests.
14
+
15
+ ## 0.1.0 - 2026-10-16
16
+
17
+ - Initial alpha API for password hashing, access tokens, and opaque refresh-token rotation.
18
+ - Added Express 4/5 and Zod subpath adapters plus refresh-store conformance utilities.
@@ -0,0 +1,73 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ - Demonstrating empathy and kindness toward other people.
14
+ - Being respectful of differing opinions, viewpoints, and experiences.
15
+ - Giving and gracefully accepting constructive feedback.
16
+ - Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience.
17
+ - Focusing on what is best not just for us as individuals, but for the overall community.
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ - The use of sexualized language or imagery, and sexual attention or advances of any kind.
22
+ - Trolling, insulting or derogatory comments, and personal or political attacks.
23
+ - Public or private harassment.
24
+ - Publishing others' private information, such as a physical or email address, without their explicit permission.
25
+ - Other conduct which could reasonably be considered inappropriate in a professional setting.
26
+
27
+ ## Enforcement Responsibilities
28
+
29
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
32
+
33
+ ## Scope
34
+
35
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
36
+
37
+ ## Enforcement
38
+
39
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at the private contact route listed in the repository's `SECURITY.md` or repository moderation settings. All complaints will be reviewed and investigated promptly and fairly.
40
+
41
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
42
+
43
+ ## Enforcement Guidelines
44
+
45
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
46
+
47
+ ### 1. Correction
48
+
49
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
50
+
51
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
52
+
53
+ ### 2. Warning
54
+
55
+ **Community Impact**: A violation through a single incident or series of actions.
56
+
57
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period. This includes avoiding interactions in community spaces, as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
58
+
59
+ ### 3. Temporary Ban
60
+
61
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
62
+
63
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
64
+
65
+ ### 4. Permanent Ban
66
+
67
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
68
+
69
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
70
+
71
+ ## Attribution
72
+
73
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
@@ -0,0 +1,35 @@
1
+ # Contributing
2
+
3
+ Thanks for helping improve rst-auth. The project is alpha software and prioritizes clear security boundaries, small APIs, and honest documentation.
4
+
5
+ ## Before opening a change
6
+
7
+ - Read the relevant design and security documentation in `docs/` before changing behavior.
8
+ - Keep user models, DB queries, routes, controllers, and business rules in the application layer.
9
+ - Do not add real credentials, publish packages, or push directly to the upstream default branch. Use a fork and pull request; do not claim production readiness.
10
+ - Every security or feature claim in README must map to a named test in `docs/claims.md`.
11
+ - Never accept a client-supplied privilege or role during signup.
12
+
13
+ ## Development checks
14
+
15
+ Use Node 22 or 24 and npm. From the repository root run:
16
+
17
+ ```sh
18
+ npm ci
19
+ npm run build
20
+ npm test
21
+ npm run lint
22
+ npm run typecheck
23
+ npm run format:check
24
+ npm pack --dry-run
25
+ npm run example:install
26
+ npm --prefix examples/express-api run typecheck
27
+ npm --prefix examples/express-api test
28
+ npm --prefix examples/express-api run import-check
29
+ ```
30
+
31
+ The example install command packs this project and installs the generated tarball into the example. Do not change the example to import source files from `src/`.
32
+
33
+ ## Pull requests
34
+
35
+ Explain the user-visible behavior, security consequences, tests, docs, and compatibility impact. Include focused tests for bug fixes and new claims. Keep PRs small enough to review. Maintainers may request changes or decline work outside the project scope. By contributing, you agree to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sayed Risat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,308 @@
1
- # Temporary Holding Version
1
+ # RST-Auth
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ <p align="center">
4
+ <a href="https://www.npmjs.com/package/rst-auth"><img alt="npm version" src="https://img.shields.io/npm/v/rst-auth?color=4c8bf5&label=npm"></a>
5
+ <a href="https://github.com/sayedrisat/rst-auth/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/sayedrisat/rst-auth/ci.yml?branch=main&label=CI"></a>
6
+ <img alt="Node.js 22+" src="https://img.shields.io/badge/Node.js-22%2B-43853d">
7
+ <a href="LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
8
+ </p>
9
+
10
+ <p align="center">
11
+ <a href="https://sayedrisat.github.io/rst-auth/">Documentation</a> ·
12
+ <a href="https://github.com/sayedrisat/rst-auth">GitHub</a> ·
13
+ <a href="https://www.npmjs.com/package/rst-auth">npm</a> ·
14
+ <a href="examples/express-api/">Runnable Express example</a>
15
+ </p>
16
+
17
+ > **Complex authentication. Simple methods. Full control. Open source.**
18
+
19
+ RST-Auth is a small set of authentication building blocks for Node.js. It handles reusable security mechanics; **your app keeps its users, database, routes, business rules, and API responses.**
20
+
21
+ | Your app owns | RST-Auth provides |
22
+ | ---------------------------------------------------- | ---------------------------------------------------------- |
23
+ | User records, DB queries, signup/login controllers | Password hashing and verification with `bcryptjs` |
24
+ | Roles, permissions, and business decisions | Signed access tokens and optional Express middleware |
25
+ | API response shapes, frontend, and account lifecycle | Stateful refresh rotation through your `RefreshTokenStore` |
26
+
27
+ > **Project status:** `0.1.0` alpha. The API may change. This project is not a security audit or a claim of production readiness.
28
+
29
+ ## Authentication flow
30
+
31
+ This overview shows where the package fits. The application connects its own user repository and persistent refresh-token store; RST-Auth does not query the user database.
32
+
33
+ ```mermaid
34
+ flowchart LR
35
+ client[Browser or API client]
36
+ app[Your app<br/>routes, controllers, policy]
37
+ auth[RST-Auth<br/>bcryptjs · jose · refresh service]
38
+ users[(Your user database)]
39
+ store[(Your atomic RefreshTokenStore)]
40
+
41
+ client -->|signup / login| app
42
+ app <-->|lookup user · save password hash| users
43
+ app -->|hash / verify · sign access token| auth
44
+ auth -->|opaque token hash · atomic consume| store
45
+ auth -->|access token + refresh token result| app
46
+ app -->|Bearer token or HttpOnly cookie| client
47
+ client -->|protected request| app
48
+ app -->|verify access token| auth
49
+ ```
50
+
51
+ During refresh, the store atomically consumes the presented token hash. A successful rotation issues a successor in the same family; replay revokes that family. See the [end-to-end flow in the docs](https://sayedrisat.github.io/rst-auth/#flow) for the walkthrough and token-delivery trade-offs.
52
+
53
+ <details>
54
+ <summary>Contents</summary>
55
+
56
+ - [Overview and features](#overview)
57
+ - [Install](#install)
58
+ - [Minimal setup](#minimal-setup)
59
+ - [Passwords](#passwords)
60
+ - [Access tokens](#access-tokens)
61
+ - [Refresh tokens](#refresh-tokens)
62
+ - [Express middleware and validation](#express-middleware)
63
+ - [Configuration](#configuration-reference)
64
+ - [Database integration and limitations](#database-integration-model)
65
+ - [Testing and contributing](#testing)
66
+ - [Comparison](#comparison)
67
+
68
+ </details>
69
+
70
+ ## Overview
71
+
72
+ `RST-Auth` is an alpha TypeScript toolkit for Node.js 22+ applications. It provides password hashing, access tokens, stateful refresh-token rotation, and optional Express and Zod adapters. Your application owns its users, database, routes, business rules, and responses.
73
+
74
+ ## Problem
75
+
76
+ Authentication code is easy to get subtly wrong, while full authentication frameworks may own user models, database tables, and application flows. This package focuses on reusable security mechanics and leaves application-specific decisions with the developer.
77
+
78
+ ## Features
79
+
80
+ - `bcryptjs` password hashing, 72-byte input checks, and dummy verification.
81
+ - `jose` access tokens with configured algorithms, issuer/audience checks, key resolution, and optional revocation lookup.
82
+ - Opaque refresh tokens with atomic store consumption, rotation, family revocation, and reuse detection.
83
+ - Express 4 and 5 authentication, role authorization, validation, and safe error middleware.
84
+ - Zod adapter and a framework-agnostic refresh-store conformance suite.
85
+ - Injected configuration; the library does not read `process.env`.
86
+
87
+ Feature and security claims are mapped to named tests in [docs/claims.md](docs/claims.md).
88
+
89
+ ## Security philosophy
90
+
91
+ The library handles reusable primitives and validates configuration. The application decides who a user is, what a role means, where data is stored, how sessions are delivered, and which HTTP response to return. Tokens are secrets: keep them out of logs and URLs. A valid access token does not establish that its subject still exists or remains enabled, and token-carried roles may be stale.
92
+
93
+ ## Install
94
+
95
+ ```sh
96
+ npm install rst-auth
97
+ ```
98
+
99
+ Core password, token, and refresh APIs need no framework peer. For the optional integrations, install the peers you use:
100
+
101
+ ```sh
102
+ npm install express zod
103
+ npm install --save-dev @types/express
104
+ ```
105
+
106
+ See [installation](docs/installation.md) for Node and package details.
107
+
108
+ ## Minimal setup
109
+
110
+ Configuration belongs in your application's config layer. Never commit a real signing secret.
111
+
112
+ ```ts
113
+ import { createAuth } from "rst-auth";
114
+
115
+ const secret = process.env.ACCESS_TOKEN_SECRET;
116
+ if (!secret || Buffer.byteLength(secret, "utf8") < 32) {
117
+ throw new Error("Set ACCESS_TOKEN_SECRET to at least 32 bytes");
118
+ }
119
+
120
+ const auth = createAuth({
121
+ accessToken: {
122
+ key: new TextEncoder().encode(secret),
123
+ issuer: "my-service",
124
+ audience: "my-api",
125
+ },
126
+ });
127
+ ```
128
+
129
+ ## Passwords
130
+
131
+ ```ts
132
+ const passwordHash = await auth.password.hash(password);
133
+ const matches = await auth.password.verify(password, passwordHash);
134
+
135
+ // When no user exists, do a dummy comparison before returning the same login error.
136
+ if (!user) await auth.password.verifyDummy(password);
137
+ ```
138
+
139
+ Passwords above 72 UTF-8 bytes are rejected because bcrypt truncates longer inputs. The default work factor is 12; benchmark it on the deployment hardware because hashing and `createAuth()` startup work increase with the setting. See [passwords](docs/passwords.md).
140
+
141
+ ### Optional register/login helpers
142
+
143
+ If you want the toolkit to hash and verify passwords inside your normal controller flow, pass your existing model and the email lookup you already use. The toolkit does not pick a database, model, schema, route, or response format for you:
144
+
145
+ ```ts
146
+ const auth = createAuth({
147
+ accessToken: { key: new TextEncoder().encode(secret), expiresInSeconds: 900 },
148
+ refreshToken: {
149
+ store: refreshTokenStore, // Your persistent atomic store in deployed apps.
150
+ refreshTokenTtl: 7 * 24 * 60 * 60,
151
+ absoluteLifetime: 30 * 24 * 60 * 60,
152
+ },
153
+ accounts: {
154
+ model: User, // Must provide create(values).
155
+ findByEmail: (email) => User.findOne({ email }),
156
+ getSubject: (user) => String(user._id),
157
+ getAccessClaims: (user) => ({ role: user.role }),
158
+ },
159
+ });
160
+
161
+ // In your existing signup/login controllers:
162
+ const session = await auth.accounts.register({
163
+ email: req.body.email,
164
+ password: req.body.password,
165
+ profile: { name: req.body.name }, // Never pass client role/permission fields.
166
+ });
167
+ res.status(201).json({ user: session.user, accessToken: session.accessToken });
168
+ // Deliver session.refreshToken through an HttpOnly cookie or your chosen channel.
169
+ ```
170
+
171
+ `auth.accounts.login({ email, password })` performs the lookup, bcrypt check (including dummy work for an unknown email), previous-session revocation, and token issuance. These helpers require refresh support and a `RefreshTokenStore`; the in-memory store is only for tests/local work. See [account helpers](docs/accounts.md).
172
+
173
+ ## Access tokens
174
+
175
+ ```ts
176
+ const token = await auth.tokens.generateAccessToken({
177
+ sub: user.id,
178
+ role: user.role,
179
+ });
180
+ const verifiedClaims = await auth.tokens.verifyAccessToken(token);
181
+ ```
182
+
183
+ The verifier uses the configured algorithm allowlist and validates signature, expiry, issuer/audience when configured, required claims, and token type. See [access tokens](docs/access-tokens.md).
184
+
185
+ ## Refresh tokens
186
+
187
+ Refresh support requires a store. The built-in `MemoryRefreshTokenStore` is for tests and local demonstrations only; it is not a production persistence option.
188
+
189
+ ```ts
190
+ import { createAuth, MemoryRefreshTokenStore } from "rst-auth";
191
+
192
+ const auth = createAuth({
193
+ accessToken: { key: new TextEncoder().encode(secret) },
194
+ refreshToken: {
195
+ store: new MemoryRefreshTokenStore(), // Use a shared persistent store in deployed services.
196
+ refreshTokenTtl: 60 * 60 * 24 * 7,
197
+ absoluteLifetime: 60 * 60 * 24 * 30,
198
+ },
199
+ });
200
+
201
+ const issued = await auth.refresh!.issue({ subject: user.id });
202
+ const next = await auth.refresh!.rotate(issued.refreshToken);
203
+ ```
204
+
205
+ The application creates an access token from the returned subject and its current user/permission data. Rotation consumes a stored hash atomically; presenting a consumed token revokes its family. Read [refresh tokens](docs/refresh-tokens.md) before implementing a store.
206
+
207
+ ## Express middleware
208
+
209
+ ```ts
210
+ import { expressAuth } from "rst-auth/express";
211
+
212
+ const middleware = expressAuth(auth);
213
+ app.get("/profile", middleware.authenticate(), profileController);
214
+ app.delete(
215
+ "/admin/users/:id",
216
+ middleware.authenticate(),
217
+ middleware.authorize({ roles: ["admin"] }),
218
+ deleteUserController,
219
+ );
220
+ ```
221
+
222
+ Authentication defaults to strict `Authorization: Bearer` parsing. Optional auth is available with `authenticate({ required: false })`; a present invalid token still fails. See [middleware](docs/middleware.md).
223
+
224
+ ## Validation
225
+
226
+ ```ts
227
+ import { expressAuth } from "rst-auth/express";
228
+ import { zodAdapter } from "rst-auth/zod";
229
+
230
+ const middleware = expressAuth(auth, { validator: zodAdapter() });
231
+ app.post(
232
+ "/items",
233
+ middleware.validate({ body: itemSchema }),
234
+ createItemController,
235
+ );
236
+ ```
237
+
238
+ Parsed values are placed on `req.validated`; `req.body`, `req.params`, and `req.query` are not silently replaced. See [validation](docs/validation.md).
239
+
240
+ ## Errors
241
+
242
+ `AuthError` exposes a stable code, developer message, safe public message, status, and optional cause. The Express error handler emits only safe fields by default; an application may provide a formatter. See [error handling](docs/error-handling.md).
243
+
244
+ ## Configuration reference
245
+
246
+ | Setting | Purpose | Default / constraint |
247
+ | ---------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------ |
248
+ | `mode` | Runtime validation profile | `development`; `production` requires issuer and audience and access expiry <= 1 hour |
249
+ | `password.workFactor` | bcrypt cost | `12`, integer 4–31 |
250
+ | `accessToken.key` | Signing key | Required; HMAC keys need at least 32 bytes |
251
+ | `accessToken.algorithm` | Signing algorithm | `HS256`; supported JOSE algorithms are explicitly listed in config types |
252
+ | `accessToken.algorithms` | Verification allowlist | Signing algorithm by default; must contain it |
253
+ | `accessToken.issuer`, `audience` | JWT issuer/audience checks | Optional outside production |
254
+ | `accessToken.expiresInSeconds` | Access-token lifetime | `900` seconds |
255
+ | `accessToken.keyId`, `keyResolver` | Key rotation support | Optional; resolver requires a `kid` |
256
+ | `accessToken.requiredClaims` | Additional required JWT claims | `sub`, `iat`, and `exp` are required automatically |
257
+ | `accessToken.isRevoked` | Stateful verification check | Optional; callback latency/availability is part of each verification |
258
+ | `refreshToken.store` | Atomic refresh-token state | Omit to disable refresh support |
259
+ | `refreshToken.refreshTokenTtl` | Idle refresh expiry | Required when refresh is enabled, in seconds |
260
+ | `refreshToken.absoluteLifetime` | Family lifetime cap | Required when refresh is enabled, in seconds |
261
+
262
+ See [configuration](docs/configuration.md) for validation details and asymmetric-key examples.
263
+
264
+ ## TypeScript
265
+
266
+ The package ships declarations and strict public types. `req.auth` and `req.validated` are augmented when the Express subpath is imported. For schema-specific parsed values, use the exported `ValidatedRequest<TSchemas>` type. Install `@types/express` when using the Express integration.
267
+
268
+ ## Database integration model
269
+
270
+ The toolkit does not choose a database or user schema. You can keep your own signup/login code using `auth.password`, or opt into `auth.accounts` and supply your model plus `findByEmail` callback. Refresh support still requires a persistent `RefreshTokenStore` with atomic compare-and-swap; run the `rst-auth/testing` conformance suite against it. See [account helpers](docs/accounts.md) and [refresh tokens](docs/refresh-tokens.md).
271
+
272
+ ## Limitations
273
+
274
+ This is alpha software, not a security audit or a complete identity system. It does not provide a production refresh store, user/session database, OAuth, MFA, account lockout, password reset, email verification, CORS policy, rate limiting, or CSRF protection. The memory refresh store is process-local. A token's roles can be stale unless the app performs current identity/permission checks. See [security](docs/security.md).
275
+
276
+ ## Testing
277
+
278
+ ```sh
279
+ npm ci
280
+ npm run build
281
+ npm test
282
+ npm run lint
283
+ npm run typecheck
284
+ npm run format:check
285
+ npm pack --dry-run
286
+ npm run example:install
287
+ npm --prefix examples/express-api run typecheck
288
+ npm --prefix examples/express-api test
289
+ npm --prefix examples/express-api run import-check
290
+ ```
291
+
292
+ The example installer creates a package tarball and installs that tarball into the example; it does not import source files from this repository. CI checks Node 22 and 24.
293
+
294
+ ## Contributing
295
+
296
+ Read [CONTRIBUTING.md](CONTRIBUTING.md), keep every documented security/feature claim connected to a test, and run all quality gates before proposing changes. The project follows the [Code of Conduct](CODE_OF_CONDUCT.md). Report vulnerabilities using [SECURITY.md](SECURITY.md), not a public issue.
297
+
298
+ ## License
299
+
300
+ MIT; Copyright (c) 2026 Sayed Risat. See [LICENSE](LICENSE).
301
+
302
+ ## Project status
303
+
304
+ Version `0.1.0` is an alpha under active development. Public API names, policies, and docs may change before a stable release. No production-readiness claim is made.
305
+
306
+ ## Comparison
307
+
308
+ This is a README-level comparison based on this project's checked-in competitive review, not an independent source audit. The reviewed JWT utility examples generally describe issuing new stateless JWTs on refresh without documented stored-token reuse detection; this package instead requires server-side refresh state and atomic consume for rotation. Broader authentication frameworks may manage schemas and migrations; this package leaves database schema and queries to the application. `express-jwt` focuses on middleware rather than passwords, refresh rotation, or validation. The reviewed analysis did not verify every package in the market, so these points describe only that review's scope and are not universal claims.
package/SECURITY.md ADDED
@@ -0,0 +1,13 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Security reports are accepted for the current alpha release line. Alpha software may change without a migration path and has not received an independent security audit.
6
+
7
+ ## Reporting a vulnerability privately
8
+
9
+ Please do not open a public issue or pull request for a suspected vulnerability. If GitHub private vulnerability reporting is enabled for this repository, use **Security → Report a vulnerability** to submit a private advisory. If it is not enabled, contact the maintainers through the repository's private contact channel and ask them to provide a secure reporting route; do not include exploit details in a public issue.
10
+
11
+ Include the affected version/commit, impact, reproduction steps, and any suggested mitigation. Do not include real user data, tokens, or production secrets. The maintainers will acknowledge receipt and coordinate a fix and disclosure timeline with the reporter.
12
+
13
+ Before the first public release, maintainers must enable and verify a private reporting route in the repository settings.
@@ -0,0 +1,41 @@
1
+ import type { AccessTokenService } from "./tokens.js";
2
+ import type { PasswordService } from "./password.js";
3
+ import type { RefreshTokenService } from "./refresh.js";
4
+ export interface AccountModelLike<User = unknown> {
5
+ create(values: Record<string, unknown>): PromiseLike<User> | User;
6
+ }
7
+ /**
8
+ * App-owned database adapter for the optional accounts helper. Pass the model
9
+ * and the query used to find an account; the package handles hash/verify and
10
+ * session issuance without taking ownership of the database.
11
+ */
12
+ export interface AccountAdapter<User = unknown> {
13
+ model: AccountModelLike<User>;
14
+ findByEmail(email: string): PromiseLike<User | null> | User | null;
15
+ getSubject?: (user: User) => string;
16
+ getAccessClaims?: (user: User) => Record<string, unknown>;
17
+ passwordHashField?: string;
18
+ /** Keep the original single-session behavior by revoking old families at login. */
19
+ revokePreviousSessionsOnLogin?: boolean;
20
+ }
21
+ export interface RegisterAccountInput {
22
+ email: string;
23
+ password: string;
24
+ profile?: Record<string, unknown>;
25
+ }
26
+ export interface LoginAccountInput {
27
+ email: string;
28
+ password: string;
29
+ }
30
+ export interface AccountSession {
31
+ user: unknown;
32
+ accessToken: string;
33
+ refreshToken: string;
34
+ }
35
+ export interface AccountService {
36
+ register(input: RegisterAccountInput): Promise<AccountSession>;
37
+ login(input: LoginAccountInput): Promise<AccountSession>;
38
+ }
39
+ export declare function validateAccountAdapter(adapter: unknown): asserts adapter is AccountAdapter;
40
+ export declare function createAccountService<User>(adapter: AccountAdapter<User>, password: PasswordService, tokens: AccessTokenService, refresh: RefreshTokenService): AccountService;
41
+ //# sourceMappingURL=accounts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,WAAW,gBAAgB,CAAC,IAAI,GAAG,OAAO;IAC9C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnE;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc,CAAC,IAAI,GAAG,OAAO;IAC5C,KAAK,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC9B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IACnE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;IACpC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mFAAmF;IACnF,6BAA6B,CAAC,EAAE,OAAO,CAAC;CACzC;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC/D,KAAK,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC1D;AAgFD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,OAAO,IAAI,cAAc,CA6CnC;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EACvC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,EAC7B,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,mBAAmB,GAC3B,cAAc,CAkGhB"}