@veloxts/auth 0.3.3 → 0.3.4

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 (54) hide show
  1. package/README.md +755 -30
  2. package/dist/adapter.d.ts +710 -0
  3. package/dist/adapter.d.ts.map +1 -0
  4. package/dist/adapter.js +581 -0
  5. package/dist/adapter.js.map +1 -0
  6. package/dist/adapters/better-auth.d.ts +271 -0
  7. package/dist/adapters/better-auth.d.ts.map +1 -0
  8. package/dist/adapters/better-auth.js +341 -0
  9. package/dist/adapters/better-auth.js.map +1 -0
  10. package/dist/adapters/index.d.ts +28 -0
  11. package/dist/adapters/index.d.ts.map +1 -0
  12. package/dist/adapters/index.js +28 -0
  13. package/dist/adapters/index.js.map +1 -0
  14. package/dist/csrf.d.ts +294 -0
  15. package/dist/csrf.d.ts.map +1 -0
  16. package/dist/csrf.js +396 -0
  17. package/dist/csrf.js.map +1 -0
  18. package/dist/guards.d.ts +139 -0
  19. package/dist/guards.d.ts.map +1 -0
  20. package/dist/guards.js +247 -0
  21. package/dist/guards.js.map +1 -0
  22. package/dist/hash.d.ts +85 -0
  23. package/dist/hash.d.ts.map +1 -0
  24. package/dist/hash.js +220 -0
  25. package/dist/hash.js.map +1 -0
  26. package/dist/index.d.ts +25 -32
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +63 -36
  29. package/dist/index.js.map +1 -1
  30. package/dist/jwt.d.ts +128 -0
  31. package/dist/jwt.d.ts.map +1 -0
  32. package/dist/jwt.js +363 -0
  33. package/dist/jwt.js.map +1 -0
  34. package/dist/middleware.d.ts +87 -0
  35. package/dist/middleware.d.ts.map +1 -0
  36. package/dist/middleware.js +241 -0
  37. package/dist/middleware.js.map +1 -0
  38. package/dist/plugin.d.ts +107 -0
  39. package/dist/plugin.d.ts.map +1 -0
  40. package/dist/plugin.js +174 -0
  41. package/dist/plugin.js.map +1 -0
  42. package/dist/policies.d.ts +137 -0
  43. package/dist/policies.d.ts.map +1 -0
  44. package/dist/policies.js +240 -0
  45. package/dist/policies.js.map +1 -0
  46. package/dist/session.d.ts +494 -0
  47. package/dist/session.d.ts.map +1 -0
  48. package/dist/session.js +795 -0
  49. package/dist/session.js.map +1 -0
  50. package/dist/types.d.ts +251 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +33 -0
  53. package/dist/types.js.map +1 -0
  54. package/package.json +38 -7
