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
@@ -0,0 +1,185 @@
1
+ import { AuthError } from "../errors.js";
2
+ const defaultErrorFormatter = (error) => ({
3
+ status: error.status,
4
+ body: { error: { code: error.code, message: error.message } },
5
+ });
6
+ function publicError(error) {
7
+ if (error instanceof AuthError) {
8
+ return {
9
+ status: error.status,
10
+ code: error.code,
11
+ message: error.publicMessage,
12
+ };
13
+ }
14
+ return {
15
+ status: 500,
16
+ code: "INTERNAL_ERROR",
17
+ message: "Internal server error",
18
+ };
19
+ }
20
+ function asyncHandler(handler) {
21
+ return (request, response, next) => {
22
+ void Promise.resolve()
23
+ .then(() => handler(request, response, next))
24
+ .catch(next);
25
+ };
26
+ }
27
+ export function fromHeader() {
28
+ return (request) => {
29
+ const value = request.get("authorization");
30
+ if (value === undefined)
31
+ return undefined;
32
+ const match = /^Bearer[ \t]+([^\s,]+)$/i.exec(value);
33
+ if (!match?.[1]) {
34
+ throw new AuthError("TOKEN_INVALID", "Malformed Authorization header");
35
+ }
36
+ return match[1];
37
+ };
38
+ }
39
+ export function fromCookie(name) {
40
+ if (!name || /[=;\s]/.test(name)) {
41
+ throw new TypeError("Cookie name must be a non-empty token");
42
+ }
43
+ return (request) => {
44
+ const header = request.get("cookie");
45
+ if (!header)
46
+ return undefined;
47
+ for (const entry of header.split(";")) {
48
+ const separator = entry.indexOf("=");
49
+ if (separator < 0 || entry.slice(0, separator).trim() !== name)
50
+ continue;
51
+ const value = entry.slice(separator + 1).trim();
52
+ try {
53
+ return decodeURIComponent(value);
54
+ }
55
+ catch {
56
+ throw new AuthError("TOKEN_INVALID", "Malformed authentication cookie");
57
+ }
58
+ }
59
+ return undefined;
60
+ };
61
+ }
62
+ export function fromAny(extractors) {
63
+ if (!extractors.length)
64
+ throw new TypeError("At least one extractor is required");
65
+ return async (request) => {
66
+ for (const extract of extractors) {
67
+ const token = await extract(request);
68
+ if (token !== undefined)
69
+ return token;
70
+ }
71
+ return undefined;
72
+ };
73
+ }
74
+ export function expressAuth(auth, options = {}) {
75
+ const extractToken = options.getToken ?? fromHeader();
76
+ function authenticate(authenticateOptions = {}) {
77
+ const required = authenticateOptions.required ?? true;
78
+ return asyncHandler(async (request, _response, next) => {
79
+ const token = await extractToken(request);
80
+ if (token === undefined) {
81
+ if (required) {
82
+ throw new AuthError("TOKEN_MISSING", "Access token is required");
83
+ }
84
+ delete request.auth;
85
+ next();
86
+ return;
87
+ }
88
+ const claims = await auth.tokens.verifyAccessToken(token, request);
89
+ const identity = options.lookupIdentity
90
+ ? await options.lookupIdentity(claims, request)
91
+ : claims;
92
+ if (identity === null) {
93
+ throw new AuthError("UNAUTHORIZED", "Identity lookup did not find a user");
94
+ }
95
+ request.auth = identity;
96
+ next();
97
+ });
98
+ }
99
+ function authorize(authorizeOptions) {
100
+ const requiredRoles = new Set(authorizeOptions.roles);
101
+ return (request, _response, next) => {
102
+ if (!request.auth) {
103
+ next(new AuthError("UNAUTHORIZED", "Authentication is required"));
104
+ return;
105
+ }
106
+ const roleData = request.auth;
107
+ const userRoles = [
108
+ ...(typeof roleData.role === "string" ? [roleData.role] : []),
109
+ ...(Array.isArray(roleData.roles)
110
+ ? roleData.roles.filter((role) => typeof role === "string")
111
+ : []),
112
+ ];
113
+ if (!userRoles.some((role) => requiredRoles.has(role))) {
114
+ next(new AuthError("FORBIDDEN", "User does not have a required role"));
115
+ return;
116
+ }
117
+ next();
118
+ };
119
+ }
120
+ function validate(schemas) {
121
+ if (!options.validator) {
122
+ throw new AuthError("INVALID_CONFIGURATION", "A validator adapter must be configured before using validate()");
123
+ }
124
+ const targets = ["body", "params", "query"];
125
+ return asyncHandler(async (request, _response, next) => {
126
+ const parsed = {};
127
+ for (const target of targets) {
128
+ const schema = schemas[target];
129
+ if (schema === undefined)
130
+ continue;
131
+ try {
132
+ parsed[target] = await options.validator.parse(schema, request[target]);
133
+ }
134
+ catch (cause) {
135
+ throw (schemas.formatError?.(cause, target) ??
136
+ new AuthError("VALIDATION_ERROR", `Invalid request ${target}`, {
137
+ cause,
138
+ }));
139
+ }
140
+ }
141
+ request.validated = parsed;
142
+ next();
143
+ });
144
+ }
145
+ function errorHandler(formatter = options.errorFormatter ?? defaultErrorFormatter) {
146
+ return (error, request, response, next) => {
147
+ if (response.headersSent) {
148
+ next(error);
149
+ return;
150
+ }
151
+ const formatted = formatter(publicError(error), request);
152
+ response.status(formatted.status).json(formatted.body);
153
+ };
154
+ }
155
+ return { authenticate, authorize, validate, errorHandler };
156
+ }
157
+ /** Alias retained for callers who prefer the create* naming convention. */
158
+ export const createExpressAuth = expressAuth;
159
+ function cookieSettings(options = {}) {
160
+ const secure = options.secure ?? true;
161
+ const sameSite = options.sameSite ?? "lax";
162
+ if (sameSite === "none" && !secure) {
163
+ throw new TypeError("SameSite=None cookies require Secure");
164
+ }
165
+ return {
166
+ httpOnly: true,
167
+ secure,
168
+ sameSite,
169
+ path: options.path ?? "/auth/refresh",
170
+ ...(options.maxAge === undefined ? {} : { maxAge: options.maxAge }),
171
+ };
172
+ }
173
+ export function setRefreshTokenCookie(response, token, options = {}) {
174
+ response.cookie(options.name ?? "refreshToken", token, cookieSettings(options));
175
+ }
176
+ export function clearRefreshTokenCookie(response, options = {}) {
177
+ const settings = cookieSettings(options);
178
+ response.clearCookie(options.name ?? "refreshToken", {
179
+ httpOnly: settings.httpOnly,
180
+ secure: settings.secure,
181
+ sameSite: settings.sameSite,
182
+ path: settings.path,
183
+ });
184
+ }
185
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/express/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { AuthConfig } from "./config.js";
2
+ import { AuthError, AUTH_ERROR_CODES, getHttpStatus } from "./errors.js";
3
+ import { createPasswordService } from "./password.js";
4
+ import { createAccessTokenService } from "./tokens.js";
5
+ import { type RefreshTokenService } from "./refresh.js";
6
+ import { MemoryRefreshTokenStore } from "./memory-refresh-token-store.js";
7
+ import { type AccountService } from "./accounts.js";
8
+ export interface Auth {
9
+ password: ReturnType<typeof createPasswordService>;
10
+ tokens: ReturnType<typeof createAccessTokenService>;
11
+ refresh?: RefreshTokenService;
12
+ accounts?: AccountService;
13
+ }
14
+ export declare function createAuth<User = unknown>(config: AuthConfig<User>): Auth;
15
+ export { MemoryRefreshTokenStore };
16
+ export { AuthError, AUTH_ERROR_CODES, getHttpStatus };
17
+ export type { ConsumeResult, RefreshTokenRecord, RefreshTokenStatus, RefreshTokenStore, RevokeTokenResult, } from "./refresh-store.js";
18
+ export type { IssuedRefreshToken, IssueRefreshTokenInput, RefreshTokenService, } from "./refresh.js";
19
+ export type { AuthErrorCode, AuthErrorOptions } from "./errors.js";
20
+ export type { AccountAdapter, AccountModelLike, AccountService, AccountSession, LoginAccountInput, RegisterAccountInput, } from "./accounts.js";
21
+ export type { AuthConfig, KeyResolver, RuntimeMode, SupportedAlgorithm, TokenKey, } from "./config.js";
22
+ export type { AccessTokenClaims, AccessTokenService, VerifiedAccessClaims, } from "./tokens.js";
23
+ export type { ValidationSchemaMap, ValidationTarget, ValidatorAdapter, } from "./validation.js";
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE1E,MAAM,WAAW,IAAI;IACnB,QAAQ,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;IACnD,MAAM,EAAE,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,wBAAgB,UAAU,CAAC,IAAI,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI,CAsBzE;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,CAAC;AACtD,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ import { validateAuthConfig } from "./config.js";
2
+ import { AuthError, AUTH_ERROR_CODES, getHttpStatus } from "./errors.js";
3
+ import { createPasswordService } from "./password.js";
4
+ import { createAccessTokenService } from "./tokens.js";
5
+ import { createRefreshTokenService, } from "./refresh.js";
6
+ import { MemoryRefreshTokenStore } from "./memory-refresh-token-store.js";
7
+ import { createAccountService } from "./accounts.js";
8
+ export function createAuth(config) {
9
+ const validatedConfig = validateAuthConfig(config);
10
+ const refresh = validatedConfig.refreshToken
11
+ ? createRefreshTokenService(validatedConfig.refreshToken)
12
+ : undefined;
13
+ const password = createPasswordService(validatedConfig.password.workFactor);
14
+ const tokens = createAccessTokenService(validatedConfig.accessToken);
15
+ const accounts = validatedConfig.accounts && refresh
16
+ ? createAccountService(validatedConfig.accounts, password, tokens, refresh)
17
+ : undefined;
18
+ return {
19
+ password,
20
+ tokens,
21
+ ...(refresh === undefined ? {} : { refresh }),
22
+ ...(accounts === undefined ? {} : { accounts }),
23
+ };
24
+ }
25
+ export { MemoryRefreshTokenStore };
26
+ export { AuthError, AUTH_ERROR_CODES, getHttpStatus };
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EACL,yBAAyB,GAE1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAuB,MAAM,eAAe,CAAC;AAS1E,MAAM,UAAU,UAAU,CAAiB,MAAwB;IACjE,MAAM,eAAe,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,eAAe,CAAC,YAAY;QAC1C,CAAC,CAAC,yBAAyB,CAAC,eAAe,CAAC,YAAY,CAAC;QACzD,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,QAAQ,GAAG,qBAAqB,CAAC,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC5E,MAAM,MAAM,GAAG,wBAAwB,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IACrE,MAAM,QAAQ,GACZ,eAAe,CAAC,QAAQ,IAAI,OAAO;QACjC,CAAC,CAAC,oBAAoB,CAClB,eAAe,CAAC,QAAQ,EACxB,QAAQ,EACR,MAAM,EACN,OAAO,CACR;QACH,CAAC,CAAC,SAAS,CAAC;IAChB,OAAO;QACL,QAAQ;QACR,MAAM;QACN,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;QAC7C,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { ConsumeResult, RefreshTokenRecord, RefreshTokenStore, RevokeTokenResult } from "./refresh-store.js";
2
+ /**
3
+ * In-memory store for tests and local examples only. It is not safe across
4
+ * processes, restarts, or multiple application instances.
5
+ */
6
+ export declare class MemoryRefreshTokenStore implements RefreshTokenStore {
7
+ private readonly records;
8
+ private readonly revokedFamilies;
9
+ create(record: RefreshTokenRecord): Promise<void>;
10
+ consume(tokenHash: string, now: Date): Promise<ConsumeResult>;
11
+ revokeToken(tokenHash: string, _now: Date): Promise<RevokeTokenResult>;
12
+ revokeFamily(familyId: string, _now: Date): Promise<void>;
13
+ revokeAllForSubject(subject: string, _now: Date): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=memory-refresh-token-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-refresh-token-store.d.ts","sourceRoot":"","sources":["../src/memory-refresh-token-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AAc5B;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,iBAAiB;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IACjE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IAE/C,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjD,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC;IAmB7D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAStE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzD,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAStE"}
@@ -0,0 +1,75 @@
1
+ function copyRecord(record) {
2
+ return {
3
+ ...record,
4
+ createdAt: new Date(record.createdAt),
5
+ expiresAt: new Date(record.expiresAt),
6
+ absoluteExpiresAt: new Date(record.absoluteExpiresAt),
7
+ ...(record.consumedAt === undefined
8
+ ? {}
9
+ : { consumedAt: new Date(record.consumedAt) }),
10
+ };
11
+ }
12
+ /**
13
+ * In-memory store for tests and local examples only. It is not safe across
14
+ * processes, restarts, or multiple application instances.
15
+ */
16
+ export class MemoryRefreshTokenStore {
17
+ records = new Map();
18
+ revokedFamilies = new Set();
19
+ async create(record) {
20
+ if (this.revokedFamilies.has(record.familyId)) {
21
+ throw new Error("Cannot create a refresh token in a revoked family");
22
+ }
23
+ if (this.records.has(record.tokenHash)) {
24
+ throw new Error("Refresh token hash already exists");
25
+ }
26
+ this.records.set(record.tokenHash, copyRecord(record));
27
+ }
28
+ async consume(tokenHash, now) {
29
+ // This mutation happens before the async method yields, giving this
30
+ // single-process implementation compare-and-swap behavior.
31
+ const record = this.records.get(tokenHash);
32
+ if (!record)
33
+ return { status: "not_found" };
34
+ if (record.status === "revoked")
35
+ return { status: "revoked" };
36
+ if (record.status === "consumed") {
37
+ await this.revokeFamily(record.familyId, now);
38
+ return { status: "reused" };
39
+ }
40
+ if (now >= record.expiresAt || now >= record.absoluteExpiresAt) {
41
+ return { status: "expired" };
42
+ }
43
+ record.status = "consumed";
44
+ record.consumedAt = new Date(now);
45
+ return { status: "ok", record: copyRecord(record) };
46
+ }
47
+ async revokeToken(tokenHash, _now) {
48
+ void _now;
49
+ const record = this.records.get(tokenHash);
50
+ if (!record)
51
+ return { status: "not_found" };
52
+ if (record.status !== "active")
53
+ return { status: "inactive" };
54
+ record.status = "revoked";
55
+ return { status: "revoked" };
56
+ }
57
+ async revokeFamily(familyId, _now) {
58
+ void _now;
59
+ this.revokedFamilies.add(familyId);
60
+ for (const record of this.records.values()) {
61
+ if (record.familyId === familyId)
62
+ record.status = "revoked";
63
+ }
64
+ }
65
+ async revokeAllForSubject(subject, _now) {
66
+ void _now;
67
+ for (const record of this.records.values()) {
68
+ if (record.subject === subject) {
69
+ this.revokedFamilies.add(record.familyId);
70
+ record.status = "revoked";
71
+ }
72
+ }
73
+ }
74
+ }
75
+ //# sourceMappingURL=memory-refresh-token-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-refresh-token-store.js","sourceRoot":"","sources":["../src/memory-refresh-token-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface PasswordService {
2
+ hash(password: string): Promise<string>;
3
+ verify(password: string, hash: string): Promise<boolean>;
4
+ verifyDummy(password: string): Promise<void>;
5
+ }
6
+ export declare function createPasswordService(workFactor: number): PasswordService;
7
+ //# sourceMappingURL=password.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../src/password.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CA2BzE"}
@@ -0,0 +1,36 @@
1
+ import bcrypt from "bcryptjs";
2
+ import { AuthError } from "./errors.js";
3
+ const MAX_PASSWORD_BYTES = 72;
4
+ function validatePassword(password) {
5
+ if (typeof password !== "string" || password.length === 0) {
6
+ throw new AuthError("VALIDATION_ERROR", "Password must be a non-empty string");
7
+ }
8
+ if (Buffer.byteLength(password, "utf8") > MAX_PASSWORD_BYTES) {
9
+ throw new AuthError("VALIDATION_ERROR", "Password must not exceed 72 UTF-8 bytes because bcrypt truncates longer values");
10
+ }
11
+ }
12
+ export function createPasswordService(workFactor) {
13
+ const dummyHash = bcrypt.hashSync("rst-auth-dummy-password-value", workFactor);
14
+ return {
15
+ async hash(password) {
16
+ validatePassword(password);
17
+ return bcrypt.hash(password, workFactor);
18
+ },
19
+ async verify(password, hash) {
20
+ validatePassword(password);
21
+ if (typeof hash !== "string" || hash.length === 0)
22
+ return false;
23
+ try {
24
+ return await bcrypt.compare(password, hash);
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ },
30
+ async verifyDummy(password) {
31
+ validatePassword(password);
32
+ await bcrypt.compare(password, dummyHash);
33
+ },
34
+ };
35
+ }
36
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../src/password.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAE9B,SAAS,gBAAgB,CAAC,QAAiB;IACzC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,SAAS,CACjB,kBAAkB,EAClB,qCAAqC,CACtC,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,kBAAkB,EAAE,CAAC;QAC7D,MAAM,IAAI,SAAS,CACjB,kBAAkB,EAClB,gFAAgF,CACjF,CAAC;IACJ,CAAC;AACH,CAAC;AAQD,MAAM,UAAU,qBAAqB,CAAC,UAAkB;IACtD,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAC/B,+BAA+B,EAC/B,UAAU,CACX,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,QAAgB;YACzB,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC3B,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC3C,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,QAAgB,EAAE,IAAY;YACzC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC3B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAChE,IAAI,CAAC;gBACH,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC9C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,QAAgB;YAChC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC3B,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC5C,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,48 @@
1
+ export type RefreshTokenStatus = "active" | "consumed" | "revoked";
2
+ export interface RefreshTokenRecord {
3
+ /** A SHA-256 digest of the opaque token. Raw refresh tokens must never be stored. */
4
+ tokenHash: string;
5
+ familyId: string;
6
+ subject: string;
7
+ createdAt: Date;
8
+ expiresAt: Date;
9
+ absoluteExpiresAt: Date;
10
+ status: RefreshTokenStatus;
11
+ consumedAt?: Date;
12
+ }
13
+ export type ConsumeResult = {
14
+ status: "ok";
15
+ record: RefreshTokenRecord;
16
+ } | {
17
+ status: "not_found";
18
+ } | {
19
+ status: "expired";
20
+ } | {
21
+ status: "revoked";
22
+ } | {
23
+ status: "reused";
24
+ };
25
+ export type RevokeTokenResult = {
26
+ status: "revoked";
27
+ } | {
28
+ status: "not_found";
29
+ } | {
30
+ status: "inactive";
31
+ };
32
+ /**
33
+ * Implementations must make consume a single atomic compare-and-swap operation.
34
+ * A store that cannot ensure only one concurrent caller gets `ok` cannot claim
35
+ * refresh-token reuse protection. Re-presenting a consumed token must revoke
36
+ * its family before returning `reused`. Stores must retain family-revocation
37
+ * tombstones through the family absolute expiry so a late rotation cannot
38
+ * recreate a revoked family.
39
+ */
40
+ export interface RefreshTokenStore {
41
+ /** Must reject records for a family that has already been revoked. */
42
+ create(record: RefreshTokenRecord): Promise<void>;
43
+ consume(tokenHash: string, now: Date): Promise<ConsumeResult>;
44
+ revokeToken(tokenHash: string, now: Date): Promise<RevokeTokenResult>;
45
+ revokeFamily(familyId: string, now: Date): Promise<void>;
46
+ revokeAllForSubject(subject: string, now: Date): Promise<void>;
47
+ }
48
+ //# sourceMappingURL=refresh-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-store.d.ts","sourceRoot":"","sources":["../src/refresh-store.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,iBAAiB,EAAE,IAAI,CAAC;IACxB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,CAAC,EAAE,IAAI,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAC5C;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEzB,MAAM,MAAM,iBAAiB,GAC3B;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAE3E;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC9D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACtE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=refresh-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-store.js","sourceRoot":"","sources":["../src/refresh-store.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import type { RefreshTokenStore } from "./refresh-store.js";
2
+ export interface IssueRefreshTokenInput {
3
+ subject: string;
4
+ }
5
+ export interface IssuedRefreshToken {
6
+ refreshToken: string;
7
+ familyId: string;
8
+ subject: string;
9
+ expiresAt: Date;
10
+ absoluteExpiresAt: Date;
11
+ }
12
+ export interface RefreshTokenService {
13
+ issue(input: IssueRefreshTokenInput): Promise<IssuedRefreshToken>;
14
+ rotate(refreshToken: string): Promise<IssuedRefreshToken>;
15
+ /** Revoke one active token. Repeated calls and unknown tokens are harmless. */
16
+ revoke(refreshToken: string): Promise<void>;
17
+ revokeFamily(familyId: string): Promise<void>;
18
+ revokeAllForSubject(subject: string): Promise<void>;
19
+ }
20
+ export interface RefreshTokenServiceConfig {
21
+ store: RefreshTokenStore;
22
+ refreshTokenTtl: number;
23
+ absoluteLifetime: number;
24
+ }
25
+ export declare function hashRefreshToken(token: string): string;
26
+ export declare function createRefreshTokenService(config: RefreshTokenServiceConfig): RefreshTokenService;
27
+ //# sourceMappingURL=refresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAI5D,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,iBAAiB,EAAE,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAClE,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1D,+EAA+E;IAC/E,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,iBAAiB,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAsBD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,yBAAyB,GAChC,mBAAmB,CAyGrB"}
@@ -0,0 +1,93 @@
1
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
2
+ import { AuthError } from "./errors.js";
3
+ const TOKEN_BYTES = 32;
4
+ export function hashRefreshToken(token) {
5
+ return createHash("sha256").update(token, "utf8").digest("hex");
6
+ }
7
+ function opaqueToken() {
8
+ return randomBytes(TOKEN_BYTES).toString("base64url");
9
+ }
10
+ function tokenExpiry(now, ttlSeconds, absoluteExpiresAt) {
11
+ const idleExpiry = new Date(now.getTime() + ttlSeconds * 1000);
12
+ return idleExpiry < absoluteExpiresAt
13
+ ? idleExpiry
14
+ : new Date(absoluteExpiresAt);
15
+ }
16
+ function invalidRefreshToken(status) {
17
+ throw new AuthError("REFRESH_TOKEN_INVALID", `Refresh token cannot be used: ${status}`);
18
+ }
19
+ export function createRefreshTokenService(config) {
20
+ return {
21
+ async issue({ subject }) {
22
+ if (typeof subject !== "string" || subject.length === 0) {
23
+ throw new AuthError("VALIDATION_ERROR", "Refresh-token subject must be a non-empty string");
24
+ }
25
+ const now = new Date();
26
+ const familyId = randomUUID();
27
+ const absoluteExpiresAt = new Date(now.getTime() + config.absoluteLifetime * 1000);
28
+ const refreshToken = opaqueToken();
29
+ const expiresAt = tokenExpiry(now, config.refreshTokenTtl, absoluteExpiresAt);
30
+ await config.store.create({
31
+ tokenHash: hashRefreshToken(refreshToken),
32
+ familyId,
33
+ subject,
34
+ createdAt: now,
35
+ expiresAt,
36
+ absoluteExpiresAt,
37
+ status: "active",
38
+ });
39
+ return { refreshToken, familyId, subject, expiresAt, absoluteExpiresAt };
40
+ },
41
+ async rotate(refreshToken) {
42
+ if (typeof refreshToken !== "string" || refreshToken.length === 0) {
43
+ invalidRefreshToken("not_found");
44
+ }
45
+ const now = new Date();
46
+ const result = await config.store.consume(hashRefreshToken(refreshToken), now);
47
+ if (result.status === "reused") {
48
+ throw new AuthError("REFRESH_TOKEN_REUSED", "A consumed refresh token was presented again; its family was revoked");
49
+ }
50
+ if (result.status !== "ok")
51
+ invalidRefreshToken(result.status);
52
+ const { record } = result;
53
+ const expiresAt = tokenExpiry(now, config.refreshTokenTtl, record.absoluteExpiresAt);
54
+ if (expiresAt <= now)
55
+ invalidRefreshToken("expired");
56
+ const nextRefreshToken = opaqueToken();
57
+ await config.store.create({
58
+ tokenHash: hashRefreshToken(nextRefreshToken),
59
+ familyId: record.familyId,
60
+ subject: record.subject,
61
+ createdAt: now,
62
+ expiresAt,
63
+ absoluteExpiresAt: record.absoluteExpiresAt,
64
+ status: "active",
65
+ });
66
+ return {
67
+ refreshToken: nextRefreshToken,
68
+ familyId: record.familyId,
69
+ subject: record.subject,
70
+ expiresAt,
71
+ absoluteExpiresAt: new Date(record.absoluteExpiresAt),
72
+ };
73
+ },
74
+ async revoke(refreshToken) {
75
+ if (typeof refreshToken !== "string" || refreshToken.length === 0)
76
+ return;
77
+ await config.store.revokeToken(hashRefreshToken(refreshToken), new Date());
78
+ },
79
+ async revokeFamily(familyId) {
80
+ if (typeof familyId !== "string" || familyId.length === 0) {
81
+ throw new AuthError("VALIDATION_ERROR", "Refresh-token family ID must be a non-empty string");
82
+ }
83
+ await config.store.revokeFamily(familyId, new Date());
84
+ },
85
+ async revokeAllForSubject(subject) {
86
+ if (typeof subject !== "string" || subject.length === 0) {
87
+ throw new AuthError("VALIDATION_ERROR", "Refresh-token subject must be a non-empty string");
88
+ }
89
+ await config.store.revokeAllForSubject(subject, new Date());
90
+ },
91
+ };
92
+ }
93
+ //# sourceMappingURL=refresh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { registerRefreshTokenStoreConformanceTests } from "./refresh-store-conformance.js";
2
+ export type { ConformanceTestRegistrar, RefreshTokenStoreFactory, } from "./refresh-store-conformance.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yCAAyC,EAAE,MAAM,gCAAgC,CAAC;AAC3F,YAAY,EACV,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,gCAAgC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { registerRefreshTokenStoreConformanceTests } from "./refresh-store-conformance.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yCAAyC,EAAE,MAAM,gCAAgC,CAAC"}