@veloxts/auth 0.6.84 → 0.6.86

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @veloxts/auth
2
2
 
3
+ ## 0.6.86
4
+
5
+ ### Patch Changes
6
+
7
+ - updated documentation
8
+ - Updated dependencies
9
+ - @veloxts/core@0.6.86
10
+ - @veloxts/router@0.6.86
11
+
12
+ ## 0.6.85
13
+
14
+ ### Patch Changes
15
+
16
+ - implement missing features from original requirements
17
+ - Updated dependencies
18
+ - @veloxts/core@0.6.85
19
+ - @veloxts/router@0.6.85
20
+
3
21
  ## 0.6.84
4
22
 
5
23
  ### Patch Changes
package/GUIDE.md CHANGED
@@ -54,14 +54,27 @@ const getProfile = procedure()
54
54
  ## Guards
55
55
 
56
56
  ```typescript
57
- import { hasRole, hasPermission } from '@veloxts/auth';
57
+ import { authenticated, hasRole, hasPermission } from '@veloxts/auth';
58
58
 
59
+ // Require authentication
60
+ const getProfile = procedure()
61
+ .guard(authenticated)
62
+ .query(({ ctx }) => ctx.user);
63
+
64
+ // Require admin role
59
65
  const adminOnly = procedure()
60
- .use(auth.middleware({ guards: [hasRole('admin')] }))
66
+ .guard(hasRole('admin'))
61
67
  .mutation(handler);
62
68
 
69
+ // Require specific permission
63
70
  const canEdit = procedure()
64
- .use(auth.middleware({ guards: [hasPermission('posts.write')] }))
71
+ .guard(hasPermission('posts.write'))
72
+ .mutation(handler);
73
+
74
+ // Chain multiple guards (all must pass)
75
+ const adminWithPermission = procedure()
76
+ .guard(authenticated)
77
+ .guard(hasRole('admin'))
65
78
  .mutation(handler);
66
79
  ```
67
80
 
