@parsrun/auth 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 (54) hide show
  1. package/README.md +133 -0
  2. package/dist/adapters/hono.d.ts +9 -0
  3. package/dist/adapters/hono.js +6 -0
  4. package/dist/adapters/hono.js.map +1 -0
  5. package/dist/adapters/index.d.ts +9 -0
  6. package/dist/adapters/index.js +7 -0
  7. package/dist/adapters/index.js.map +1 -0
  8. package/dist/authorization-By1Xp8Za.d.ts +213 -0
  9. package/dist/base-BKyR8rcE.d.ts +646 -0
  10. package/dist/chunk-42MGHABB.js +263 -0
  11. package/dist/chunk-42MGHABB.js.map +1 -0
  12. package/dist/chunk-7GOBAL4G.js +3 -0
  13. package/dist/chunk-7GOBAL4G.js.map +1 -0
  14. package/dist/chunk-G5I3T73A.js +152 -0
  15. package/dist/chunk-G5I3T73A.js.map +1 -0
  16. package/dist/chunk-IB4WUQDZ.js +410 -0
  17. package/dist/chunk-IB4WUQDZ.js.map +1 -0
  18. package/dist/chunk-MOG4Y6I7.js +415 -0
  19. package/dist/chunk-MOG4Y6I7.js.map +1 -0
  20. package/dist/chunk-NK4TJV2W.js +295 -0
  21. package/dist/chunk-NK4TJV2W.js.map +1 -0
  22. package/dist/chunk-RHNVRCF3.js +838 -0
  23. package/dist/chunk-RHNVRCF3.js.map +1 -0
  24. package/dist/chunk-YTCPXJR5.js +570 -0
  25. package/dist/chunk-YTCPXJR5.js.map +1 -0
  26. package/dist/cloudflare-kv-L64CZKDK.js +105 -0
  27. package/dist/cloudflare-kv-L64CZKDK.js.map +1 -0
  28. package/dist/deno-kv-F55HKKP6.js +111 -0
  29. package/dist/deno-kv-F55HKKP6.js.map +1 -0
  30. package/dist/index-C3kz9XqE.d.ts +226 -0
  31. package/dist/index-DOGcetyD.d.ts +1041 -0
  32. package/dist/index.d.ts +1579 -0
  33. package/dist/index.js +4294 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/jwt-manager-CH8H0kmm.d.ts +182 -0
  36. package/dist/providers/index.d.ts +90 -0
  37. package/dist/providers/index.js +3 -0
  38. package/dist/providers/index.js.map +1 -0
  39. package/dist/providers/otp/index.d.ts +3 -0
  40. package/dist/providers/otp/index.js +4 -0
  41. package/dist/providers/otp/index.js.map +1 -0
  42. package/dist/redis-5TIS6XCA.js +121 -0
  43. package/dist/redis-5TIS6XCA.js.map +1 -0
  44. package/dist/security/index.d.ts +301 -0
  45. package/dist/security/index.js +5 -0
  46. package/dist/security/index.js.map +1 -0
  47. package/dist/session/index.d.ts +117 -0
  48. package/dist/session/index.js +4 -0
  49. package/dist/session/index.js.map +1 -0
  50. package/dist/storage/index.d.ts +97 -0
  51. package/dist/storage/index.js +3 -0
  52. package/dist/storage/index.js.map +1 -0
  53. package/dist/types-DSjafxJ4.d.ts +193 -0
  54. package/package.json +102 -0
