rst-auth 0.0.0-stage → 0.1.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 (72) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/CODE_OF_CONDUCT.md +73 -0
  3. package/CONTRIBUTING.md +35 -0
  4. package/LICENSE +21 -0
  5. package/README.md +212 -2
  6. package/SECURITY.md +13 -0
  7. package/dist/config.d.ts +59 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +187 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/errors.d.ts +16 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +54 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/express/index.d.ts +74 -0
  16. package/dist/express/index.d.ts.map +1 -0
  17. package/dist/express/index.js +185 -0
  18. package/dist/express/index.js.map +1 -0
  19. package/dist/index.d.ts +21 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +20 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/memory-refresh-token-store.d.ts +15 -0
  24. package/dist/memory-refresh-token-store.d.ts.map +1 -0
  25. package/dist/memory-refresh-token-store.js +75 -0
  26. package/dist/memory-refresh-token-store.js.map +1 -0
  27. package/dist/password.d.ts +7 -0
  28. package/dist/password.d.ts.map +1 -0
  29. package/dist/password.js +36 -0
  30. package/dist/password.js.map +1 -0
  31. package/dist/refresh-store.d.ts +48 -0
  32. package/dist/refresh-store.d.ts.map +1 -0
  33. package/dist/refresh-store.js +2 -0
  34. package/dist/refresh-store.js.map +1 -0
  35. package/dist/refresh.d.ts +27 -0
  36. package/dist/refresh.d.ts.map +1 -0
  37. package/dist/refresh.js +93 -0
  38. package/dist/refresh.js.map +1 -0
  39. package/dist/testing/index.d.ts +3 -0
  40. package/dist/testing/index.d.ts.map +1 -0
  41. package/dist/testing/index.js +2 -0
  42. package/dist/testing/index.js.map +1 -0
  43. package/dist/testing/refresh-store-conformance.d.ts +11 -0
  44. package/dist/testing/refresh-store-conformance.d.ts.map +1 -0
  45. package/dist/testing/refresh-store-conformance.js +110 -0
  46. package/dist/testing/refresh-store-conformance.js.map +1 -0
  47. package/dist/tokens.d.ts +15 -0
  48. package/dist/tokens.d.ts.map +1 -0
  49. package/dist/tokens.js +90 -0
  50. package/dist/tokens.js.map +1 -0
  51. package/dist/validation.d.ts +7 -0
  52. package/dist/validation.d.ts.map +1 -0
  53. package/dist/validation.js +2 -0
  54. package/dist/validation.js.map +1 -0
  55. package/dist/zod/index.d.ts +5 -0
  56. package/dist/zod/index.d.ts.map +1 -0
  57. package/dist/zod/index.js +22 -0
  58. package/dist/zod/index.js.map +1 -0
  59. package/docs/access-tokens.md +15 -0
  60. package/docs/before-first-release.md +31 -0
  61. package/docs/claims.md +40 -0
  62. package/docs/configuration.md +30 -0
  63. package/docs/cookies-vs-bearer.md +82 -0
  64. package/docs/error-handling.md +15 -0
  65. package/docs/installation.md +39 -0
  66. package/docs/middleware.md +24 -0
  67. package/docs/migration.md +17 -0
  68. package/docs/passwords.md +23 -0
  69. package/docs/refresh-tokens.md +47 -0
  70. package/docs/security.md +16 -0
  71. package/docs/validation.md +24 -0
  72. package/package.json +91 -4