package/dist/jwt.js ADDED
@@ -0,0 +1,363 @@
1
+ /**
2
+ * JWT token utilities for @veloxts/auth
3
+ * @module auth/jwt
4
+ */
5
+ import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
6
+ // ============================================================================
7
+ // Constants
8
+ // ============================================================================
9
+ const DEFAULT_ACCESS_EXPIRY = '15m';
10
+ const DEFAULT_REFRESH_EXPIRY = '7d';
11
+ /**
12
+ * Minimum JWT secret length (64 characters = 512 bits)
13
+ * HS256 requires at least 256 bits, but we require 512 for extra security margin
14
+ */
15
+ const MIN_SECRET_LENGTH = 64;
16
+ /**
17
+ * Minimum unique characters in secret for entropy validation
18
+ */
19
+ const MIN_SECRET_ENTROPY_CHARS = 16;
20
+ /**
21
+ * Reserved JWT claims that cannot be overridden via additionalClaims
22
+ */
23
+ const RESERVED_JWT_CLAIMS = new Set([
24
+ 'sub',
25
+ 'iss',
26
+ 'aud',
27
+ 'exp',
28
+ 'iat',
29
+ 'jti',
30
+ 'nbf',
31
+ 'type',
32
+ 'email',
33
+ ]);
34
+ // ============================================================================
35
+ // JWT Implementation
36
+ // ============================================================================
37
+ /**
38
+ * Parses time string to seconds
39
+ * Supports: '15m', '1h', '7d', '30d', etc.
40
+ */
41
+ export function parseTimeToSeconds(time) {
42
+ const match = time.match(/^(\d+)([smhd])$/);
43
+ if (!match) {
44
+ throw new Error(`Invalid time format: ${time}. Use format like '15m', '1h', '7d'`);
45
+ }
46
+ const value = parseInt(match[1], 10);
47
+ const unit = match[2];
48
+ switch (unit) {
49
+ case 's':
50
+ return value;
51
+ case 'm':
52
+ return value * 60;
53
+ case 'h':
54
+ return value * 60 * 60;
55
+ case 'd':
56
+ return value * 60 * 60 * 24;
57
+ default:
58
+ throw new Error(`Unknown time unit: ${unit}`);
59
+ }
60
+ }
61
+ /**
62
+ * Base64url encode
63
+ */
64
+ function base64urlEncode(data) {
65
+ const base64 = Buffer.from(data).toString('base64');
66
+ return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
67
+ }
68
+ /**
69
+ * Base64url decode
70
+ */
71
+ function base64urlDecode(data) {
72
+ const base64 = data.replace(/-/g, '+').replace(/_/g, '/');
73
+ const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);
74
+ return Buffer.from(padded, 'base64').toString('utf8');
75
+ }
76
+ /**
77
+ * Create HMAC-SHA256 signature
78
+ */
79
+ function createSignature(data, secret) {
80
+ const hmac = createHmac('sha256', secret);
81
+ hmac.update(data);
82
+ return base64urlEncode(hmac.digest());
83
+ }
84
+ /**
85
+ * Generate a unique token ID
86
+ */
87
+ export function generateTokenId() {
88
+ return randomBytes(16).toString('hex');
89
+ }
90
+ // ============================================================================
91
+ // JWT Manager Class
92
+ // ============================================================================
93
+ /**
94
+ * JWT token manager
95
+ *
96
+ * Handles token creation, verification, and refresh.
97
+ * Uses HS256 (HMAC-SHA256) algorithm.
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const jwt = new JwtManager({
102
+ * secret: process.env.JWT_SECRET!,
103
+ * accessTokenExpiry: '15m',
104
+ * refreshTokenExpiry: '7d',
105
+ * });
106
+ *
107
+ * // Create tokens for user
108
+ * const tokens = jwt.createTokenPair(user);
109
+ *
110
+ * // Verify access token
111
+ * const payload = jwt.verifyToken(tokens.accessToken);
112
+ *
113
+ * // Refresh tokens
114
+ * const newTokens = jwt.refreshTokens(tokens.refreshToken);
115
+ * ```
116
+ */
117
+ export class JwtManager {
118
+ config;
119
+ constructor(config) {
120
+ // Validate secret length (Critical Fix #1)
121
+ if (!config.secret || config.secret.length < MIN_SECRET_LENGTH) {
122
+ throw new Error(`JWT secret must be at least ${MIN_SECRET_LENGTH} characters long (512 bits). ` +
123
+ 'Generate with: openssl rand -base64 64');
124
+ }
125
+ // Validate secret entropy - check for sufficient unique characters
126
+ const uniqueChars = new Set(config.secret).size;
127
+ if (uniqueChars < MIN_SECRET_ENTROPY_CHARS) {
128
+ throw new Error(`JWT secret has insufficient entropy (only ${uniqueChars} unique characters). ` +
129
+ 'Use cryptographically random data with at least 16 unique characters.');
130
+ }
131
+ this.config = {
132
+ ...config,
133
+ accessTokenExpiry: config.accessTokenExpiry ?? DEFAULT_ACCESS_EXPIRY,
134
+ refreshTokenExpiry: config.refreshTokenExpiry ?? DEFAULT_REFRESH_EXPIRY,
135
+ };
136
+ }
137
+ /**
138
+ * Creates a JWT token with the given payload
139
+ */
140
+ createToken(payload, expiresIn) {
141
+ const now = Math.floor(Date.now() / 1000);
142
+ const exp = now + parseTimeToSeconds(expiresIn);
143
+ const fullPayload = {
144
+ ...payload,
145
+ iat: now,
146
+ exp,
147
+ };
148
+ // Create header
149
+ const header = { alg: 'HS256', typ: 'JWT' };
150
+ const encodedHeader = base64urlEncode(JSON.stringify(header));
151
+ const encodedPayload = base64urlEncode(JSON.stringify(fullPayload));
152
+ // Create signature
153
+ const signatureInput = `${encodedHeader}.${encodedPayload}`;
154
+ const signature = createSignature(signatureInput, this.config.secret);
155
+ return `${signatureInput}.${signature}`;
156
+ }
157
+ /**
158
+ * Verifies a JWT token and returns the payload
159
+ *
160
+ * @throws Error if token is invalid or expired
161
+ */
162
+ verifyToken(token) {
163
+ const parts = token.split('.');
164
+ if (parts.length !== 3) {
165
+ throw new Error('Invalid token format');
166
+ }
167
+ const [encodedHeader, encodedPayload, signature] = parts;
168
+ // Critical Fix #2: Validate algorithm BEFORE signature verification
169
+ // This prevents algorithm confusion attacks (CVE-2015-9235)
170
+ let header;
171
+ try {
172
+ header = JSON.parse(base64urlDecode(encodedHeader));
173
+ }
174
+ catch {
175
+ throw new Error('Invalid token header');
176
+ }
177
+ // Only allow HS256 - reject "none", RS256, and other algorithms
178
+ if (header.alg !== 'HS256') {
179
+ throw new Error(`Invalid algorithm: ${header.alg}. Only HS256 is supported.`);
180
+ }
181
+ if (header.typ !== 'JWT') {
182
+ throw new Error('Invalid token type in header');
183
+ }
184
+ // Verify signature using timing-safe comparison to prevent timing attacks
185
+ const signatureInput = `${encodedHeader}.${encodedPayload}`;
186
+ const expectedSignature = createSignature(signatureInput, this.config.secret);
187
+ const sigBuffer = Buffer.from(signature, 'utf8');
188
+ const expectedBuffer = Buffer.from(expectedSignature, 'utf8');
189
+ if (sigBuffer.length !== expectedBuffer.length || !timingSafeEqual(sigBuffer, expectedBuffer)) {
190
+ throw new Error('Invalid token signature');
191
+ }
192
+ // Decode payload
193
+ let payload;
194
+ try {
195
+ const decoded = JSON.parse(base64urlDecode(encodedPayload));
196
+ // Validate required fields
197
+ if (typeof decoded.sub !== 'string' ||
198
+ typeof decoded.email !== 'string' ||
199
+ typeof decoded.iat !== 'number' ||
200
+ typeof decoded.exp !== 'number' ||
201
+ (decoded.type !== 'access' && decoded.type !== 'refresh')) {
202
+ throw new Error('Missing required token fields');
203
+ }
204
+ payload = decoded;
205
+ }
206
+ catch (error) {
207
+ throw new Error(error instanceof Error ? error.message : 'Invalid token payload');
208
+ }
209
+ // Check expiration
210
+ const now = Math.floor(Date.now() / 1000);
211
+ if (payload.exp < now) {
212
+ throw new Error('Token has expired');
213
+ }
214
+ // Check not-before claim if present (Medium Fix #10)
215
+ if (typeof payload.nbf === 'number' && payload.nbf > now) {
216
+ throw new Error('Token not yet valid');
217
+ }
218
+ // Verify issuer if configured
219
+ if (this.config.issuer && payload.iss !== this.config.issuer) {
220
+ throw new Error('Invalid token issuer');
221
+ }
222
+ // Verify audience if configured
223
+ if (this.config.audience && payload.aud !== this.config.audience) {
224
+ throw new Error('Invalid token audience');
225
+ }
226
+ return payload;
227
+ }
228
+ /**
229
+ * Creates an access/refresh token pair for a user
230
+ *
231
+ * @param user - The user to create tokens for
232
+ * @param additionalClaims - Custom claims to include (cannot override reserved claims)
233
+ * @throws Error if additionalClaims contains reserved JWT claims
234
+ */
235
+ createTokenPair(user, additionalClaims) {
236
+ // Critical Fix #3: Validate additionalClaims don't contain reserved claims
237
+ if (additionalClaims) {
238
+ for (const key of Object.keys(additionalClaims)) {
239
+ if (RESERVED_JWT_CLAIMS.has(key)) {
240
+ throw new Error(`Cannot override reserved JWT claim: ${key}. ` +
241
+ `Reserved claims are: ${[...RESERVED_JWT_CLAIMS].join(', ')}`);
242
+ }
243
+ }
244
+ }
245
+ const tokenId = generateTokenId();
246
+ const basePayload = {
247
+ sub: user.id,
248
+ email: user.email,
249
+ jti: tokenId,
250
+ ...(this.config.issuer && { iss: this.config.issuer }),
251
+ ...(this.config.audience && { aud: this.config.audience }),
252
+ ...additionalClaims,
253
+ };
254
+ const accessToken = this.createToken({ ...basePayload, type: 'access' }, this.config.accessTokenExpiry);
255
+ const refreshToken = this.createToken({ ...basePayload, type: 'refresh' }, this.config.refreshTokenExpiry);
256
+ return {
257
+ accessToken,
258
+ refreshToken,
259
+ expiresIn: parseTimeToSeconds(this.config.accessTokenExpiry),
260
+ tokenType: 'Bearer',
261
+ };
262
+ }
263
+ refreshTokens(refreshToken, userLoader) {
264
+ const payload = this.verifyToken(refreshToken);
265
+ if (payload.type !== 'refresh') {
266
+ throw new Error('Invalid token type: expected refresh token');
267
+ }
268
+ // If userLoader provided, fetch fresh user data
269
+ if (userLoader) {
270
+ return userLoader(payload.sub).then((user) => {
271
+ if (!user) {
272
+ throw new Error('User not found');
273
+ }
274
+ return this.createTokenPair(user);
275
+ });
276
+ }
277
+ // Otherwise, create new tokens from payload data
278
+ const user = {
279
+ id: payload.sub,
280
+ email: payload.email,
281
+ };
282
+ return this.createTokenPair(user);
283
+ }
284
+ /**
285
+ * Decodes a token without verification
286
+ * Useful for extracting payload from expired tokens
287
+ */
288
+ decodeToken(token) {
289
+ try {
290
+ const parts = token.split('.');
291
+ if (parts.length !== 3) {
292
+ return null;
293
+ }
294
+ return JSON.parse(base64urlDecode(parts[1]));
295
+ }
296
+ catch {
297
+ return null;
298
+ }
299
+ }
300
+ /**
301
+ * Extracts token from Authorization header
302
+ * Supports 'Bearer <token>' format
303
+ */
304
+ extractFromHeader(authHeader) {
305
+ if (!authHeader) {
306
+ return null;
307
+ }
308
+ const parts = authHeader.split(' ');
309
+ if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {
310
+ return null;
311
+ }
312
+ return parts[1];
313
+ }
314
+ }
315
+ /**
316
+ * Creates a new JWT manager instance
317
+ */
318
+ export function createJwtManager(config) {
319
+ return new JwtManager(config);
320
+ }
321
+ /**
322
+ * Creates an in-memory token store for development and testing
323
+ *
324
+ * ⚠️ WARNING: NOT suitable for production!
325
+ * - Does not persist across server restarts
326
+ * - Does not work across multiple server instances
327
+ * - No automatic cleanup of expired token IDs
328
+ *
329
+ * For production, use Redis or database-backed storage:
330
+ * - upstash/redis for serverless
331
+ * - ioredis for traditional servers
332
+ * - Database table for audit trail
333
+ *
334
+ * @example
335
+ * ```typescript
336
+ * // Development/Testing
337
+ * const tokenStore = createInMemoryTokenStore();
338
+ *
339
+ * const authConfig: AuthConfig = {
340
+ * jwt: { secret: process.env.JWT_SECRET! },
341
+ * isTokenRevoked: tokenStore.isRevoked,
342
+ * };
343
+ *
344
+ * // Revoke on logout
345
+ * app.post('/logout', async (req) => {
346
+ * const tokenId = req.auth.token.jti;
347
+ * tokenStore.revoke(tokenId);
348
+ * });
349
+ * ```
350
+ */
351
+ export function createInMemoryTokenStore() {
352
+ const revokedTokens = new Set();
353
+ return {
354
+ revoke: (tokenId) => {
355
+ revokedTokens.add(tokenId);
356
+ },
357
+ isRevoked: (tokenId) => revokedTokens.has(tokenId),
358
+ clear: () => {
359
+ revokedTokens.clear();
360
+ },
361
+ };
362
+ }
363
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../src/jwt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Authentication middleware for @veloxts/auth
3
+ * @module auth/middleware
4
+ */
5
+ import type { BaseContext } from '@veloxts/core';
6
+ import type { MiddlewareFunction } from '@veloxts/router';
7
+ import { JwtManager } from './jwt.js';
8
+ import type { AuthConfig, AuthContext, AuthMiddlewareOptions, GuardDefinition, User } from './types.js';
9
+ /**
10
+ * Creates an authentication middleware for procedures
11
+ *
12
+ * This middleware:
13
+ * 1. Extracts JWT from Authorization header
14
+ * 2. Verifies the token
15
+ * 3. Loads user from database (if userLoader provided)
16
+ * 4. Adds user and auth context to ctx
17
+ * 5. Runs guards if specified
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const auth = createAuthMiddleware(authConfig);
22
+ *
23
+ * // Use in procedures
24
+ * const getProfile = procedure()
25
+ * .use(auth.middleware())
26
+ * .query(async ({ ctx }) => {
27
+ * return ctx.user; // Guaranteed to exist
28
+ * });
29
+ *
30
+ * // Optional auth (user may be undefined)
31
+ * const getPosts = procedure()
32
+ * .use(auth.middleware({ optional: true }))
33
+ * .query(async ({ ctx }) => {
34
+ * // ctx.user may be undefined
35
+ * return fetchPosts(ctx.user?.id);
36
+ * });
37
+ *
38
+ * // With guards
39
+ * const adminOnly = procedure()
40
+ * .use(auth.middleware({ guards: [hasRole('admin')] }))
41
+ * .query(async ({ ctx }) => {
42
+ * // Only admins get here
43
+ * });
44
+ * ```
45
+ */
46
+ export declare function createAuthMiddleware(config: AuthConfig): {
47
+ middleware: <TInput, TContext extends BaseContext, TOutput>(options?: AuthMiddlewareOptions) => MiddlewareFunction<TInput, TContext, TContext & {
48
+ user?: User;
49
+ auth: AuthContext;
50
+ }, TOutput>;
51
+ requireAuth: <TInput, TContext extends BaseContext, TOutput>(guards?: Array<GuardDefinition | string>) => MiddlewareFunction<TInput, TContext, TContext & {
52
+ user: User;
53
+ auth: AuthContext;
54
+ }, TOutput>;
55
+ optionalAuth: <TInput, TContext extends BaseContext, TOutput>() => MiddlewareFunction<TInput, TContext, TContext & {
56
+ user?: User;
57
+ auth: AuthContext;
58
+ }, TOutput>;
59
+ jwt: JwtManager;
60
+ };
61
+ /**
62
+ * Creates a rate limiting middleware
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * const rateLimit = createRateLimitMiddleware({
67
+ * max: 100,
68
+ * windowMs: 60000, // 1 minute
69
+ * });
70
+ *
71
+ * const login = procedure()
72
+ * .use(rateLimit)
73
+ * .input(LoginSchema)
74
+ * .mutation(handler);
75
+ * ```
76
+ */
77
+ export declare function createRateLimitMiddleware<TInput, TContext extends BaseContext, TOutput>(options: {
78
+ max?: number;
79
+ windowMs?: number;
80
+ keyGenerator?: (ctx: TContext) => string;
81
+ message?: string;
82
+ }): MiddlewareFunction<TInput, TContext, TContext, TOutput>;
83
+ /**
84
+ * Clears rate limit store (useful for testing)
85
+ */
86
+ export declare function clearRateLimitStore(): void;
87
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG1D,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,qBAAqB,EACrB,eAAe,EAEf,IAAI,EACL,MAAM,YAAY,CAAC;AAOpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU;iBAMjC,MAAM,EAAE,QAAQ,SAAS,WAAW,EAAE,OAAO,YACtD,qBAAqB,KAC7B,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG;QAAE,IAAI,CAAC,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,EAAE,OAAO,CAAC;kBA8H1E,MAAM,EAAE,QAAQ,SAAS,WAAW,EAAE,OAAO,WACvD,KAAK,CAAC,eAAe,GAAG,MAAM,CAAC,KACvC,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,EAAE,OAAO,CAAC;mBAYxE,MAAM,EAAE,QAAQ,SAAS,WAAW,EAAE,OAAO,OAAK,kBAAkB,CACxF,MAAM,EACN,QAAQ,EACR,QAAQ,GAAG;QAAE,IAAI,CAAC,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,EAC7C,OAAO,CACR;;EAUF;AAkBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,QAAQ,SAAS,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE;IAChG,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAuC1D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}