@@ -0,0 +1,182 @@
1
+ import * as jose from 'jose';
2
+
3
+ /**
4
+ * JWT Manager with Key Rotation Support
5
+ * Uses jose library for multi-runtime compatibility (Node, Deno, CF Workers, Bun)
6
+ */
7
+
8
+ /**
9
+ * JWT configuration
10
+ */
11
+ interface JwtConfig {
12
+ /** Secret key for signing tokens */
13
+ secret: string;
14
+ /** Token issuer */
15
+ issuer: string;
16
+ /** Token audience */
17
+ audience: string;
18
+ /** Access token TTL (e.g., '15m', '1h') */
19
+ accessTokenTTL?: string;
20
+ /** Refresh token TTL (e.g., '7d', '12h') */
21
+ refreshTokenTTL?: string;
22
+ /** Previous secrets for key rotation */
23
+ previousSecrets?: string[];
24
+ /** Current key version */
25
+ keyVersion?: number;
26
+ }
27
+ /**
28
+ * JWT payload structure
29
+ */
30
+ interface JwtPayload {
31
+ /** User ID */
32
+ sub: string;
33
+ /** Tenant ID */
34
+ tid?: string;
35
+ /** Session ID */
36
+ sid?: string;
37
+ /** Issued at timestamp */
38
+ iat: number;
39
+ /** Expiration timestamp */
40
+ exp: number;
41
+ /** Issuer */
42
+ iss: string;
43
+ /** Audience */
44
+ aud: string | string[];
45
+ /** User roles */
46
+ roles?: string[];
47
+ /** User permissions */
48
+ permissions?: string[];
49
+ /** Additional claims */
50
+ [key: string]: unknown;
51
+ }
52
+ /**
53
+ * Token pair (access + refresh)
54
+ */
55
+ interface TokenPair {
56
+ accessToken: string;
57
+ refreshToken: string;
58
+ accessExpiresAt: Date;
59
+ refreshExpiresAt: Date;
60
+ }
61
+ /**
62
+ * Key rotation result
63
+ */
64
+ interface KeyRotationResult {
65
+ previousSecret: string;
66
+ newSecret: string;
67
+ keyVersion: number;
68
+ rotatedAt: Date;
69
+ }
70
+ /**
71
+ * Parse duration string to seconds
72
+ * Supports: s (seconds), m (minutes), h (hours), d (days), w (weeks)
73
+ */
74
+ declare function parseDuration(duration: string): number;
75
+ /**
76
+ * JWT Manager
77
+ * Handles token generation, verification, and key rotation
78
+ */
79
+ declare class JwtManager {
80
+ private secret;
81
+ private previousSecrets;
82
+ private config;
83
+ private keyVersion;
84
+ constructor(config: JwtConfig);
85
+ /**
86
+ * Get current key version
87
+ */
88
+ getKeyVersion(): number;
89
+ /**
90
+ * Rotate the signing key
91
+ * Moves current secret to previousSecrets and sets new secret
92
+ */
93
+ rotateKey(newSecret: string, options?: {
94
+ maxPreviousSecrets?: number;
95
+ }): KeyRotationResult;
96
+ /**
97
+ * Get current configuration (for persistence)
98
+ */
99
+ getConfig(): JwtConfig;
100
+ /**
101
+ * Generate access token
102
+ */
103
+ generateAccessToken(payload: {
104
+ userId: string;
105
+ tenantId?: string;
106
+ sessionId?: string;
107
+ roles?: string[];
108
+ permissions?: string[];
109
+ claims?: Record<string, unknown>;
110
+ }): Promise<{
111
+ token: string;
112
+ expiresAt: Date;
113
+ }>;
114
+ /**
115
+ * Generate refresh token
116
+ */
117
+ generateRefreshToken(payload: {
118
+ userId: string;
119
+ tenantId?: string;
120
+ sessionId?: string;
121
+ }): Promise<{
122
+ token: string;
123
+ expiresAt: Date;
124
+ }>;
125
+ /**
126
+ * Generate token pair (access + refresh)
127
+ */
128
+ generateTokenPair(payload: {
129
+ userId: string;
130
+ tenantId?: string;
131
+ sessionId?: string;
132
+ roles?: string[];
133
+ permissions?: string[];
134
+ claims?: Record<string, unknown>;
135
+ }): Promise<TokenPair>;
136
+ /**
137
+ * Verify access token
138
+ * Tries current secret first, then falls back to previous secrets for graceful rotation
139
+ */
140
+ verifyAccessToken(token: string): Promise<JwtPayload>;
141
+ /**
142
+ * Verify refresh token
143
+ */
144
+ verifyRefreshToken(token: string): Promise<{
145
+ userId: string;
146
+ tenantId?: string;
147
+ sessionId?: string;
148
+ }>;
149
+ /**
150
+ * Decode token without verification (for inspection)
151
+ */
152
+ decodeToken(token: string): jose.JWTPayload | null;
153
+ /**
154
+ * Check if token is expired (without signature verification)
155
+ */
156
+ isTokenExpired(token: string): boolean;
157
+ /**
158
+ * Get token expiration date (without signature verification)
159
+ */
160
+ getTokenExpiration(token: string): Date | null;
161
+ /**
162
+ * Get time until token expires in seconds
163
+ */
164
+ getTokenTTL(token: string): number;
165
+ }
166
+ /**
167
+ * JWT Error class
168
+ */
169
+ declare class JwtError extends Error {
170
+ readonly code: 'TOKEN_EXPIRED' | 'INVALID_TOKEN' | 'INVALID_TOKEN_TYPE' | 'VERIFICATION_FAILED';
171
+ constructor(message: string, code: 'TOKEN_EXPIRED' | 'INVALID_TOKEN' | 'INVALID_TOKEN_TYPE' | 'VERIFICATION_FAILED');
172
+ }
173
+ /**
174
+ * Extract token from Authorization header
175
+ */
176
+ declare function extractBearerToken(authHeader: string | null | undefined): string | null;
177
+ /**
178
+ * Create a JwtManager instance
179
+ */
180
+ declare function createJwtManager(config: JwtConfig): JwtManager;
181
+
182
+ export { JwtManager as J, type KeyRotationResult as K, type TokenPair as T, JwtError as a, type JwtConfig as b, createJwtManager as c, type JwtPayload as d, extractBearerToken as e, parseDuration as p };
@@ -0,0 +1,90 @@
1
+ import { A as AuthProvider, P as ProviderType, a as ProviderInfo, O as OAuthProvider, T as TwoFactorProvider } from '../base-BKyR8rcE.js';
2
+ export { b as AuthInput, c as AuthResult, B as BaseProvider, f as OAuthUserInfo, e as TwoFactorSetupResult, V as VerifyInput, d as VerifyResult } from '../base-BKyR8rcE.js';
3
+ import '../types-DSjafxJ4.js';
4
+
5
+ /**
6
+ * Provider Registry
7
+ * Manages authentication providers
8
+ */
9
+
10
+ /**
11
+ * Provider registry for managing auth providers
12
+ */
13
+ declare class ProviderRegistry {
14
+ private providers;
15
+ /**
16
+ * Register a provider
17
+ */
18
+ register(provider: AuthProvider): void;
19
+ /**
20
+ * Unregister a provider
21
+ */
22
+ unregister(name: string): boolean;
23
+ /**
24
+ * Get a provider by name
25
+ */
26
+ get(name: string): AuthProvider | undefined;
27
+ /**
28
+ * Get a provider by name (throws if not found)
29
+ */
30
+ getOrThrow(name: string): AuthProvider;
31
+ /**
32
+ * Check if a provider is registered
33
+ */
34
+ has(name: string): boolean;
35
+ /**
36
+ * Get all providers of a specific type
37
+ */
38
+ getByType(type: ProviderType): AuthProvider[];
39
+ /**
40
+ * Get all enabled providers
41
+ */
42
+ getEnabled(): AuthProvider[];
43
+ /**
44
+ * Get all enabled providers of a specific type
45
+ */
46
+ getEnabledByType(type: ProviderType): AuthProvider[];
47
+ /**
48
+ * Get all registered providers
49
+ */
50
+ getAll(): AuthProvider[];
51
+ /**
52
+ * Get provider names
53
+ */
54
+ getNames(): string[];
55
+ /**
56
+ * Get provider info for all providers
57
+ */
58
+ getInfo(): ProviderInfo[];
59
+ /**
60
+ * Get OAuth providers
61
+ */
62
+ getOAuthProviders(): OAuthProvider[];
63
+ /**
64
+ * Get 2FA providers
65
+ */
66
+ getTwoFactorProviders(): TwoFactorProvider[];
67
+ /**
68
+ * Check if a provider type is enabled
69
+ */
70
+ isTypeEnabled(type: ProviderType): boolean;
71
+ /**
72
+ * Get the primary authentication provider
73
+ * Returns the first enabled provider in order: otp > magic-link > oauth > password
74
+ */
75
+ getPrimary(): AuthProvider | undefined;
76
+ /**
77
+ * Clear all providers
78
+ */
79
+ clear(): void;
80
+ /**
81
+ * Get provider count
82
+ */
83
+ get size(): number;
84
+ }
85
+ /**
86
+ * Create a new provider registry
87
+ */
88
+ declare function createProviderRegistry(): ProviderRegistry;
89
+
90
+ export { AuthProvider, OAuthProvider, ProviderInfo, ProviderRegistry, ProviderType, TwoFactorProvider, createProviderRegistry };
@@ -0,0 +1,3 @@
1
+ export { BaseProvider, ProviderRegistry, createProviderRegistry } from '../chunk-G5I3T73A.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,3 @@
1
+ import '../../types-DSjafxJ4.js';
2
+ import '../../base-BKyR8rcE.js';
3
+ export { e as OTPConfig, a as OTPManager, O as OTPProvider, R as RequestOTPInput, d as RequestOTPResult, b as createOTPManager, c as createOTPProvider } from '../../index-C3kz9XqE.js';
@@ -0,0 +1,4 @@
1
+ export { OTPManager, OTPProvider, createOTPManager, createOTPProvider } from '../../chunk-IB4WUQDZ.js';
2
+ import '../../chunk-42MGHABB.js';
3
+ //# sourceMappingURL=index.js.map
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,121 @@
1
+ // src/storage/redis.ts
2
+ var RedisStorage = class {
3
+ client;
4
+ prefix;
5
+ constructor(client, prefix) {
6
+ this.client = client;
7
+ this.prefix = prefix ?? "";
8
+ }
9
+ getKey(key) {
10
+ return this.prefix ? `${this.prefix}:${key}` : key;
11
+ }
12
+ async get(key) {
13
+ const fullKey = this.getKey(key);
14
+ const value = await this.client.get(fullKey);
15
+ if (value === null) return null;
16
+ try {
17
+ return JSON.parse(value);
18
+ } catch {
19
+ return value;
20
+ }
21
+ }
22
+ async set(key, value, ttl) {
23
+ const fullKey = this.getKey(key);
24
+ const serialized = JSON.stringify(value);
25
+ if (ttl) {
26
+ await this.client.set(fullKey, serialized, "EX", ttl);
27
+ } else {
28
+ await this.client.set(fullKey, serialized);
29
+ }
30
+ }
31
+ async delete(key) {
32
+ const fullKey = this.getKey(key);
33
+ await this.client.del(fullKey);
34
+ }
35
+ async has(key) {
36
+ const fullKey = this.getKey(key);
37
+ const exists = await this.client.exists(fullKey);
38
+ return exists > 0;
39
+ }
40
+ async getMany(keys) {
41
+ if (keys.length === 0) return [];
42
+ const fullKeys = keys.map((k) => this.getKey(k));
43
+ const values = await this.client.mget(...fullKeys);
44
+ return values.map((value) => {
45
+ if (value === null) return null;
46
+ try {
47
+ return JSON.parse(value);
48
+ } catch {
49
+ return value;
50
+ }
51
+ });
52
+ }
53
+ async setMany(entries) {
54
+ await Promise.all(
55
+ entries.map(([key, value, ttl]) => this.set(key, value, ttl))
56
+ );
57
+ }
58
+ async deleteMany(keys) {
59
+ if (keys.length === 0) return;
60
+ const fullKeys = keys.map((k) => this.getKey(k));
61
+ await this.client.del(fullKeys);
62
+ }
63
+ async keys(pattern) {
64
+ const searchPattern = pattern ? this.getKey(pattern) : this.prefix ? `${this.prefix}:*` : "*";
65
+ const keys = await this.client.keys(searchPattern);
66
+ const prefixLength = this.prefix ? this.prefix.length + 1 : 0;
67
+ return keys.map((k) => prefixLength ? k.slice(prefixLength) : k);
68
+ }
69
+ async clear() {
70
+ if (this.prefix) {
71
+ const keys = await this.client.keys(`${this.prefix}:*`);
72
+ if (keys.length > 0) {
73
+ await this.client.del(keys);
74
+ }
75
+ } else {
76
+ console.warn(
77
+ "[Pars Auth] Cannot clear Redis storage without prefix. Use Redis FLUSHDB command directly if needed."
78
+ );
79
+ }
80
+ }
81
+ async close() {
82
+ if (this.client.quit) {
83
+ await this.client.quit();
84
+ } else if (this.client.disconnect) {
85
+ await this.client.disconnect();
86
+ }
87
+ }
88
+ };
89
+ async function createRedisClientFromUrl(url) {
90
+ try {
91
+ const { Redis } = await import('ioredis');
92
+ return new Redis(url);
93
+ } catch {
94
+ }
95
+ try {
96
+ const { Redis } = await import('@upstash/redis');
97
+ const client = new Redis({ url, token: "" });
98
+ return client;
99
+ } catch {
100
+ }
101
+ throw new Error(
102
+ '[Pars Auth] No Redis client available. Install either "ioredis" or "@upstash/redis"'
103
+ );
104
+ }
105
+ async function createRedisStorage(config) {
106
+ let client;
107
+ if (config.client) {
108
+ client = config.client;
109
+ } else if (config.url) {
110
+ client = await createRedisClientFromUrl(config.url);
111
+ } else {
112
+ throw new Error(
113
+ "[Pars Auth] Redis storage requires either url or client configuration"
114
+ );
115
+ }
116
+ return new RedisStorage(client, config.prefix);
117
+ }
118
+
119
+ export { RedisStorage, createRedisStorage };
120
+ //# sourceMappingURL=redis-5TIS6XCA.js.map
121
+ //# sourceMappingURL=redis-5TIS6XCA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/storage/redis.ts"],"names":[],"mappings":"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","file":"redis-5TIS6XCA.js","sourcesContent":["/**\n * Redis KV Storage adapter\n * Supports both ioredis and Upstash Redis\n */\n\nimport type { KVStorage, RedisConfig } from './types.js';\n\n/**\n * Generic Redis client interface\n * Compatible with both ioredis and Upstash Redis\n */\ninterface RedisClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, ...args: unknown[]): Promise<unknown>;\n del(key: string | string[]): Promise<number>;\n exists(key: string | string[]): Promise<number>;\n keys(pattern: string): Promise<string[]>;\n mget(...keys: string[]): Promise<(string | null)[]>;\n expire(key: string, seconds: number): Promise<number>;\n quit?(): Promise<unknown>;\n disconnect?(): Promise<void>;\n}\n\n/**\n * Redis storage adapter\n */\nexport class RedisStorage implements KVStorage {\n private client: RedisClient;\n private readonly prefix: string;\n\n constructor(client: RedisClient, prefix?: string) {\n this.client = client;\n this.prefix = prefix ?? '';\n }\n\n private getKey(key: string): string {\n return this.prefix ? `${this.prefix}:${key}` : key;\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const fullKey = this.getKey(key);\n const value = await this.client.get(fullKey);\n\n if (value === null) return null;\n\n try {\n return JSON.parse(value) as T;\n } catch {\n // Return as string if not valid JSON\n return value as unknown as T;\n }\n }\n\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n const fullKey = this.getKey(key);\n const serialized = JSON.stringify(value);\n\n if (ttl) {\n // Use EX for seconds TTL\n await this.client.set(fullKey, serialized, 'EX', ttl);\n } else {\n await this.client.set(fullKey, serialized);\n }\n }\n\n async delete(key: string): Promise<void> {\n const fullKey = this.getKey(key);\n await this.client.del(fullKey);\n }\n\n async has(key: string): Promise<boolean> {\n const fullKey = this.getKey(key);\n const exists = await this.client.exists(fullKey);\n return exists > 0;\n }\n\n async getMany<T = unknown>(keys: string[]): Promise<(T | null)[]> {\n if (keys.length === 0) return [];\n\n const fullKeys = keys.map((k) => this.getKey(k));\n const values = await this.client.mget(...fullKeys);\n\n return values.map((value) => {\n if (value === null) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as unknown as T;\n }\n });\n }\n\n async setMany<T = unknown>(\n entries: Array<[key: string, value: T, ttl?: number]>\n ): Promise<void> {\n // Redis doesn't have native MSET with TTL, so we use individual sets\n await Promise.all(\n entries.map(([key, value, ttl]) => this.set(key, value, ttl))\n );\n }\n\n async deleteMany(keys: string[]): Promise<void> {\n if (keys.length === 0) return;\n\n const fullKeys = keys.map((k) => this.getKey(k));\n await this.client.del(fullKeys);\n }\n\n async keys(pattern?: string): Promise<string[]> {\n const searchPattern = pattern\n ? this.getKey(pattern)\n : this.prefix\n ? `${this.prefix}:*`\n : '*';\n\n const keys = await this.client.keys(searchPattern);\n const prefixLength = this.prefix ? this.prefix.length + 1 : 0;\n\n return keys.map((k) => (prefixLength ? k.slice(prefixLength) : k));\n }\n\n async clear(): Promise<void> {\n if (this.prefix) {\n const keys = await this.client.keys(`${this.prefix}:*`);\n if (keys.length > 0) {\n await this.client.del(keys);\n }\n } else {\n console.warn(\n '[Pars Auth] Cannot clear Redis storage without prefix. Use Redis FLUSHDB command directly if needed.'\n );\n }\n }\n\n async close(): Promise<void> {\n if (this.client.quit) {\n await this.client.quit();\n } else if (this.client.disconnect) {\n await this.client.disconnect();\n }\n }\n}\n\n/**\n * Create Redis storage from URL\n * Dynamically imports ioredis or @upstash/redis\n */\nasync function createRedisClientFromUrl(url: string): Promise<RedisClient> {\n // Try ioredis first (Node.js)\n try {\n const { Redis } = await import('ioredis');\n return new Redis(url) as unknown as RedisClient;\n } catch {\n // ioredis not available\n }\n\n // Try @upstash/redis (Edge/Serverless)\n try {\n const { Redis } = await import('@upstash/redis');\n // Upstash Redis v2+ accepts url and token as separate config\n // Type assertion needed for compatibility with different Upstash versions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const client = new Redis({ url, token: '' } as any);\n return client as unknown as RedisClient;\n } catch {\n // Upstash not available\n }\n\n throw new Error(\n '[Pars Auth] No Redis client available. Install either \"ioredis\" or \"@upstash/redis\"'\n );\n}\n\n/**\n * Create Redis storage adapter\n *\n * @example\n * ```ts\n * // With URL (auto-detects client)\n * const storage = await createRedisStorage({ url: 'redis://localhost:6379' });\n *\n * // With existing client\n * import Redis from 'ioredis';\n * const client = new Redis();\n * const storage = await createRedisStorage({ client });\n *\n * // With prefix\n * const storage = await createRedisStorage({\n * url: 'redis://localhost:6379',\n * prefix: 'pars:auth'\n * });\n * ```\n */\nexport async function createRedisStorage(\n config: RedisConfig\n): Promise<KVStorage> {\n let client: RedisClient;\n\n if (config.client) {\n client = config.client as RedisClient;\n } else if (config.url) {\n client = await createRedisClientFromUrl(config.url);\n } else {\n throw new Error(\n '[Pars Auth] Redis storage requires either url or client configuration'\n );\n }\n\n return new RedisStorage(client, config.prefix);\n}\n"]}