@@ -0,0 +1,16 @@
1
+ export declare const AUTH_ERROR_CODES: readonly ["TOKEN_MISSING", "TOKEN_INVALID", "TOKEN_EXPIRED", "REFRESH_TOKEN_INVALID", "REFRESH_TOKEN_REUSED", "SESSION_REVOKED", "UNAUTHORIZED", "FORBIDDEN", "VALIDATION_ERROR", "INVALID_CONFIGURATION"];
2
+ export type AuthErrorCode = (typeof AUTH_ERROR_CODES)[number];
3
+ export interface AuthErrorOptions {
4
+ publicMessage?: string;
5
+ status?: number;
6
+ cause?: unknown;
7
+ }
8
+ export declare class AuthError extends Error {
9
+ readonly code: AuthErrorCode;
10
+ readonly developerMessage: string;
11
+ readonly publicMessage: string;
12
+ readonly status: number;
13
+ constructor(code: AuthErrorCode, developerMessage: string, options?: AuthErrorOptions);
14
+ }
15
+ export declare function getHttpStatus(code: AuthErrorCode): number;
16
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,4MAWnB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AA4B9D,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGtB,IAAI,EAAE,aAAa,EACnB,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,gBAAqB;CASjC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAEzD"}
package/dist/errors.js ADDED
@@ -0,0 +1,54 @@
1
+ export const AUTH_ERROR_CODES = [
2
+ "TOKEN_MISSING",
3
+ "TOKEN_INVALID",
4
+ "TOKEN_EXPIRED",
5
+ "REFRESH_TOKEN_INVALID",
6
+ "REFRESH_TOKEN_REUSED",
7
+ "SESSION_REVOKED",
8
+ "UNAUTHORIZED",
9
+ "FORBIDDEN",
10
+ "VALIDATION_ERROR",
11
+ "INVALID_CONFIGURATION",
12
+ ];
13
+ const HTTP_STATUS = {
14
+ TOKEN_MISSING: 401,
15
+ TOKEN_INVALID: 401,
16
+ TOKEN_EXPIRED: 401,
17
+ REFRESH_TOKEN_INVALID: 401,
18
+ REFRESH_TOKEN_REUSED: 401,
19
+ SESSION_REVOKED: 401,
20
+ UNAUTHORIZED: 401,
21
+ FORBIDDEN: 403,
22
+ VALIDATION_ERROR: 400,
23
+ INVALID_CONFIGURATION: 500,
24
+ };
25
+ const PUBLIC_MESSAGES = {
26
+ TOKEN_MISSING: "Authentication is required",
27
+ TOKEN_INVALID: "Authentication failed",
28
+ TOKEN_EXPIRED: "Authentication has expired",
29
+ REFRESH_TOKEN_INVALID: "Refresh token is invalid",
30
+ REFRESH_TOKEN_REUSED: "Refresh token is invalid",
31
+ SESSION_REVOKED: "Authentication has been revoked",
32
+ UNAUTHORIZED: "Authentication is required",
33
+ FORBIDDEN: "You are not allowed to perform this action",
34
+ VALIDATION_ERROR: "The request is invalid",
35
+ INVALID_CONFIGURATION: "Authentication is unavailable",
36
+ };
37
+ export class AuthError extends Error {
38
+ code;
39
+ developerMessage;
40
+ publicMessage;
41
+ status;
42
+ constructor(code, developerMessage, options = {}) {
43
+ super(developerMessage, { cause: options.cause });
44
+ this.name = "AuthError";
45
+ this.code = code;
46
+ this.developerMessage = developerMessage;
47
+ this.publicMessage = options.publicMessage ?? PUBLIC_MESSAGES[code];
48
+ this.status = options.status ?? HTTP_STATUS[code];
49
+ }
50
+ }
51
+ export function getHttpStatus(code) {
52
+ return HTTP_STATUS[code];
53
+ }
54
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,eAAe;IACf,eAAe;IACf,eAAe;IACf,uBAAuB;IACvB,sBAAsB;IACtB,iBAAiB;IACjB,cAAc;IACd,WAAW;IACX,kBAAkB;IAClB,uBAAuB;CACf,CAAC;AAIX,MAAM,WAAW,GAAkC;IACjD,aAAa,EAAE,GAAG;IAClB,aAAa,EAAE,GAAG;IAClB,aAAa,EAAE,GAAG;IAClB,qBAAqB,EAAE,GAAG;IAC1B,oBAAoB,EAAE,GAAG;IACzB,eAAe,EAAE,GAAG;IACpB,YAAY,EAAE,GAAG;IACjB,SAAS,EAAE,GAAG;IACd,gBAAgB,EAAE,GAAG;IACrB,qBAAqB,EAAE,GAAG;CAC3B,CAAC;AAEF,MAAM,eAAe,GAAkC;IACrD,aAAa,EAAE,4BAA4B;IAC3C,aAAa,EAAE,uBAAuB;IACtC,aAAa,EAAE,4BAA4B;IAC3C,qBAAqB,EAAE,0BAA0B;IACjD,oBAAoB,EAAE,0BAA0B;IAChD,eAAe,EAAE,iCAAiC;IAClD,YAAY,EAAE,4BAA4B;IAC1C,SAAS,EAAE,4CAA4C;IACvD,gBAAgB,EAAE,wBAAwB;IAC1C,qBAAqB,EAAE,+BAA+B;CACvD,CAAC;AAQF,MAAM,OAAO,SAAU,SAAQ,KAAK;IACzB,IAAI,CAAgB;IACpB,gBAAgB,CAAS;IACzB,aAAa,CAAS;IACtB,MAAM,CAAS;IAExB,YACE,IAAmB,EACnB,gBAAwB,EACxB,UAA4B,EAAE;QAE9B,KAAK,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;CACF;AAED,MAAM,UAAU,aAAa,CAAC,IAAmB;IAC/C,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,74 @@
1
+ import type { ErrorRequestHandler, Request, RequestHandler, Response } from "express";
2
+ import { AuthError } from "../errors.js";
3
+ import type { Auth } from "../index.js";
4
+ import type { ValidationSchemaMap, ValidationTarget, ValidatorAdapter } from "../validation.js";
5
+ import type { VerifiedAccessClaims } from "../tokens.js";
6
+ export interface AuthenticatedRequest<Identity extends VerifiedAccessClaims = VerifiedAccessClaims> extends Request {
7
+ auth?: Identity;
8
+ validated?: Partial<Record<ValidationTarget, unknown>>;
9
+ }
10
+ type SchemaOutput<TSchema> = TSchema extends {
11
+ _output: infer TOutput;
12
+ } ? TOutput : unknown;
13
+ export type ValidatedRequest<TSchemas extends ValidationSchemaMap> = Request & {
14
+ validated?: {
15
+ [Target in keyof TSchemas]?: SchemaOutput<TSchemas[Target]>;
16
+ };
17
+ };
18
+ declare module "express-serve-static-core" {
19
+ interface Request {
20
+ auth?: VerifiedAccessClaims;
21
+ validated?: Partial<Record<ValidationTarget, unknown>>;
22
+ }
23
+ }
24
+ export type TokenExtractor = (request: Request) => string | undefined | Promise<string | undefined>;
25
+ export interface PublicHttpError {
26
+ status: number;
27
+ code: string;
28
+ message: string;
29
+ }
30
+ export interface FormattedHttpError {
31
+ status: number;
32
+ body: unknown;
33
+ }
34
+ export type ErrorFormatter = (error: PublicHttpError, request: Request) => FormattedHttpError;
35
+ export type IdentityLookup<Identity extends VerifiedAccessClaims> = (claims: VerifiedAccessClaims, request: Request) => Identity | null | Promise<Identity | null>;
36
+ export interface ExpressAuthOptions<Identity extends VerifiedAccessClaims> {
37
+ getToken?: TokenExtractor;
38
+ lookupIdentity?: IdentityLookup<Identity>;
39
+ validator?: ValidatorAdapter;
40
+ errorFormatter?: ErrorFormatter;
41
+ }
42
+ export interface AuthenticateOptions {
43
+ required?: boolean;
44
+ }
45
+ export interface AuthorizeOptions {
46
+ roles: readonly string[];
47
+ }
48
+ export declare function fromHeader(): TokenExtractor;
49
+ export declare function fromCookie(name: string): TokenExtractor;
50
+ export declare function fromAny(extractors: readonly TokenExtractor[]): TokenExtractor;
51
+ export type ValidateOptions<TSchemas extends ValidationSchemaMap = ValidationSchemaMap> = {
52
+ [Target in keyof TSchemas]?: TSchemas[Target];
53
+ } & {
54
+ formatError?: (cause: unknown, target: ValidationTarget) => AuthError;
55
+ };
56
+ export declare function expressAuth<Identity extends VerifiedAccessClaims = VerifiedAccessClaims>(auth: Auth, options?: ExpressAuthOptions<Identity>): {
57
+ authenticate: (authenticateOptions?: AuthenticateOptions) => RequestHandler;
58
+ authorize: (authorizeOptions: AuthorizeOptions) => RequestHandler;
59
+ validate: <TSchemas extends ValidationSchemaMap>(schemas: ValidateOptions<TSchemas>) => RequestHandler;
60
+ errorHandler: (formatter?: ErrorFormatter) => ErrorRequestHandler;
61
+ };
62
+ /** Alias retained for callers who prefer the create* naming convention. */
63
+ export declare const createExpressAuth: typeof expressAuth;
64
+ export interface RefreshCookieOptions {
65
+ name?: string;
66
+ path?: string;
67
+ maxAge?: number;
68
+ secure?: boolean;
69
+ sameSite?: "lax" | "strict" | "none";
70
+ }
71
+ export declare function setRefreshTokenCookie(response: Response, token: string, options?: RefreshCookieOptions): void;
72
+ export declare function clearRefreshTokenCookie(response: Response, options?: RefreshCookieOptions): void;
73
+ export type { ValidatorAdapter, ValidationSchemaMap, ValidationTarget, } from "../validation.js";
74
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/express/index.ts"],"names":[],"mappings":"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"}
@@ -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,21 @@
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
+ export interface Auth {
8
+ password: ReturnType<typeof createPasswordService>;
9
+ tokens: ReturnType<typeof createAccessTokenService>;
10
+ refresh?: RefreshTokenService;
11
+ }
12
+ export declare function createAuth(config: AuthConfig): Auth;
13
+ export { MemoryRefreshTokenStore };
14
+ export { AuthError, AUTH_ERROR_CODES, getHttpStatus };
15
+ export type { ConsumeResult, RefreshTokenRecord, RefreshTokenStatus, RefreshTokenStore, RevokeTokenResult, } from "./refresh-store.js";
16
+ export type { IssuedRefreshToken, IssueRefreshTokenInput, RefreshTokenService, } from "./refresh.js";
17
+ export type { AuthErrorCode, AuthErrorOptions } from "./errors.js";
18
+ export type { AuthConfig, KeyResolver, RuntimeMode, SupportedAlgorithm, TokenKey, } from "./config.js";
19
+ export type { AccessTokenClaims, AccessTokenService, VerifiedAccessClaims, } from "./tokens.js";
20
+ export type { ValidationSchemaMap, ValidationTarget, ValidatorAdapter, } from "./validation.js";
21
+ //# 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;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;CAC/B;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAUnD;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,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,20 @@
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
+ export function createAuth(config) {
8
+ const validatedConfig = validateAuthConfig(config);
9
+ const refresh = validatedConfig.refreshToken
10
+ ? createRefreshTokenService(validatedConfig.refreshToken)
11
+ : undefined;
12
+ return {
13
+ password: createPasswordService(validatedConfig.password.workFactor),
14
+ tokens: createAccessTokenService(validatedConfig.accessToken),
15
+ ...(refresh === undefined ? {} : { refresh }),
16
+ };
17
+ }
18
+ export { MemoryRefreshTokenStore };
19
+ export { AuthError, AUTH_ERROR_CODES, getHttpStatus };
20
+ //# 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;AAQ1E,MAAM,UAAU,UAAU,CAAC,MAAkB;IAC3C,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,OAAO;QACL,QAAQ,EAAE,qBAAqB,CAAC,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC;QACpE,MAAM,EAAE,wBAAwB,CAAC,eAAe,CAAC,WAAW,CAAC;QAC7D,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;KAC9C,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":""}