package/dist/adapter.d.ts CHANGED
@@ -195,11 +195,12 @@ export interface AdapterRoute {
195
195
  */
196
196
  export interface AuthAdapterConfig {
197
197
  /**
198
- * Adapter name for identification and logging
198
+ * Adapter name for identification and logging (optional)
199
199
  *
200
200
  * Should be a unique identifier like 'better-auth', 'clerk', 'auth0'.
201
+ * If not provided, the factory function or adapter class will supply a default.
201
202
  */
202
- name: string;
203
+ name?: string;
203
204
  /**
204
205
  * Enable debug logging
205
206
  *
@@ -486,6 +487,9 @@ export interface AuthAdapter<TConfig extends AuthAdapterConfig = AuthAdapterConf
486
487
  export declare function defineAuthAdapter<TConfig extends AuthAdapterConfig = AuthAdapterConfig>(adapter: AuthAdapter<TConfig>): AuthAdapter<TConfig>;
487
488
  /**
488
489
  * Plugin options for the auth adapter plugin
490
+ *
491
+ * @deprecated Use the simplified form: `createAuthAdapterPlugin(adapter)` where adapter
492
+ * is created via a factory function like `createClerkAdapter()` that attaches config.
489
493
  */
490
494
  export interface AuthAdapterPluginOptions<TConfig extends AuthAdapterConfig = AuthAdapterConfig> {
491
495
  /**
@@ -497,6 +501,17 @@ export interface AuthAdapterPluginOptions<TConfig extends AuthAdapterConfig = Au
497
501
  */
498
502
  config: TConfig;
499
503
  }
504
+ /**
505
+ * Adapter with attached configuration (returned by factory functions)
506
+ *
507
+ * Factory functions like `createClerkAdapter()` return an adapter with its
508
+ * configuration attached, enabling the simplified plugin registration:
509
+ * `createAuthAdapterPlugin(adapter)` instead of
510
+ * `createAuthAdapterPlugin({ adapter, config: adapter.config })`
511
+ */
512
+ export type AdapterWithConfig<TAdapter extends AuthAdapter<TConfig>, TConfig extends AuthAdapterConfig = AuthAdapterConfig> = TAdapter & {
513
+ config: TConfig;
514
+ };
500
515
  /**
501
516
  * Creates a VeloxTS plugin from an auth adapter
502
517
  *
@@ -510,31 +525,34 @@ export interface AuthAdapterPluginOptions<TConfig extends AuthAdapterConfig = Au
510
525
  * - Cleanup on shutdown
511
526
  *
512
527
  * @template TConfig - Adapter-specific configuration type
513
- * @param options - Plugin options with adapter and config
528
+ * @param adapterOrOptions - Either an adapter with attached config (from factory), or legacy options object
514
529
  * @returns VeloxTS plugin ready for registration
515
530
  *
516
- * @example
531
+ * @example Simplified API (recommended)
517
532
  * ```typescript
518
533
  * import { createAuthAdapterPlugin } from '@veloxts/auth';
519
- * import { betterAuthAdapter } from './adapters/better-auth';
534
+ * import { createClerkAdapter } from '@veloxts/auth/adapters/clerk';
520
535
  *
521
- * const authPlugin = createAuthAdapterPlugin({
522
- * adapter: betterAuthAdapter,
523
- * config: {
524
- * name: 'better-auth',
525
- * auth: betterAuth({
526
- * database: db,
527
- * trustedOrigins: ['http://localhost:3000'],
528
- * }),
529
- * debug: process.env.NODE_ENV === 'development',
530
- * },
536
+ * const adapter = createClerkAdapter({
537
+ * clerk: createClerkClient({ secretKey: '...' }),
538
+ * debug: process.env.NODE_ENV === 'development',
531
539
  * });
532
540
  *
533
- * // Register with VeloxApp
541
+ * // Simple: just pass the adapter
542
+ * const authPlugin = createAuthAdapterPlugin(adapter);
543
+ *
534
544
  * app.use(authPlugin);
535
545
  * ```
546
+ *
547
+ * @example Legacy API (still supported)
548
+ * ```typescript
549
+ * const authPlugin = createAuthAdapterPlugin({
550
+ * adapter: myAdapter,
551
+ * config: { ... },
552
+ * });
553
+ * ```
536
554
  */
537
- export declare function createAuthAdapterPlugin<TConfig extends AuthAdapterConfig>(options: AuthAdapterPluginOptions<TConfig>): VeloxPlugin<AuthAdapterPluginOptions<TConfig>>;
555
+ export declare function createAuthAdapterPlugin<TConfig extends AuthAdapterConfig>(adapterOrOptions: AdapterWithConfig<AuthAdapter<TConfig>, TConfig> | AuthAdapterPluginOptions<TConfig>): VeloxPlugin<AuthAdapterPluginOptions<TConfig>>;
538
556
  /**
539
557
  * Options for adapter-based auth middleware
540
558
  */
package/dist/adapter.js CHANGED
@@ -182,32 +182,47 @@ function matchesExcludePattern(path, patterns) {
182
182
  * - Cleanup on shutdown
183
183
  *
184
184
  * @template TConfig - Adapter-specific configuration type
185
- * @param options - Plugin options with adapter and config
185
+ * @param adapterOrOptions - Either an adapter with attached config (from factory), or legacy options object
186
186
  * @returns VeloxTS plugin ready for registration
187
187
  *
188
- * @example
188
+ * @example Simplified API (recommended)
189
189
  * ```typescript
190
190
  * import { createAuthAdapterPlugin } from '@veloxts/auth';
191
- * import { betterAuthAdapter } from './adapters/better-auth';
191
+ * import { createClerkAdapter } from '@veloxts/auth/adapters/clerk';
192
192
  *
193
- * const authPlugin = createAuthAdapterPlugin({
194
- * adapter: betterAuthAdapter,
195
- * config: {
196
- * name: 'better-auth',
197
- * auth: betterAuth({
198
- * database: db,
199
- * trustedOrigins: ['http://localhost:3000'],
200
- * }),
201
- * debug: process.env.NODE_ENV === 'development',
202
- * },
193
+ * const adapter = createClerkAdapter({
194
+ * clerk: createClerkClient({ secretKey: '...' }),
195
+ * debug: process.env.NODE_ENV === 'development',
203
196
  * });
204
197
  *
205
- * // Register with VeloxApp
198
+ * // Simple: just pass the adapter
199
+ * const authPlugin = createAuthAdapterPlugin(adapter);
200
+ *
206
201
  * app.use(authPlugin);
207
202
  * ```
203
+ *
204
+ * @example Legacy API (still supported)
205
+ * ```typescript
206
+ * const authPlugin = createAuthAdapterPlugin({
207
+ * adapter: myAdapter,
208
+ * config: { ... },
209
+ * });
210
+ * ```
208
211
  */
209
- export function createAuthAdapterPlugin(options) {
210
- const { adapter, config } = options;
212
+ export function createAuthAdapterPlugin(adapterOrOptions) {
213
+ // Support both new simplified API and legacy options object
214
+ let adapter;
215
+ let config;
216
+ if ('adapter' in adapterOrOptions && 'config' in adapterOrOptions) {
217
+ // Legacy: { adapter, config } object
218
+ adapter = adapterOrOptions.adapter;
219
+ config = adapterOrOptions.config;
220
+ }
221
+ else {
222
+ // New: adapter with attached config
223
+ adapter = adapterOrOptions;
224
+ config = adapterOrOptions.config;
225
+ }
211
226
  const debug = config.debug ?? false;
212
227
  const excludeRoutes = config.excludeRoutes ?? [];
213
228
  const transformUser = config.transformUser ?? defaultTransformUser;
@@ -216,7 +231,8 @@ export function createAuthAdapterPlugin(options) {
216
231
  version: adapter.version,
217
232
  dependencies: ['@veloxts/core'],
218
233
  async register(server, _opts) {
219
- const mergedConfig = { ...config, ..._opts.config };
234
+ // Config is already captured from adapter - _opts.config is for legacy override support
235
+ const mergedConfig = _opts?.config ? { ...config, ..._opts.config } : config;
220
236
  // Prevent double-registration of auth systems
221
237
  checkDoubleRegistration(server, `adapter:${adapter.name}`);
222
238
  if (debug) {
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Auth0 Adapter for @veloxts/auth
3
+ *
4
+ * Integrates Auth0 (https://auth0.com) with VeloxTS's pluggable
5
+ * authentication system. Auth0 is an identity platform providing
6
+ * authentication and authorization services.
7
+ *
8
+ * This adapter uses JWKS (JSON Web Key Sets) for JWT verification,
9
+ * allowing secure token validation without sharing secrets.
10
+ *
11
+ * @module auth/adapters/auth0
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { createAuthAdapterPlugin } from '@veloxts/auth';
16
+ * import { createAuth0Adapter } from '@veloxts/auth/adapters/auth0';
17
+ *
18
+ * const adapter = createAuth0Adapter({
19
+ * domain: process.env.AUTH0_DOMAIN!,
20
+ * audience: process.env.AUTH0_AUDIENCE!,
21
+ * clientId: process.env.AUTH0_CLIENT_ID,
22
+ * });
23
+ *
24
+ * // Simplified API - just pass the adapter
25
+ * const authPlugin = createAuthAdapterPlugin(adapter);
26
+ *
27
+ * app.use(authPlugin);
28
+ * ```
29
+ */
30
+ import type { FastifyInstance, FastifyRequest } from 'fastify';
31
+ import type { AdapterRoute, AdapterSessionResult, AuthAdapterConfig } from '../adapter.js';
32
+ import { BaseAuthAdapter } from '../adapter.js';
33
+ /**
34
+ * Auth0 JWT claims (standard + custom)
35
+ *
36
+ * Represents the claims in a verified Auth0 JWT.
37
+ */
38
+ export interface Auth0Claims {
39
+ /** Subject (user ID - Auth0's user_id) */
40
+ sub: string;
41
+ /** Issued at timestamp */
42
+ iat: number;
43
+ /** Expiration timestamp */
44
+ exp: number;
45
+ /** Not before timestamp */
46
+ nbf?: number;
47
+ /** Issuer (Auth0 domain) */
48
+ iss: string;
49
+ /** Audience */
50
+ aud: string | string[];
51
+ /** Authorized party */
52
+ azp?: string;
53
+ /** Token scope */
54
+ scope?: string;
55
+ /** Token permissions (RBAC) */
56
+ permissions?: string[];
57
+ /** Organization ID (Auth0 Organizations) */
58
+ org_id?: string;
59
+ /** Organization name */
60
+ org_name?: string;
61
+ /** Email (if included in token) */
62
+ email?: string;
63
+ /** Email verified status */
64
+ email_verified?: boolean;
65
+ /** User name */
66
+ name?: string;
67
+ /** User nickname */
68
+ nickname?: string;
69
+ /** Profile picture URL */
70
+ picture?: string;
71
+ /** Updated at timestamp */
72
+ updated_at?: string;
73
+ }
74
+ /**
75
+ * Auth0 Management API user object
76
+ *
77
+ * Full user profile from Auth0's Management API.
78
+ */
79
+ export interface Auth0User {
80
+ /** User ID */
81
+ user_id: string;
82
+ /** Email address */
83
+ email?: string;
84
+ /** Whether email is verified */
85
+ email_verified?: boolean;
86
+ /** Display name */
87
+ name?: string;
88
+ /** Nickname */
89
+ nickname?: string;
90
+ /** First name */
91
+ given_name?: string;
92
+ /** Last name */
93
+ family_name?: string;
94
+ /** Profile picture URL */
95
+ picture?: string;
96
+ /** Last login timestamp */
97
+ last_login?: string;
98
+ /** Login count */
99
+ logins_count?: number;
100
+ /** Account creation timestamp */
101
+ created_at?: string;
102
+ /** Account update timestamp */
103
+ updated_at?: string;
104
+ /** User metadata (writable by user) */
105
+ user_metadata?: Record<string, unknown>;
106
+ /** App metadata (writable by app) */
107
+ app_metadata?: Record<string, unknown>;
108
+ /** Identity providers linked to this user */
109
+ identities?: Array<{
110
+ connection: string;
111
+ provider: string;
112
+ user_id: string;
113
+ isSocial: boolean;
114
+ }>;
115
+ }
116
+ /**
117
+ * JWKS Key object
118
+ *
119
+ * JSON Web Key from Auth0's JWKS endpoint.
120
+ */
121
+ export interface JWKSKey {
122
+ /** Key type (always 'RSA' for Auth0) */
123
+ kty: string;
124
+ /** Key ID */
125
+ kid: string;
126
+ /** Algorithm (RS256) */
127
+ alg: string;
128
+ /** Key use (signature) */
129
+ use: string;
130
+ /** RSA modulus */
131
+ n: string;
132
+ /** RSA exponent */
133
+ e: string;
134
+ /** X.509 certificate chain */
135
+ x5c?: string[];
136
+ /** X.509 thumbprint */
137
+ x5t?: string;
138
+ }
139
+ /**
140
+ * JWKS response from Auth0
141
+ */
142
+ export interface JWKSResponse {
143
+ keys: JWKSKey[];
144
+ }
145
+ /**
146
+ * JWT verifier interface
147
+ *
148
+ * For custom JWT verification implementations.
149
+ * The adapter provides a default implementation using jose library.
150
+ */
151
+ export interface JwtVerifier {
152
+ /**
153
+ * Verify a JWT token
154
+ *
155
+ * @param token - JWT token to verify
156
+ * @returns Decoded claims if valid, throws if invalid
157
+ */
158
+ verify(token: string): Promise<Auth0Claims>;
159
+ }
160
+ /**
161
+ * Auth0 adapter configuration
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * const config: Auth0AdapterConfig = {
166
+ * name: 'auth0',
167
+ * domain: 'your-tenant.auth0.com',
168
+ * audience: 'https://your-api.example.com',
169
+ * clientId: 'your-client-id', // Optional for additional validation
170
+ * debug: true,
171
+ * };
172
+ * ```
173
+ */
174
+ export interface Auth0AdapterConfig extends AuthAdapterConfig {
175
+ /**
176
+ * Auth0 domain
177
+ *
178
+ * Your Auth0 tenant domain (e.g., 'your-tenant.auth0.com').
179
+ * Can be the custom domain if configured.
180
+ */
181
+ domain: string;
182
+ /**
183
+ * API audience
184
+ *
185
+ * The identifier for your API in Auth0.
186
+ * Tokens must have this audience to be valid.
187
+ */
188
+ audience: string;
189
+ /**
190
+ * Client ID (optional)
191
+ *
192
+ * If provided, validates the authorized party (azp) claim.
193
+ * Useful for ensuring tokens were issued for your specific client.
194
+ */
195
+ clientId?: string;
196
+ /**
197
+ * Custom JWT verifier (optional)
198
+ *
199
+ * Provide a custom JWT verification implementation.
200
+ * If not provided, uses the default JWKS-based verifier.
201
+ */
202
+ jwtVerifier?: JwtVerifier;
203
+ /**
204
+ * JWKS cache TTL in milliseconds
205
+ *
206
+ * How long to cache the JWKS keys before fetching fresh ones.
207
+ *
208
+ * @default 3600000 (1 hour)
209
+ */
210
+ jwksCacheTtl?: number;
211
+ /**
212
+ * Clock tolerance in seconds
213
+ *
214
+ * Tolerance for clock skew when validating exp/iat/nbf claims.
215
+ *
216
+ * @default 5
217
+ */
218
+ clockTolerance?: number;
219
+ /**
220
+ * Custom header name for the authorization token
221
+ *
222
+ * @default 'authorization'
223
+ */
224
+ authHeader?: string;
225
+ /**
226
+ * Token issuer (optional)
227
+ *
228
+ * Override the expected issuer. By default, constructs from domain.
229
+ * Useful for custom domains.
230
+ */
231
+ issuer?: string;
232
+ }
233
+ /**
234
+ * Auth0 Adapter
235
+ *
236
+ * Integrates Auth0 with VeloxTS by:
237
+ * - Verifying Auth0 JWTs using JWKS
238
+ * - Extracting user data from token claims
239
+ * - Supporting Auth0 Organizations and RBAC
240
+ *
241
+ * @example
242
+ * ```typescript
243
+ * const adapter = new Auth0Adapter();
244
+ * const plugin = createAuthAdapterPlugin({
245
+ * adapter,
246
+ * config: {
247
+ * name: 'auth0',
248
+ * domain: 'your-tenant.auth0.com',
249
+ * audience: 'https://your-api.example.com',
250
+ * },
251
+ * });
252
+ * ```
253
+ */
254
+ export declare class Auth0Adapter extends BaseAuthAdapter<Auth0AdapterConfig> {
255
+ private verifier;
256
+ private domain;
257
+ private clientId?;
258
+ private authHeader;
259
+ constructor();
260
+ /**
261
+ * Initialize the adapter with Auth0 configuration
262
+ */
263
+ initialize(fastify: FastifyInstance, config: Auth0AdapterConfig): Promise<void>;
264
+ /**
265
+ * Get session from Auth0 JWT
266
+ *
267
+ * Extracts the Bearer token from the Authorization header
268
+ * and verifies it using JWKS.
269
+ */
270
+ getSession(request: FastifyRequest): Promise<AdapterSessionResult | null>;
271
+ /**
272
+ * Get routes for Auth0
273
+ *
274
+ * Auth0 handles auth on the client side via their SDK.
275
+ * Server only needs to verify tokens, not handle auth routes.
276
+ *
277
+ * If you need to handle Auth0 webhooks or Actions callbacks,
278
+ * override this method.
279
+ */
280
+ getRoutes(): AdapterRoute[];
281
+ /**
282
+ * Clean up adapter resources
283
+ */
284
+ cleanup(): Promise<void>;
285
+ }
286
+ /**
287
+ * Create an Auth0 adapter
288
+ *
289
+ * This is the recommended way to create an Auth0 adapter.
290
+ * It returns an adapter instance with the configuration attached.
291
+ *
292
+ * @param config - Adapter configuration
293
+ * @returns Auth0 adapter with configuration
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * import { createAuth0Adapter } from '@veloxts/auth/adapters/auth0';
298
+ * import { createAuthAdapterPlugin } from '@veloxts/auth';
299
+ *
300
+ * const adapter = createAuth0Adapter({
301
+ * domain: process.env.AUTH0_DOMAIN!,
302
+ * audience: process.env.AUTH0_AUDIENCE!,
303
+ * clientId: process.env.AUTH0_CLIENT_ID, // Optional
304
+ * debug: process.env.NODE_ENV === 'development',
305
+ * });
306
+ *
307
+ * // Simplified API - just pass the adapter
308
+ * const authPlugin = createAuthAdapterPlugin(adapter);
309
+ *
310
+ * app.use(authPlugin);
311
+ * ```
312
+ */
313
+ export declare function createAuth0Adapter(config: Auth0AdapterConfig): Auth0Adapter & {
314
+ config: Auth0AdapterConfig;
315
+ };
316
+ export { AuthAdapterError } from '../adapter.js';