@agentuity/auth 0.1.7 → 0.1.9

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.
@@ -1,401 +0,0 @@
1
- /**
2
- * Auth configuration for @agentuity/auth.
3
- *
4
- * Provides sensible defaults and wraps BetterAuth with Agentuity-specific helpers.
5
- *
6
- * @module agentuity/config
7
- */
8
-
9
- import { betterAuth, type BetterAuthOptions } from 'better-auth';
10
- import { drizzleAdapter } from 'better-auth/adapters/drizzle';
11
- import { organization, jwt, bearer, apiKey } from 'better-auth/plugins';
12
- import { drizzle } from 'drizzle-orm/bun-sql';
13
- import * as authSchema from '../schema';
14
-
15
- // Re-export plugin types for convenience
16
- export type {
17
- Organization,
18
- OrganizationMember,
19
- OrganizationInvitation,
20
- OrganizationApiMethods,
21
- ApiKey,
22
- ApiKeyPluginOptions,
23
- ApiKeyApiMethods,
24
- JwtApiMethods,
25
- DefaultPluginApiMethods,
26
- } from './plugins';
27
-
28
- export { DEFAULT_API_KEY_OPTIONS } from './plugins';
29
-
30
- import type { ApiKeyPluginOptions, DefaultPluginApiMethods } from './plugins';
31
- import { DEFAULT_API_KEY_OPTIONS } from './plugins';
32
-
33
- /**
34
- * Type for BetterAuth trustedOrigins option.
35
- * Matches the signature expected by BetterAuthOptions.trustedOrigins.
36
- */
37
- type TrustedOrigins = string[] | ((request?: Request) => string[] | Promise<string[]>);
38
-
39
- // =============================================================================
40
- // Base Interface for Middleware
41
- // =============================================================================
42
-
43
- /**
44
- * Base interface for the auth instance used by middleware and route handlers.
45
- *
46
- * This interface defines the core authentication APIs that Agentuity middleware
47
- * relies on. It's designed to be stable and middleware-friendly while the full
48
- * auth instance provides additional type-safe APIs for your application code.
49
- *
50
- * @remarks
51
- * You typically don't interact with this interface directly. Instead, use
52
- * `createAuth()` to create an auth instance which implements this interface.
53
- *
54
- * @see {@link createAuth} - Create an auth instance
55
- * @see {@link createSessionMiddleware} - Session-based authentication middleware
56
- * @see {@link createApiKeyMiddleware} - API key authentication middleware
57
- */
58
- export interface AuthBase {
59
- /**
60
- * HTTP request handler for auth routes.
61
- *
62
- * Handles all auth-related endpoints like sign-in, sign-up, sign-out,
63
- * password reset, OAuth callbacks, and session management.
64
- *
65
- * @param request - The incoming HTTP request
66
- * @returns Response for the auth endpoint
67
- */
68
- handler: (request: Request) => Promise<Response>;
69
-
70
- /**
71
- * Server-side API methods for authentication operations.
72
- *
73
- * These methods are used internally by middleware and can also be called
74
- * directly in your route handlers for custom authentication logic.
75
- */
76
- api: {
77
- /**
78
- * Get the current session from request headers.
79
- *
80
- * @param params - Object containing the request headers
81
- * @returns The session with user info, or null if not authenticated
82
- */
83
- getSession: (params: { headers: Headers }) => Promise<{
84
- user: { id: string; name?: string | null; email: string };
85
- session: { id: string; userId: string; activeOrganizationId?: string };
86
- } | null>;
87
-
88
- /**
89
- * Get full organization details including members.
90
- *
91
- * @param params - Object containing the request headers
92
- * @returns Full organization details, or null if no active org
93
- */
94
- getFullOrganization: (params: {
95
- query?: {
96
- organizationId?: string;
97
- organizationSlug?: string;
98
- membersLimit?: number;
99
- };
100
- headers?: Headers;
101
- }) => Promise<{
102
- id: string;
103
- name?: string;
104
- slug?: string;
105
- members?: Array<{ userId: string; role: string; id?: string }>;
106
- } | null>;
107
-
108
- /**
109
- * Verify an API key and get its metadata.
110
- *
111
- * @param params - Object containing the API key to verify
112
- * @returns Validation result with key details if valid
113
- */
114
- verifyApiKey: (params: { body: { key: string } }) => Promise<{
115
- valid: boolean;
116
- error?: { message: string; code: string } | null;
117
- key?: {
118
- id: string;
119
- name?: string;
120
- userId?: string;
121
- permissions?: Record<string, string[]> | null;
122
- } | null;
123
- }>;
124
- } & DefaultPluginApiMethods;
125
- }
126
-
127
- /**
128
- * Safely parse a URL and return its origin, or undefined if invalid.
129
- */
130
- function safeOrigin(url: string | undefined): string | undefined {
131
- if (!url) return undefined;
132
- try {
133
- return new URL(url).origin;
134
- } catch {
135
- return undefined;
136
- }
137
- }
138
-
139
- /**
140
- * Parse a domain or URL into an origin.
141
- * Handles both full URLs (https://example.com) and bare domains (example.com).
142
- * Bare domains default to https:// scheme.
143
- */
144
- function parseOriginLike(value: string): string | undefined {
145
- const trimmed = value.trim();
146
- if (!trimmed) return undefined;
147
-
148
- // If it looks like a URL with scheme, parse as-is
149
- if (/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(trimmed)) {
150
- return safeOrigin(trimmed);
151
- }
152
-
153
- // Otherwise, treat as host[:port] and assume https
154
- return safeOrigin(`https://${trimmed}`);
155
- }
156
-
157
- /**
158
- * Resolve the base URL for the auth instance.
159
- *
160
- * Priority:
161
- * 1. Explicit `baseURL` option
162
- * 2. `AGENTUITY_BASE_URL` env var (Agentuity platform-injected)
163
- * 3. `BETTER_AUTH_URL` env var (BetterAuth standard, for 3rd party SDK compatibility)
164
- */
165
- function resolveBaseURL(explicitBaseURL?: string): string | undefined {
166
- return explicitBaseURL ?? process.env.AGENTUITY_BASE_URL ?? process.env.BETTER_AUTH_URL;
167
- }
168
-
169
- /**
170
- * Resolve the auth secret.
171
- *
172
- * Priority:
173
- * 1. Explicit `secret` option
174
- * 2. `AGENTUITY_AUTH_SECRET` env var (Agentuity convention)
175
- * 3. `BETTER_AUTH_SECRET` env var (BetterAuth standard, for backward compatibility)
176
- */
177
- function resolveSecret(explicitSecret?: string): string | undefined {
178
- return explicitSecret ?? process.env.AGENTUITY_AUTH_SECRET ?? process.env.BETTER_AUTH_SECRET;
179
- }
180
-
181
- /**
182
- * Create the default trustedOrigins function for Agentuity deployments.
183
- *
184
- * This provides zero-config CORS/origin handling:
185
- * - Trusts the resolved baseURL origin
186
- * - Trusts the AGENTUITY_BASE_URL origin
187
- * - Trusts all domains from AGENTUITY_CLOUD_DOMAINS (platform-set, comma-separated)
188
- * - Trusts additional domains from AUTH_TRUSTED_DOMAINS (developer-set, comma-separated)
189
- * - Trusts the same-origin of incoming requests (request.url.origin)
190
- *
191
- * @param baseURL - The resolved base URL for the auth instance
192
- */
193
- function createDefaultTrustedOrigins(baseURL?: string): (request?: Request) => Promise<string[]> {
194
- const agentuityURL = process.env.AGENTUITY_BASE_URL;
195
- const cloudDomains = process.env.AGENTUITY_CLOUD_DOMAINS;
196
- const devTrustedDomains = process.env.AUTH_TRUSTED_DOMAINS;
197
-
198
- const staticOrigins = new Set<string>();
199
-
200
- const baseOrigin = safeOrigin(baseURL);
201
- if (baseOrigin) staticOrigins.add(baseOrigin);
202
-
203
- const agentuityOrigin = safeOrigin(agentuityURL);
204
- if (agentuityOrigin) staticOrigins.add(agentuityOrigin);
205
-
206
- // Platform-set cloud domains (deployment, project, PR, custom domains, tunnels)
207
- if (cloudDomains) {
208
- for (const raw of cloudDomains.split(',')) {
209
- const origin = parseOriginLike(raw);
210
- if (origin) staticOrigins.add(origin);
211
- }
212
- }
213
-
214
- // Developer-set additional trusted domains
215
- if (devTrustedDomains) {
216
- for (const raw of devTrustedDomains.split(',')) {
217
- const origin = parseOriginLike(raw);
218
- if (origin) staticOrigins.add(origin);
219
- }
220
- }
221
-
222
- return async (request?: Request): Promise<string[]> => {
223
- const origins = new Set(staticOrigins);
224
-
225
- if (request) {
226
- const requestOrigin = safeOrigin(request.url);
227
- if (requestOrigin) origins.add(requestOrigin);
228
- }
229
-
230
- return [...origins];
231
- };
232
- }
233
-
234
- /**
235
- * Configuration options for auth.
236
- * Extends BetterAuth options with Agentuity-specific settings.
237
- */
238
- export interface AuthOptions extends BetterAuthOptions {
239
- /**
240
- * PostgreSQL connection string.
241
- * When provided, we create a Bun SQL connection and Drizzle instance internally.
242
- * This is the simplest path - just provide the connection string.
243
- *
244
- * @example
245
- * ```typescript
246
- * createAuth({
247
- * connectionString: process.env.DATABASE_URL,
248
- * });
249
- * ```
250
- */
251
- connectionString?: string;
252
-
253
- /**
254
- * Skip default plugins (organization, jwt, bearer, apiKey).
255
- * Use this if you want full control over plugins.
256
- */
257
- skipDefaultPlugins?: boolean;
258
-
259
- /**
260
- * API Key plugin configuration.
261
- * Set to false to disable the API key plugin entirely.
262
- */
263
- apiKey?: ApiKeyPluginOptions | false;
264
- }
265
-
266
- /**
267
- * Default plugins included with Agentuity auth.
268
- *
269
- * @param apiKeyOptions - API key plugin options, or false to disable
270
- */
271
- export function getDefaultPlugins(apiKeyOptions?: ApiKeyPluginOptions | false) {
272
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
273
- const plugins: any[] = [organization(), jwt(), bearer()];
274
-
275
- // Add API key plugin unless explicitly disabled
276
- if (apiKeyOptions !== false) {
277
- const opts = { ...DEFAULT_API_KEY_OPTIONS, ...apiKeyOptions };
278
-
279
- if (opts.enabled) {
280
- plugins.push(
281
- apiKey({
282
- apiKeyHeaders: opts.apiKeyHeaders,
283
- enableSessionForAPIKeys: opts.enableSessionForAPIKeys,
284
- defaultPrefix: opts.defaultPrefix,
285
- defaultKeyLength: opts.defaultKeyLength,
286
- enableMetadata: opts.enableMetadata,
287
- })
288
- );
289
- }
290
- }
291
-
292
- return plugins;
293
- }
294
-
295
- /**
296
- * Create an Auth instance.
297
- *
298
- * This wraps BetterAuth with sensible defaults for Agentuity projects:
299
- * - Default basePath: '/api/auth'
300
- * - Email/password authentication enabled by default
301
- * - Organization plugin for multi-tenancy
302
- * - JWT plugin for token-based auth
303
- * - Bearer plugin for API auth
304
- * - API Key plugin for programmatic access
305
- * - Experimental joins enabled by default for better performance
306
- *
307
- * @example Option A: Connection string (simplest)
308
- * ```typescript
309
- * import { createAuth } from '@agentuity/auth';
310
- *
311
- * export const auth = createAuth({
312
- * connectionString: process.env.DATABASE_URL,
313
- * });
314
- * ```
315
- *
316
- * @example Option B: Bring your own Drizzle
317
- * ```typescript
318
- * import { drizzle } from 'drizzle-orm/bun-sql';
319
- * import { drizzleAdapter } from 'better-auth/adapters/drizzle';
320
- * import * as authSchema from '@agentuity/auth/schema';
321
- *
322
- * const schema = { ...authSchema, ...myAppSchema };
323
- * const db = drizzle(connectionString, { schema });
324
- *
325
- * export const auth = createAuth({
326
- * database: drizzleAdapter(db, { provider: 'pg', schema: authSchema }),
327
- * });
328
- * ```
329
- *
330
- * @example Option C: Other adapters (Prisma, MongoDB, etc.)
331
- * ```typescript
332
- * import { prismaAdapter } from 'better-auth/adapters/prisma';
333
- *
334
- * export const auth = createAuth({
335
- * database: prismaAdapter(new PrismaClient()),
336
- * });
337
- * ```
338
- */
339
- export function createAuth<T extends AuthOptions>(options: T) {
340
- const {
341
- skipDefaultPlugins,
342
- plugins = [],
343
- apiKey: apiKeyOptions,
344
- connectionString,
345
- ...restOptions
346
- } = options;
347
-
348
- const resolvedBaseURL = resolveBaseURL(restOptions.baseURL);
349
- const resolvedSecret = resolveSecret(restOptions.secret);
350
-
351
- // Apply Agentuity defaults
352
- const basePath = restOptions.basePath ?? '/api/auth';
353
- const emailAndPassword = restOptions.emailAndPassword ?? { enabled: true };
354
-
355
- // Explicitly type to avoid union type inference issues with downstream consumers
356
- const trustedOrigins: TrustedOrigins =
357
- restOptions.trustedOrigins ?? createDefaultTrustedOrigins(resolvedBaseURL);
358
-
359
- const defaultPlugins = skipDefaultPlugins ? [] : getDefaultPlugins(apiKeyOptions);
360
-
361
- // Handle database configuration
362
- let database = restOptions.database;
363
-
364
- // ConnectionString provided - create Bun SQL connection + drizzle internally
365
- if (connectionString && !database) {
366
- const db = drizzle(connectionString, { schema: authSchema });
367
- database = drizzleAdapter(db, {
368
- provider: 'pg',
369
- schema: authSchema,
370
- });
371
- }
372
-
373
- // Default experimental.joins to true for better performance
374
- const experimental = {
375
- joins: true,
376
- ...restOptions.experimental,
377
- };
378
-
379
- const authInstance = betterAuth({
380
- ...restOptions,
381
- database,
382
- basePath,
383
- emailAndPassword,
384
- experimental,
385
- ...(resolvedBaseURL ? { baseURL: resolvedBaseURL } : {}),
386
- ...(resolvedSecret ? { secret: resolvedSecret } : {}),
387
- trustedOrigins,
388
- plugins: [...defaultPlugins, ...plugins],
389
- });
390
-
391
- return authInstance as AuthBase &
392
- typeof authInstance & {
393
- api: typeof authInstance.api & DefaultPluginApiMethods;
394
- };
395
- }
396
-
397
- /**
398
- * Type helper for the auth instance with default plugin methods.
399
- * Inferred from createAuth to stay in sync with BetterAuth.
400
- */
401
- export type AuthInstance = ReturnType<typeof createAuth>;
@@ -1,158 +0,0 @@
1
- /**
2
- * API Key plugin types for @agentuity/auth.
3
- *
4
- * Server-side API methods for API key management provided by BetterAuth's
5
- * API Key plugin. Enables programmatic access to your application.
6
- *
7
- * @see https://better-auth.com/docs/plugins/api-key
8
- * @module agentuity/plugins/api-key
9
- */
10
-
11
- /**
12
- * API Key data returned from API calls.
13
- */
14
- export interface ApiKey {
15
- id: string;
16
- name: string;
17
- key?: string;
18
- start?: string;
19
- userId?: string;
20
- expiresAt?: Date | null;
21
- createdAt: Date;
22
- permissions?: Record<string, string[]> | null;
23
- metadata?: Record<string, unknown> | null;
24
- }
25
-
26
- /**
27
- * API Key plugin configuration options.
28
- */
29
- export interface ApiKeyPluginOptions {
30
- /**
31
- * Whether to enable API key authentication.
32
- * Defaults to true.
33
- */
34
- enabled?: boolean;
35
-
36
- /**
37
- * Header names to check for API key.
38
- * Defaults to ['x-agentuity-auth-api-key', 'X-Agentuity-Auth-Api-Key'].
39
- */
40
- apiKeyHeaders?: string[];
41
-
42
- /**
43
- * Whether API keys should create mock sessions for the user.
44
- * This allows API key auth to work seamlessly with session-based middleware.
45
- * Defaults to true.
46
- */
47
- enableSessionForAPIKeys?: boolean;
48
-
49
- /**
50
- * Default prefix for generated API keys.
51
- * Defaults to 'ag_'.
52
- */
53
- defaultPrefix?: string;
54
-
55
- /**
56
- * Default length for generated API keys (excluding prefix).
57
- * Defaults to 64.
58
- */
59
- defaultKeyLength?: number;
60
-
61
- /**
62
- * Whether to enable metadata storage on API keys.
63
- * Defaults to true.
64
- */
65
- enableMetadata?: boolean;
66
- }
67
-
68
- /**
69
- * Default API key plugin options.
70
- */
71
- export const DEFAULT_API_KEY_OPTIONS: Required<ApiKeyPluginOptions> = {
72
- enabled: true,
73
- apiKeyHeaders: ['x-agentuity-auth-api-key', 'X-Agentuity-Auth-Api-Key'],
74
- enableSessionForAPIKeys: true,
75
- defaultPrefix: 'ag_',
76
- defaultKeyLength: 64,
77
- enableMetadata: true,
78
- };
79
-
80
- /**
81
- * Server-side API methods for API key management.
82
- *
83
- * These methods are added by the BetterAuth API Key plugin and provide
84
- * programmatic access to your application via API keys.
85
- *
86
- * @see https://better-auth.com/docs/plugins/api-key
87
- */
88
- export interface ApiKeyApiMethods {
89
- /**
90
- * Create a new API key.
91
- *
92
- * When using session headers, the key is created for the authenticated user.
93
- * For server-side creation (without headers), pass `userId` explicitly.
94
- *
95
- * **Important:** The full API key is only returned once at creation time.
96
- * Store it securely - it cannot be retrieved later.
97
- */
98
- createApiKey: (params: {
99
- body: {
100
- name?: string;
101
- expiresIn?: number;
102
- prefix?: string;
103
- userId?: string;
104
- permissions?: Record<string, string[]>;
105
- remaining?: number;
106
- metadata?: Record<string, unknown>;
107
- refillAmount?: number;
108
- refillInterval?: number;
109
- rateLimitTimeWindow?: number;
110
- rateLimitMax?: number;
111
- rateLimitEnabled?: boolean;
112
- };
113
- headers?: Headers;
114
- }) => Promise<ApiKey>;
115
-
116
- /**
117
- * List all API keys for the authenticated user.
118
- *
119
- * Note: The full key value is not returned - only the `start` prefix
120
- * for identification purposes.
121
- */
122
- listApiKeys: (params: { headers?: Headers }) => Promise<
123
- Array<{
124
- id: string;
125
- name: string;
126
- start: string;
127
- expiresAt?: Date | null;
128
- createdAt: Date;
129
- }>
130
- >;
131
-
132
- /**
133
- * Delete an API key.
134
- *
135
- * The key is immediately revoked and can no longer be used for authentication.
136
- */
137
- deleteApiKey: (params: {
138
- body: { keyId: string };
139
- headers?: Headers;
140
- }) => Promise<{ success: boolean }>;
141
-
142
- /**
143
- * Verify an API key and get its metadata.
144
- *
145
- * Used internally by middleware, but can also be called directly
146
- * for custom API key validation logic.
147
- */
148
- verifyApiKey: (params: { body: { key: string }; headers?: Headers }) => Promise<{
149
- valid: boolean;
150
- error?: { message: string; code: string } | null;
151
- key?: {
152
- id: string;
153
- name: string;
154
- userId: string;
155
- permissions?: Record<string, string[]> | null;
156
- } | null;
157
- }>;
158
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * Plugin type exports for @agentuity/auth.
3
- *
4
- * This module re-exports all plugin-specific types and interfaces for
5
- * convenient access. Each plugin has its own file for easier maintenance.
6
- *
7
- * @module agentuity/plugins
8
- */
9
-
10
- // Organization plugin
11
- export type {
12
- Organization,
13
- OrganizationMember,
14
- OrganizationInvitation,
15
- OrganizationApiMethods,
16
- } from './organization';
17
-
18
- // API Key plugin
19
- export type { ApiKey, ApiKeyPluginOptions, ApiKeyApiMethods } from './api-key';
20
- export { DEFAULT_API_KEY_OPTIONS } from './api-key';
21
-
22
- // JWT plugin
23
- export type { JwtApiMethods } from './jwt';
24
-
25
- /**
26
- * Combined API extensions from all default plugins.
27
- *
28
- * This type represents all the server-side API methods added by the
29
- * default Agentuity auth plugins (organization, jwt, bearer, apiKey).
30
- */
31
- import type { OrganizationApiMethods } from './organization';
32
- import type { ApiKeyApiMethods } from './api-key';
33
- import type { JwtApiMethods } from './jwt';
34
-
35
- export type DefaultPluginApiMethods = OrganizationApiMethods & ApiKeyApiMethods & JwtApiMethods;
@@ -1,30 +0,0 @@
1
- /**
2
- * JWT plugin types for @agentuity/auth.
3
- *
4
- * Server-side API methods for JWT token management provided by BetterAuth's
5
- * JWT plugin. Enables token-based authentication.
6
- *
7
- * @see https://better-auth.com/docs/plugins/jwt
8
- * @module agentuity/plugins/jwt
9
- */
10
-
11
- /**
12
- * Server-side API methods for JWT token management.
13
- *
14
- * These methods are added by the BetterAuth JWT plugin and provide
15
- * JWT token generation for authenticated users.
16
- *
17
- * @see https://better-auth.com/docs/plugins/jwt
18
- */
19
- export interface JwtApiMethods {
20
- /**
21
- * Get a JWT token for the authenticated user.
22
- *
23
- * The token can be used with the Bearer plugin for stateless
24
- * authentication in subsequent requests.
25
- *
26
- * The JWKS endpoint for token verification is available at:
27
- * `{baseURL}/api/auth/.well-known/jwks.json`
28
- */
29
- getToken: (params: { headers?: Headers }) => Promise<{ token: string }>;
30
- }