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,169 @@
1
+ import { AuthError } from "./errors.js";
2
+ const PRIVILEGED_PROFILE_FIELDS = new Set([
3
+ "role",
4
+ "roles",
5
+ "permissions",
6
+ "scopes",
7
+ "isAdmin",
8
+ "admin",
9
+ ]);
10
+ function invalidInput(message) {
11
+ throw new AuthError("VALIDATION_ERROR", message);
12
+ }
13
+ function normalizedEmail(email) {
14
+ if (typeof email !== "string" || email.trim().length === 0) {
15
+ invalidInput("Email must be a non-empty string");
16
+ }
17
+ return email.trim();
18
+ }
19
+ function readField(user, field) {
20
+ if (typeof user !== "object" || user === null)
21
+ return undefined;
22
+ return user[field];
23
+ }
24
+ function plainUser(user) {
25
+ if (typeof user !== "object" || user === null) {
26
+ throw new AuthError("UNAUTHORIZED", "Account lookup returned no user");
27
+ }
28
+ const toObject = user.toObject;
29
+ const value = typeof toObject === "function" ? toObject.call(user) : user;
30
+ if (typeof value !== "object" || value === null) {
31
+ throw new AuthError("UNAUTHORIZED", "Account lookup returned no user");
32
+ }
33
+ return { ...value };
34
+ }
35
+ function publicUser(user, passwordHashField) {
36
+ const copy = plainUser(user);
37
+ delete copy[passwordHashField];
38
+ // Never expose legacy/raw session fields if a user schema still has them.
39
+ delete copy.refreshToken;
40
+ delete copy.refreshTokens;
41
+ delete copy.authRefreshTokens;
42
+ return copy;
43
+ }
44
+ function subjectFor(adapter, user) {
45
+ const value = adapter.getSubject?.(user) ??
46
+ readField(user, "_id") ??
47
+ readField(user, "id");
48
+ const subject = typeof value === "string"
49
+ ? value
50
+ : typeof value === "number" || typeof value === "bigint"
51
+ ? String(value)
52
+ : typeof value === "object" && value !== null
53
+ ? String(value)
54
+ : undefined;
55
+ if (typeof subject !== "string" || subject.length === 0) {
56
+ throw new AuthError("INVALID_CONFIGURATION", "Account adapter must provide a stable user subject");
57
+ }
58
+ return subject;
59
+ }
60
+ function accessClaimsFor(adapter, user) {
61
+ if (adapter.getAccessClaims)
62
+ return adapter.getAccessClaims(user);
63
+ const role = readField(user, "role");
64
+ return typeof role === "string" ? { role } : {};
65
+ }
66
+ export function validateAccountAdapter(adapter) {
67
+ if (!adapter || typeof adapter !== "object") {
68
+ throw new AuthError("INVALID_CONFIGURATION", "accounts must be an object");
69
+ }
70
+ const value = adapter;
71
+ if (!value.model || typeof value.model.create !== "function") {
72
+ throw new AuthError("INVALID_CONFIGURATION", "accounts.model must provide create()");
73
+ }
74
+ if (typeof value.findByEmail !== "function") {
75
+ throw new AuthError("INVALID_CONFIGURATION", "accounts.findByEmail must be a function");
76
+ }
77
+ if (value.getSubject !== undefined &&
78
+ typeof value.getSubject !== "function") {
79
+ throw new AuthError("INVALID_CONFIGURATION", "accounts.getSubject must be a function");
80
+ }
81
+ if (value.getAccessClaims !== undefined &&
82
+ typeof value.getAccessClaims !== "function") {
83
+ throw new AuthError("INVALID_CONFIGURATION", "accounts.getAccessClaims must be a function");
84
+ }
85
+ if (value.passwordHashField !== undefined &&
86
+ (typeof value.passwordHashField !== "string" ||
87
+ value.passwordHashField.length === 0)) {
88
+ throw new AuthError("INVALID_CONFIGURATION", "accounts.passwordHashField must be a non-empty string");
89
+ }
90
+ }
91
+ export function createAccountService(adapter, password, tokens, refresh) {
92
+ const passwordHashField = adapter.passwordHashField ?? "passwordHash";
93
+ const revokePreviousSessionsOnLogin = adapter.revokePreviousSessionsOnLogin ?? true;
94
+ async function createSession(user) {
95
+ const subject = subjectFor(adapter, user);
96
+ const accessToken = await tokens.generateAccessToken({
97
+ ...accessClaimsFor(adapter, user),
98
+ sub: subject,
99
+ });
100
+ const issuedRefresh = await refresh.issue({ subject });
101
+ return {
102
+ user: publicUser(user, passwordHashField),
103
+ accessToken,
104
+ refreshToken: issuedRefresh.refreshToken,
105
+ };
106
+ }
107
+ return {
108
+ async register({ email: rawEmail, password: rawPassword, profile = {} }) {
109
+ const email = normalizedEmail(rawEmail);
110
+ if (!profile || typeof profile !== "object" || Array.isArray(profile)) {
111
+ invalidInput("profile must be an object when provided");
112
+ }
113
+ const unsafeField = Object.keys(profile).find((key) => PRIVILEGED_PROFILE_FIELDS.has(key));
114
+ if (unsafeField) {
115
+ invalidInput(`Signup cannot set privileged field: ${unsafeField}`);
116
+ }
117
+ const existing = await adapter.findByEmail(email);
118
+ if (existing) {
119
+ throw new AuthError("ACCOUNT_EXISTS", "An account already exists for this email");
120
+ }
121
+ const passwordHash = await password.hash(rawPassword);
122
+ let user;
123
+ try {
124
+ user = await adapter.model.create({
125
+ ...profile,
126
+ email,
127
+ [passwordHashField]: passwordHash,
128
+ });
129
+ }
130
+ catch (cause) {
131
+ // A unique email index may win a concurrent signup race.
132
+ if (typeof cause === "object" &&
133
+ cause !== null &&
134
+ "code" in cause &&
135
+ cause.code === 11000) {
136
+ throw new AuthError("ACCOUNT_EXISTS", "An account already exists for this email", { cause });
137
+ }
138
+ throw cause;
139
+ }
140
+ return createSession(user);
141
+ },
142
+ async login({ email: rawEmail, password: rawPassword }) {
143
+ const email = normalizedEmail(rawEmail);
144
+ if (typeof rawPassword !== "string" || rawPassword.length === 0) {
145
+ invalidInput("Password must be a non-empty string");
146
+ }
147
+ const user = await adapter.findByEmail(email);
148
+ if (!user) {
149
+ await password.verifyDummy(rawPassword);
150
+ throw new AuthError("UNAUTHORIZED", "Invalid email or password", {
151
+ publicMessage: "Invalid email or password",
152
+ });
153
+ }
154
+ const storedHash = readField(user, passwordHashField);
155
+ const matches = await password.verify(rawPassword, typeof storedHash === "string" ? storedHash : "");
156
+ if (!matches) {
157
+ throw new AuthError("UNAUTHORIZED", "Invalid email or password", {
158
+ publicMessage: "Invalid email or password",
159
+ });
160
+ }
161
+ const subject = subjectFor(adapter, user);
162
+ if (revokePreviousSessionsOnLogin) {
163
+ await refresh.revokeAllForSubject(subject);
164
+ }
165
+ return createSession(user);
166
+ },
167
+ };
168
+ }
169
+ //# sourceMappingURL=accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { CompactJWSHeaderParameters, KeyInput } from "jose";
2
+ import type { RefreshTokenStore } from "./refresh-store.js";
3
+ import { type AccountAdapter } from "./accounts.js";
4
+ export declare const DEFAULT_BCRYPT_ROUNDS = 12;
5
+ export declare const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 900;
6
+ export declare const SUPPORTED_ALGORITHMS: readonly ["HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512", "EdDSA"];
7
+ export type SupportedAlgorithm = (typeof SUPPORTED_ALGORITHMS)[number];
8
+ export type RuntimeMode = "development" | "production";
9
+ export type TokenKey = KeyInput;
10
+ export type KeyResolver = (header: CompactJWSHeaderParameters) => TokenKey | Promise<TokenKey>;
11
+ export interface AuthConfig<User = unknown> {
12
+ mode?: RuntimeMode;
13
+ password?: {
14
+ workFactor?: number;
15
+ };
16
+ accessToken: {
17
+ algorithm?: SupportedAlgorithm;
18
+ algorithms?: readonly SupportedAlgorithm[];
19
+ key: TokenKey;
20
+ keyId?: string;
21
+ keyResolver?: KeyResolver;
22
+ issuer?: string;
23
+ audience?: string | readonly string[];
24
+ expiresInSeconds?: number;
25
+ requiredClaims?: readonly string[];
26
+ isRevoked?: (claims: Readonly<Record<string, unknown>>, context?: unknown) => boolean | Promise<boolean>;
27
+ };
28
+ /** Omit to disable refresh-token support. A configured refresh store is mandatory. */
29
+ refreshToken?: {
30
+ store: RefreshTokenStore;
31
+ refreshTokenTtl: number;
32
+ absoluteLifetime: number;
33
+ };
34
+ /** Optional high-level register/login helpers using the app's model/query. */
35
+ accounts?: AccountAdapter<User>;
36
+ }
37
+ export interface ValidatedAuthConfig<User = unknown> {
38
+ mode: RuntimeMode;
39
+ password: {
40
+ workFactor: number;
41
+ };
42
+ accessToken: {
43
+ algorithm: SupportedAlgorithm;
44
+ algorithms: readonly SupportedAlgorithm[];
45
+ key: TokenKey;
46
+ keyId?: string;
47
+ keyResolver?: KeyResolver;
48
+ issuer?: string;
49
+ audience?: string | readonly string[];
50
+ expiresInSeconds: number;
51
+ requiredClaims: readonly string[];
52
+ isRevoked?: AuthConfig["accessToken"]["isRevoked"];
53
+ };
54
+ refreshToken?: {
55
+ store: RefreshTokenStore;
56
+ refreshTokenTtl: number;
57
+ absoluteLifetime: number;
58
+ };
59
+ accounts?: AccountAdapter<User>;
60
+ }
61
+ export declare function isReservedClaim(name: string): boolean;
62
+ export declare function validateAuthConfig<User = unknown>(config: AuthConfig<User>): ValidatedAuthConfig<User>;
63
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/config.js ADDED
@@ -0,0 +1,196 @@
1
+ import { AuthError } from "./errors.js";
2
+ import { validateAccountAdapter } from "./accounts.js";
3
+ export const DEFAULT_BCRYPT_ROUNDS = 12;
4
+ export const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 900;
5
+ const MAX_REFRESH_LIFETIME_SECONDS = 8_000_000_000_000;
6
+ export const SUPPORTED_ALGORITHMS = [
7
+ "HS256",
8
+ "HS384",
9
+ "HS512",
10
+ "RS256",
11
+ "RS384",
12
+ "RS512",
13
+ "PS256",
14
+ "PS384",
15
+ "PS512",
16
+ "ES256",
17
+ "ES384",
18
+ "ES512",
19
+ "EdDSA",
20
+ ];
21
+ const RESERVED_CLAIMS = new Set([
22
+ "iss",
23
+ "aud",
24
+ "exp",
25
+ "iat",
26
+ "nbf",
27
+ "jti",
28
+ "token_use",
29
+ ]);
30
+ export function isReservedClaim(name) {
31
+ return RESERVED_CLAIMS.has(name);
32
+ }
33
+ function invalid(message) {
34
+ throw new AuthError("INVALID_CONFIGURATION", message);
35
+ }
36
+ function validateKey(key, algorithm) {
37
+ if (algorithm.startsWith("HS")) {
38
+ if (!(key instanceof Uint8Array) || key.byteLength < 32) {
39
+ invalid("HMAC access-token keys must be Uint8Array values of at least 32 bytes");
40
+ }
41
+ return;
42
+ }
43
+ if (key instanceof Uint8Array) {
44
+ invalid(`${algorithm} requires a CryptoKey or KeyObject, not a byte array`);
45
+ }
46
+ }
47
+ export function validateAuthConfig(config) {
48
+ if (!config || typeof config !== "object") {
49
+ invalid("Configuration must be an object");
50
+ }
51
+ const mode = config.mode ?? "development";
52
+ if (mode !== "development" && mode !== "production") {
53
+ invalid('mode must be "development" or "production"');
54
+ }
55
+ if (config.password !== undefined &&
56
+ (typeof config.password !== "object" || config.password === null)) {
57
+ invalid("password must be an object when provided");
58
+ }
59
+ const workFactor = config.password?.workFactor ?? DEFAULT_BCRYPT_ROUNDS;
60
+ if (!Number.isInteger(workFactor) || workFactor < 4 || workFactor > 31) {
61
+ invalid("password.workFactor must be an integer between 4 and 31");
62
+ }
63
+ const tokenConfig = config.accessToken;
64
+ if (!tokenConfig || typeof tokenConfig !== "object" || !tokenConfig.key) {
65
+ invalid("accessToken.key is required");
66
+ }
67
+ const algorithm = tokenConfig.algorithm ?? "HS256";
68
+ if (!SUPPORTED_ALGORITHMS.includes(algorithm)) {
69
+ invalid("accessToken.algorithm is not supported");
70
+ }
71
+ const algorithms = [...new Set(tokenConfig.algorithms ?? [algorithm])];
72
+ if (algorithms.length === 0 ||
73
+ !algorithms.includes(algorithm) ||
74
+ algorithms.some((entry) => !SUPPORTED_ALGORITHMS.includes(entry))) {
75
+ invalid("accessToken.algorithms must be a non-empty allowlist containing the signing algorithm");
76
+ }
77
+ validateKey(tokenConfig.key, algorithm);
78
+ const expiresInSeconds = tokenConfig.expiresInSeconds ?? DEFAULT_ACCESS_TOKEN_TTL_SECONDS;
79
+ if (!Number.isSafeInteger(expiresInSeconds) || expiresInSeconds <= 0) {
80
+ invalid("accessToken.expiresInSeconds must be a positive safe integer");
81
+ }
82
+ if (tokenConfig.issuer !== undefined &&
83
+ (typeof tokenConfig.issuer !== "string" || tokenConfig.issuer.length === 0)) {
84
+ invalid("accessToken.issuer must be a non-empty string when provided");
85
+ }
86
+ if (tokenConfig.audience !== undefined) {
87
+ const audience = tokenConfig.audience;
88
+ if (!((typeof audience === "string" && audience.length > 0) ||
89
+ (Array.isArray(audience) &&
90
+ audience.length > 0 &&
91
+ audience.every((item) => typeof item === "string" && item.length > 0)))) {
92
+ invalid("accessToken.audience must contain non-empty string values");
93
+ }
94
+ }
95
+ if (mode === "production") {
96
+ if (!tokenConfig.issuer || !tokenConfig.audience) {
97
+ invalid("Production mode requires accessToken.issuer and accessToken.audience");
98
+ }
99
+ if (expiresInSeconds > 3600) {
100
+ invalid("Production access tokens must expire within one hour");
101
+ }
102
+ }
103
+ if (tokenConfig.keyId !== undefined && tokenConfig.keyId.length === 0) {
104
+ invalid("accessToken.keyId must be non-empty when provided");
105
+ }
106
+ if (tokenConfig.keyResolver !== undefined &&
107
+ typeof tokenConfig.keyResolver !== "function") {
108
+ invalid("accessToken.keyResolver must be a function");
109
+ }
110
+ if (tokenConfig.requiredClaims !== undefined &&
111
+ !Array.isArray(tokenConfig.requiredClaims)) {
112
+ invalid("accessToken.requiredClaims must be an array");
113
+ }
114
+ if (tokenConfig.isRevoked !== undefined &&
115
+ typeof tokenConfig.isRevoked !== "function") {
116
+ invalid("accessToken.isRevoked must be a function");
117
+ }
118
+ let refreshToken;
119
+ if (config.refreshToken !== undefined) {
120
+ const refreshConfig = config.refreshToken;
121
+ if (!refreshConfig || typeof refreshConfig !== "object") {
122
+ invalid("refreshToken must be an object when provided");
123
+ }
124
+ const store = refreshConfig.store;
125
+ if (!store ||
126
+ typeof store.create !== "function" ||
127
+ typeof store.consume !== "function" ||
128
+ typeof store.revokeToken !== "function" ||
129
+ typeof store.revokeFamily !== "function" ||
130
+ typeof store.revokeAllForSubject !== "function") {
131
+ invalid("refreshToken.store must implement the complete RefreshTokenStore interface");
132
+ }
133
+ if (!Number.isSafeInteger(refreshConfig.refreshTokenTtl) ||
134
+ refreshConfig.refreshTokenTtl <= 0 ||
135
+ refreshConfig.refreshTokenTtl > MAX_REFRESH_LIFETIME_SECONDS) {
136
+ invalid("refreshToken.refreshTokenTtl must be a positive safe integer in seconds");
137
+ }
138
+ if (!Number.isSafeInteger(refreshConfig.absoluteLifetime) ||
139
+ refreshConfig.absoluteLifetime <= 0 ||
140
+ refreshConfig.absoluteLifetime > MAX_REFRESH_LIFETIME_SECONDS) {
141
+ invalid("refreshToken.absoluteLifetime must be a positive safe integer in seconds");
142
+ }
143
+ refreshToken = {
144
+ store,
145
+ refreshTokenTtl: refreshConfig.refreshTokenTtl,
146
+ absoluteLifetime: refreshConfig.absoluteLifetime,
147
+ };
148
+ }
149
+ if (config.accounts !== undefined) {
150
+ // Account helpers issue both tokens, so they require a configured store.
151
+ if (!refreshToken) {
152
+ invalid("accounts requires refreshToken.store to be configured");
153
+ }
154
+ validateAccountAdapter(config.accounts);
155
+ }
156
+ const requiredClaims = [
157
+ ...new Set([
158
+ "sub",
159
+ "iat",
160
+ "exp",
161
+ ...(tokenConfig.issuer ? ["iss"] : []),
162
+ ...(tokenConfig.audience ? ["aud"] : []),
163
+ ...(tokenConfig.requiredClaims ?? []),
164
+ ]),
165
+ ];
166
+ if (requiredClaims.some((claim) => typeof claim !== "string" || !claim)) {
167
+ invalid("accessToken.requiredClaims must contain non-empty claim names");
168
+ }
169
+ return {
170
+ mode,
171
+ password: { workFactor },
172
+ accessToken: {
173
+ algorithm,
174
+ algorithms,
175
+ key: tokenConfig.key,
176
+ ...(tokenConfig.keyId === undefined ? {} : { keyId: tokenConfig.keyId }),
177
+ ...(tokenConfig.keyResolver === undefined
178
+ ? {}
179
+ : { keyResolver: tokenConfig.keyResolver }),
180
+ ...(tokenConfig.issuer === undefined
181
+ ? {}
182
+ : { issuer: tokenConfig.issuer }),
183
+ ...(tokenConfig.audience === undefined
184
+ ? {}
185
+ : { audience: tokenConfig.audience }),
186
+ expiresInSeconds,
187
+ requiredClaims,
188
+ ...(tokenConfig.isRevoked === undefined
189
+ ? {}
190
+ : { isRevoked: tokenConfig.isRevoked }),
191
+ },
192
+ ...(refreshToken === undefined ? {} : { refreshToken }),
193
+ ...(config.accounts === undefined ? {} : { accounts: config.accounts }),
194
+ };
195
+ }
196
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,sBAAsB,EAAuB,MAAM,eAAe,CAAC;AAE5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AACxC,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AACpD,MAAM,4BAA4B,GAAG,iBAAiB,CAAC;AACvD,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;CACC,CAAC;AA8DX,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,WAAW;CACZ,CAAC,CAAC;AAEH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,OAAO,CAAC,OAAe;IAC9B,MAAM,IAAI,SAAS,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,WAAW,CAAC,GAAa,EAAE,SAA6B;IAC/D,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC,CAAC,GAAG,YAAY,UAAU,CAAC,IAAI,GAAG,CAAC,UAAU,GAAG,EAAE,EAAE,CAAC;YACxD,OAAO,CACL,uEAAuE,CACxE,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,GAAG,YAAY,UAAU,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,SAAS,sDAAsD,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAwB;IAExB,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,CAAC,iCAAiC,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,aAAa,CAAC;IAC1C,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QACpD,OAAO,CAAC,4CAA4C,CAAC,CAAC;IACxD,CAAC;IAED,IACE,MAAM,CAAC,QAAQ,KAAK,SAAS;QAC7B,CAAC,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,EACjE,CAAC;QACD,OAAO,CAAC,0CAA0C,CAAC,CAAC;IACtD,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,EAAE,UAAU,IAAI,qBAAqB,CAAC;IACxE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,IAAI,UAAU,GAAG,EAAE,EAAE,CAAC;QACvE,OAAO,CAAC,yDAAyD,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IACvC,IAAI,CAAC,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;QACxE,OAAO,CAAC,6BAA6B,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,SAAS,GAAG,WAAW,CAAC,SAAS,IAAI,OAAO,CAAC;IACnD,IAAI,CAAE,oBAA0C,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACrE,OAAO,CAAC,wCAAwC,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,UAAU,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACvE,IACE,UAAU,CAAC,MAAM,KAAK,CAAC;QACvB,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,UAAU,CAAC,IAAI,CACb,CAAC,KAAK,EAAE,EAAE,CAAC,CAAE,oBAA0C,CAAC,QAAQ,CAAC,KAAK,CAAC,CACxE,EACD,CAAC;QACD,OAAO,CACL,uFAAuF,CACxF,CAAC;IACJ,CAAC;IACD,WAAW,CAAC,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAExC,MAAM,gBAAgB,GACpB,WAAW,CAAC,gBAAgB,IAAI,gCAAgC,CAAC;IACnE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,IAAI,gBAAgB,IAAI,CAAC,EAAE,CAAC;QACrE,OAAO,CAAC,8DAA8D,CAAC,CAAC;IAC1E,CAAC;IACD,IACE,WAAW,CAAC,MAAM,KAAK,SAAS;QAChC,CAAC,OAAO,WAAW,CAAC,MAAM,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,EAC3E,CAAC;QACD,OAAO,CAAC,6DAA6D,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,WAAW,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;QACtC,IAAI,CAAC,CACH,CAAC,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YACrD,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACtB,QAAQ,CAAC,MAAM,GAAG,CAAC;gBACnB,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CACzE,EAAE,CAAC;YACF,OAAO,CAAC,2DAA2D,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IACD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YACjD,OAAO,CACL,sEAAsE,CACvE,CAAC;QACJ,CAAC;QACD,IAAI,gBAAgB,GAAG,IAAI,EAAE,CAAC;YAC5B,OAAO,CAAC,sDAAsD,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IACD,IAAI,WAAW,CAAC,KAAK,KAAK,SAAS,IAAI,WAAW,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtE,OAAO,CAAC,mDAAmD,CAAC,CAAC;IAC/D,CAAC;IACD,IACE,WAAW,CAAC,WAAW,KAAK,SAAS;QACrC,OAAO,WAAW,CAAC,WAAW,KAAK,UAAU,EAC7C,CAAC;QACD,OAAO,CAAC,4CAA4C,CAAC,CAAC;IACxD,CAAC;IACD,IACE,WAAW,CAAC,cAAc,KAAK,SAAS;QACxC,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,cAAc,CAAC,EAC1C,CAAC;QACD,OAAO,CAAC,6CAA6C,CAAC,CAAC;IACzD,CAAC;IACD,IACE,WAAW,CAAC,SAAS,KAAK,SAAS;QACnC,OAAO,WAAW,CAAC,SAAS,KAAK,UAAU,EAC3C,CAAC;QACD,OAAO,CAAC,0CAA0C,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,YAAiD,CAAC;IACtD,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,aAAa,GAAG,MAAM,CAAC,YAAY,CAAC;QAC1C,IAAI,CAAC,aAAa,IAAI,OAAO,aAAa,KAAK,QAAQ,EAAE,CAAC;YACxD,OAAO,CAAC,8CAA8C,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,KAAK,GAAG,aAAa,CAAC,KAC+B,CAAC;QAC5D,IACE,CAAC,KAAK;YACN,OAAO,KAAK,CAAC,MAAM,KAAK,UAAU;YAClC,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU;YACnC,OAAO,KAAK,CAAC,WAAW,KAAK,UAAU;YACvC,OAAO,KAAK,CAAC,YAAY,KAAK,UAAU;YACxC,OAAO,KAAK,CAAC,mBAAmB,KAAK,UAAU,EAC/C,CAAC;YACD,OAAO,CACL,4EAA4E,CAC7E,CAAC;QACJ,CAAC;QACD,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,eAAe,CAAC;YACpD,aAAa,CAAC,eAAe,IAAI,CAAC;YAClC,aAAa,CAAC,eAAe,GAAG,4BAA4B,EAC5D,CAAC;YACD,OAAO,CACL,yEAAyE,CAC1E,CAAC;QACJ,CAAC;QACD,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,gBAAgB,CAAC;YACrD,aAAa,CAAC,gBAAgB,IAAI,CAAC;YACnC,aAAa,CAAC,gBAAgB,GAAG,4BAA4B,EAC7D,CAAC;YACD,OAAO,CACL,0EAA0E,CAC3E,CAAC;QACJ,CAAC;QACD,YAAY,GAAG;YACb,KAAK;YACL,eAAe,EAAE,aAAa,CAAC,eAAe;YAC9C,gBAAgB,EAAE,aAAa,CAAC,gBAAgB;SACjD,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,yEAAyE;QACzE,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,CAAC,uDAAuD,CAAC,CAAC;QACnE,CAAC;QACD,sBAAsB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,cAAc,GAAG;QACrB,GAAG,IAAI,GAAG,CAAC;YACT,KAAK;YACL,KAAK;YACL,KAAK;YACL,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxC,GAAG,CAAC,WAAW,CAAC,cAAc,IAAI,EAAE,CAAC;SACtC,CAAC;KACH,CAAC;IACF,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,CAAC,+DAA+D,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO;QACL,IAAI;QACJ,QAAQ,EAAE,EAAE,UAAU,EAAE;QACxB,WAAW,EAAE;YACX,SAAS;YACT,UAAU;YACV,GAAG,EAAE,WAAW,CAAC,GAAG;YACpB,GAAG,CAAC,WAAW,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,CAAC;YACxE,GAAG,CAAC,WAAW,CAAC,WAAW,KAAK,SAAS;gBACvC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,WAAW,EAAE,WAAW,CAAC,WAAW,EAAE,CAAC;YAC7C,GAAG,CAAC,WAAW,CAAC,MAAM,KAAK,SAAS;gBAClC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC;YACnC,GAAG,CAAC,WAAW,CAAC,QAAQ,KAAK,SAAS;gBACpC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAAE,CAAC;YACvC,gBAAgB;YAChB,cAAc;YACd,GAAG,CAAC,WAAW,CAAC,SAAS,KAAK,SAAS;gBACrC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,SAAS,EAAE,CAAC;SAC1C;QACD,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;QACvD,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;KACxE,CAAC;AACJ,CAAC"}
@@ -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", "ACCOUNT_EXISTS", "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,8NAYnB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AA8B9D,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,57 @@
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
+ "ACCOUNT_EXISTS",
9
+ "UNAUTHORIZED",
10
+ "FORBIDDEN",
11
+ "VALIDATION_ERROR",
12
+ "INVALID_CONFIGURATION",
13
+ ];
14
+ const HTTP_STATUS = {
15
+ TOKEN_MISSING: 401,
16
+ TOKEN_INVALID: 401,
17
+ TOKEN_EXPIRED: 401,
18
+ REFRESH_TOKEN_INVALID: 401,
19
+ REFRESH_TOKEN_REUSED: 401,
20
+ SESSION_REVOKED: 401,
21
+ ACCOUNT_EXISTS: 409,
22
+ UNAUTHORIZED: 401,
23
+ FORBIDDEN: 403,
24
+ VALIDATION_ERROR: 400,
25
+ INVALID_CONFIGURATION: 500,
26
+ };
27
+ const PUBLIC_MESSAGES = {
28
+ TOKEN_MISSING: "Authentication is required",
29
+ TOKEN_INVALID: "Authentication failed",
30
+ TOKEN_EXPIRED: "Authentication has expired",
31
+ REFRESH_TOKEN_INVALID: "Refresh token is invalid",
32
+ REFRESH_TOKEN_REUSED: "Refresh token is invalid",
33
+ SESSION_REVOKED: "Authentication has been revoked",
34
+ ACCOUNT_EXISTS: "An account already exists",
35
+ UNAUTHORIZED: "Authentication is required",
36
+ FORBIDDEN: "You are not allowed to perform this action",
37
+ VALIDATION_ERROR: "The request is invalid",
38
+ INVALID_CONFIGURATION: "Authentication is unavailable",
39
+ };
40
+ export class AuthError extends Error {
41
+ code;
42
+ developerMessage;
43
+ publicMessage;
44
+ status;
45
+ constructor(code, developerMessage, options = {}) {
46
+ super(developerMessage, { cause: options.cause });
47
+ this.name = "AuthError";
48
+ this.code = code;
49
+ this.developerMessage = developerMessage;
50
+ this.publicMessage = options.publicMessage ?? PUBLIC_MESSAGES[code];
51
+ this.status = options.status ?? HTTP_STATUS[code];
52
+ }
53
+ }
54
+ export function getHttpStatus(code) {
55
+ return HTTP_STATUS[code];
56
+ }
57
+ //# 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,gBAAgB;IAChB,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,cAAc,EAAE,GAAG;IACnB,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,cAAc,EAAE,2BAA2B;IAC3C,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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"}