@usearete/sdk 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.
@@ -0,0 +1,381 @@
1
+ 'use strict';
2
+
3
+ var ed25519 = require('@noble/ed25519');
4
+
5
+ function _interopNamespaceDefault(e) {
6
+ var n = Object.create(null);
7
+ if (e) {
8
+ Object.keys(e).forEach(function (k) {
9
+ if (k !== 'default') {
10
+ var d = Object.getOwnPropertyDescriptor(e, k);
11
+ Object.defineProperty(n, k, d.get ? d : {
12
+ enumerable: true,
13
+ get: function () { return e[k]; }
14
+ });
15
+ }
16
+ });
17
+ }
18
+ n.default = e;
19
+ return Object.freeze(n);
20
+ }
21
+
22
+ var ed25519__namespace = /*#__PURE__*/_interopNamespaceDefault(ed25519);
23
+
24
+ /**
25
+ * Base64URL encoding/decoding utilities
26
+ */
27
+ /**
28
+ * Encode Uint8Array to base64url string (RFC 4648)
29
+ */
30
+ function encode(bytes) {
31
+ // Convert to regular base64
32
+ const base64 = Buffer.from(bytes).toString('base64');
33
+ // Convert to base64url: replace + with -, / with _, remove padding
34
+ return base64
35
+ .replace(/\+/g, '-')
36
+ .replace(/\//g, '_')
37
+ .replace(/=/g, '');
38
+ }
39
+ /**
40
+ * Decode base64url string to Uint8Array
41
+ */
42
+ function decode(base64url) {
43
+ // Convert from base64url to regular base64
44
+ let base64 = base64url
45
+ .replace(/-/g, '+')
46
+ .replace(/_/g, '/');
47
+ // Add padding if needed
48
+ const padding = 4 - (base64.length % 4);
49
+ if (padding !== 4) {
50
+ base64 += '='.repeat(padding);
51
+ }
52
+ return new Uint8Array(Buffer.from(base64, 'base64'));
53
+ }
54
+ const base64url = {
55
+ encode,
56
+ decode,
57
+ };
58
+
59
+ /**
60
+ * Arete Auth Server - Drop-in Endpoint Handlers
61
+ *
62
+ * These are framework-agnostic API route handlers that users can mount however they like.
63
+ * They handle token minting and JWKS serving directly using Ed25519 signing.
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * // app/api/arete/sessions/route.ts (Next.js App Router)
68
+ * import { handleSessionRequest, handleJwksRequest } from '@usearete/sdk/ssr/handlers';
69
+ *
70
+ * export async function POST(request: Request) {
71
+ * const user = await getAuthenticatedUser(request);
72
+ * if (!user) return new Response('Unauthorized', { status: 401 });
73
+ * return handleSessionRequest({}, user.id);
74
+ * }
75
+ *
76
+ * export async function GET() {
77
+ * return handleJwksRequest();
78
+ * }
79
+ * ```
80
+ */
81
+ /**
82
+ * Decode base64 to Uint8Array
83
+ */
84
+ function decodeBase64(base64) {
85
+ const binary = Buffer.from(base64, 'base64');
86
+ return new Uint8Array(binary);
87
+ }
88
+ /**
89
+ * Encode Uint8Array to base64url
90
+ */
91
+ function encodeBase64url(bytes) {
92
+ return base64url.encode(bytes);
93
+ }
94
+ /**
95
+ * Generate a key ID from public key bytes
96
+ */
97
+ function deriveKeyId(publicKey) {
98
+ // Use first 8 bytes of public key as hex for kid
99
+ return Array.from(publicKey.slice(0, 8))
100
+ .map(b => b.toString(16).padStart(2, '0'))
101
+ .join('');
102
+ }
103
+ /**
104
+ * Create JWT header for Ed25519
105
+ */
106
+ function createJwtHeader(keyId) {
107
+ const header = {
108
+ alg: 'EdDSA',
109
+ typ: 'JWT',
110
+ kid: keyId,
111
+ };
112
+ return encodeBase64url(new TextEncoder().encode(JSON.stringify(header)));
113
+ }
114
+ /**
115
+ * Create JWT payload from claims
116
+ */
117
+ function createJwtPayload(claims) {
118
+ return encodeBase64url(new TextEncoder().encode(JSON.stringify(claims)));
119
+ }
120
+ /**
121
+ * Sign data with Ed25519
122
+ */
123
+ async function signEd25519(data, privateKey) {
124
+ const messageBytes = new TextEncoder().encode(data);
125
+ return await ed25519__namespace.signAsync(messageBytes, privateKey);
126
+ }
127
+ /**
128
+ * Mint a session token using Ed25519 signing
129
+ * `subject` must come from verified server-side auth or trusted service code.
130
+ */
131
+ async function mintSessionToken(config, subject = 'anonymous', scope = 'read', origin) {
132
+ const signingKeyBase64 = config.signingKey || process.env.ARETE_SIGNING_KEY;
133
+ if (!signingKeyBase64) {
134
+ throw new Error('ARETE_SIGNING_KEY not set. Generate with: node -e "console.log(require(\'crypto\').randomBytes(32).toString(\'base64\'))"');
135
+ }
136
+ const privateKeyBytes = decodeBase64(signingKeyBase64);
137
+ if (privateKeyBytes.length !== 32) {
138
+ throw new Error(`Invalid signing key length: expected 32 bytes, got ${privateKeyBytes.length}. ` +
139
+ 'Ed25519 signing key must be 32 bytes (base64-encoded).');
140
+ }
141
+ // Derive public key from private key
142
+ const publicKeyBytes = await ed25519__namespace.getPublicKeyAsync(privateKeyBytes);
143
+ const keyId = config.keyId || deriveKeyId(publicKeyBytes);
144
+ const issuer = config.issuer || process.env.ARETE_ISSUER || 'arete';
145
+ const audience = config.audience || process.env.ARETE_AUDIENCE || 'arete';
146
+ const ttlSeconds = config.ttlSeconds || 300;
147
+ const now = Math.floor(Date.now() / 1000);
148
+ const expiresAt = now + ttlSeconds;
149
+ const claims = {
150
+ iss: issuer,
151
+ sub: subject,
152
+ aud: audience,
153
+ iat: now,
154
+ nbf: now,
155
+ exp: expiresAt,
156
+ jti: crypto.randomUUID(),
157
+ scope,
158
+ metering_key: `meter:${subject}`,
159
+ key_class: 'secret',
160
+ limits: config.limits || {
161
+ max_connections: 10,
162
+ max_subscriptions: 100,
163
+ max_snapshot_rows: 1000,
164
+ max_messages_per_minute: 10000,
165
+ max_bytes_per_minute: 100 * 1024 * 1024,
166
+ },
167
+ };
168
+ // Add origin binding if provided
169
+ if (origin) {
170
+ claims.origin = origin;
171
+ }
172
+ // Create JWT
173
+ const header = createJwtHeader(keyId);
174
+ const payload = createJwtPayload(claims);
175
+ const signingInput = `${header}.${payload}`;
176
+ const signature = await signEd25519(signingInput, privateKeyBytes);
177
+ const signatureBase64 = encodeBase64url(signature);
178
+ const token = `${signingInput}.${signatureBase64}`;
179
+ return {
180
+ token,
181
+ expires_at: expiresAt,
182
+ };
183
+ }
184
+ /**
185
+ * Generate JWKS response from signing key
186
+ */
187
+ async function generateJwks(config) {
188
+ const signingKeyBase64 = config.signingKey || process.env.ARETE_SIGNING_KEY;
189
+ const publicKeyBase64 = config.publicKey || process.env.ARETE_PUBLIC_KEY;
190
+ if (!signingKeyBase64 && !publicKeyBase64) {
191
+ return { keys: [] };
192
+ }
193
+ let publicKeyBytes;
194
+ if (publicKeyBase64) {
195
+ // Use provided public key
196
+ publicKeyBytes = decodeBase64(publicKeyBase64);
197
+ if (publicKeyBytes.length !== 32) {
198
+ throw new Error(`Invalid public key length: expected 32 bytes, got ${publicKeyBytes.length}`);
199
+ }
200
+ }
201
+ else {
202
+ // Derive public key from private key
203
+ const privateKeyBytes = decodeBase64(signingKeyBase64);
204
+ if (privateKeyBytes.length !== 32) {
205
+ throw new Error(`Invalid signing key length: expected 32 bytes, got ${privateKeyBytes.length}`);
206
+ }
207
+ publicKeyBytes = await ed25519__namespace.getPublicKeyAsync(privateKeyBytes);
208
+ }
209
+ const keyId = config.keyId ||
210
+ (publicKeyBase64 ? 'key-1' : deriveKeyId(publicKeyBytes));
211
+ return {
212
+ keys: [
213
+ {
214
+ kty: 'OKP',
215
+ crv: 'Ed25519',
216
+ kid: keyId,
217
+ use: 'sig',
218
+ alg: 'EdDSA',
219
+ x: encodeBase64url(publicKeyBytes),
220
+ },
221
+ ],
222
+ };
223
+ }
224
+
225
+ /**
226
+ * TanStack Start integration for Arete Auth
227
+ *
228
+ * Drop-in API route handlers for TanStack Start.
229
+ * `resolveSession` must derive the subject from verified server-side auth.
230
+ * Never trust caller-supplied headers for identity or scope.
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * // app/routes/api/arete/sessions.ts
235
+ * import { createTanStackSessionRoute, createTanStackJwksRoute } from '@usearete/sdk/ssr/tanstack-start';
236
+ * import { json } from '@tanstack/react-start';
237
+ *
238
+ * export const APIRoute = createTanStackSessionRoute({
239
+ * resolveSession: async ({ request }) => {
240
+ * const user = await getAuthenticatedUser(request);
241
+ * if (!user) return null;
242
+ * return { subject: user.id };
243
+ * },
244
+ * });
245
+ *
246
+ * // For JWKS at the same route with GET
247
+ * export const GET = createTanStackJwksRoute();
248
+ * ```
249
+ */
250
+ /**
251
+ * Create a TanStack Start handler for POST /sessions
252
+ * Returns a function compatible with TanStack Start's APIRoute
253
+ */
254
+ function createTanStackSessionRoute(config = {}) {
255
+ return async function POST({ request }) {
256
+ const origin = request.headers.get('origin') || undefined;
257
+ try {
258
+ if (!config.resolveSession) {
259
+ return new Response(JSON.stringify({
260
+ error: 'createTanStackSessionRoute requires resolveSession to derive the subject from authenticated server-side state',
261
+ }), {
262
+ status: 500,
263
+ headers: {
264
+ 'Content-Type': 'application/json',
265
+ },
266
+ });
267
+ }
268
+ const session = await config.resolveSession({ request });
269
+ if (!session) {
270
+ return new Response(JSON.stringify({
271
+ error: 'Unauthorized',
272
+ }), {
273
+ status: 401,
274
+ headers: {
275
+ 'Content-Type': 'application/json',
276
+ },
277
+ });
278
+ }
279
+ const tokenData = await mintSessionToken(config, session.subject, session.scope || 'read', origin);
280
+ return new Response(JSON.stringify(tokenData), {
281
+ status: 200,
282
+ headers: {
283
+ 'Content-Type': 'application/json',
284
+ },
285
+ });
286
+ }
287
+ catch (error) {
288
+ return new Response(JSON.stringify({
289
+ error: error instanceof Error ? error.message : 'Failed to mint token',
290
+ }), {
291
+ status: 500,
292
+ headers: {
293
+ 'Content-Type': 'application/json',
294
+ },
295
+ });
296
+ }
297
+ };
298
+ }
299
+ /**
300
+ * Create a TanStack Start handler for GET /.well-known/jwks.json
301
+ */
302
+ function createTanStackJwksRoute(config = {}) {
303
+ return async function GET() {
304
+ try {
305
+ const jwks = await generateJwks(config);
306
+ return new Response(JSON.stringify(jwks), {
307
+ status: 200,
308
+ headers: {
309
+ 'Content-Type': 'application/json',
310
+ },
311
+ });
312
+ }
313
+ catch (error) {
314
+ return new Response(JSON.stringify({
315
+ error: error instanceof Error ? error.message : 'Failed to generate JWKS',
316
+ }), {
317
+ status: 500,
318
+ headers: {
319
+ 'Content-Type': 'application/json',
320
+ },
321
+ });
322
+ }
323
+ };
324
+ }
325
+ /**
326
+ * Create a TanStack Start API route that handles both POST (sessions) and GET (JWKS)
327
+ *
328
+ * @example
329
+ * ```typescript
330
+ * // app/routes/api/arete/auth.ts
331
+ * import { createTanStackAuthRoute } from '@usearete/sdk/ssr/tanstack-start';
332
+ *
333
+ * export const APIRoute = createTanStackAuthRoute({
334
+ * resolveSession: async ({ request }) => {
335
+ * const user = await getAuthenticatedUser(request);
336
+ * if (!user) return null;
337
+ * return { subject: user.id };
338
+ * },
339
+ * ttlSeconds: 600,
340
+ * });
341
+ * ```
342
+ */
343
+ function createTanStackAuthRoute(config = {}) {
344
+ return {
345
+ POST: createTanStackSessionRoute(config),
346
+ GET: createTanStackJwksRoute(config),
347
+ };
348
+ }
349
+ /**
350
+ * Hook to access the Arete token in TanStack Start loaders
351
+ *
352
+ * @example
353
+ * ```typescript
354
+ * // app/routes/dashboard.tsx
355
+ * import { createFileRoute } from '@tanstack/react-start';
356
+ * import { fetchAreteToken } from '@usearete/sdk/ssr/tanstack-start';
357
+ *
358
+ * export const Route = createFileRoute('/dashboard')({
359
+ * loader: async () => {
360
+ * const token = await fetchAreteToken('/api/arete/sessions');
361
+ * // Use token for data fetching...
362
+ * },
363
+ * });
364
+ * ```
365
+ */
366
+ async function fetchAreteToken(endpoint = '/api/arete/sessions') {
367
+ const response = await fetch(endpoint, {
368
+ method: 'POST',
369
+ });
370
+ if (!response.ok) {
371
+ throw new Error(`Failed to fetch token: ${response.statusText}`);
372
+ }
373
+ const data = (await response.json());
374
+ return data.token;
375
+ }
376
+
377
+ exports.createTanStackAuthRoute = createTanStackAuthRoute;
378
+ exports.createTanStackJwksRoute = createTanStackJwksRoute;
379
+ exports.createTanStackSessionRoute = createTanStackSessionRoute;
380
+ exports.fetchAreteToken = fetchAreteToken;
381
+ //# sourceMappingURL=tanstack-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tanstack-start.js","sources":["../../src/ssr/utils.ts","../../src/ssr/handlers.ts","../../src/ssr/tanstack-start.ts"],"sourcesContent":[null,null,null],"names":["ed25519"],"mappings":"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"}
@@ -0,0 +1,164 @@
1
+ import { Request, Response } from 'express';
2
+
3
+ /**
4
+ * Arete Auth Server - Drop-in Endpoint Handlers
5
+ *
6
+ * These are framework-agnostic API route handlers that users can mount however they like.
7
+ * They handle token minting and JWKS serving directly using Ed25519 signing.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // app/api/arete/sessions/route.ts (Next.js App Router)
12
+ * import { handleSessionRequest, handleJwksRequest } from '@usearete/sdk/ssr/handlers';
13
+ *
14
+ * export async function POST(request: Request) {
15
+ * const user = await getAuthenticatedUser(request);
16
+ * if (!user) return new Response('Unauthorized', { status: 401 });
17
+ * return handleSessionRequest({}, user.id);
18
+ * }
19
+ *
20
+ * export async function GET() {
21
+ * return handleJwksRequest();
22
+ * }
23
+ * ```
24
+ */
25
+ interface AuthHandlerConfig {
26
+ /**
27
+ * Ed25519 signing key seed (base64-encoded, 32 bytes).
28
+ * Set ARETE_SIGNING_KEY env var OR pass here.
29
+ * Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
30
+ */
31
+ signingKey?: string;
32
+ /**
33
+ * Optional: Pre-derived public key (base64-encoded, 32 bytes).
34
+ * If not provided, will be derived from the signing key.
35
+ */
36
+ publicKey?: string;
37
+ /**
38
+ * Token issuer (defaults to ARETE_ISSUER env var or 'arete')
39
+ */
40
+ issuer?: string;
41
+ /**
42
+ * Token audience (defaults to ARETE_AUDIENCE env var)
43
+ */
44
+ audience?: string;
45
+ /**
46
+ * Token TTL in seconds (defaults to 300 = 5 minutes)
47
+ */
48
+ ttlSeconds?: number;
49
+ /**
50
+ * Key ID for JWKS (defaults to 'key-1')
51
+ */
52
+ keyId?: string;
53
+ /**
54
+ * Custom limits for tokens
55
+ */
56
+ limits?: {
57
+ max_connections?: number;
58
+ max_subscriptions?: number;
59
+ max_snapshot_rows?: number;
60
+ };
61
+ }
62
+ interface TokenResponse {
63
+ token: string;
64
+ expires_at: number;
65
+ }
66
+ /**
67
+ * Authenticated session data resolved by framework adapters.
68
+ * Always derive this from verified server-side auth, never request headers.
69
+ */
70
+ interface ResolvedSession {
71
+ subject: string;
72
+ scope?: string;
73
+ }
74
+
75
+ /**
76
+ * Vite SSR integration for Arete Auth
77
+ *
78
+ * Express/Connect middleware that mounts auth endpoints.
79
+ * `resolveSession` must derive the subject from verified server-side auth.
80
+ * Never trust caller-supplied headers for identity or scope.
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * // server.ts
85
+ * import express from 'express';
86
+ * import { createViteAuthMiddleware } from '@usearete/sdk/ssr/vite';
87
+ *
88
+ * const app = express();
89
+ *
90
+ * // Mount auth endpoints at /api/arete
91
+ * app.use('/api/arete', createViteAuthMiddleware({
92
+ * resolveSession: async (req) => {
93
+ * const user = await getAuthenticatedUser(req);
94
+ * if (!user) return null;
95
+ * return { subject: user.id };
96
+ * },
97
+ * }));
98
+ *
99
+ * // Or mount at root
100
+ * app.use(createViteAuthMiddleware({
101
+ * basePath: '/auth',
102
+ * resolveSession: async (req) => {
103
+ * const user = await getAuthenticatedUser(req);
104
+ * if (!user) return null;
105
+ * return { subject: user.id };
106
+ * },
107
+ * }));
108
+ * ```
109
+ */
110
+
111
+ interface ViteAuthMiddlewareOptions extends AuthHandlerConfig {
112
+ /**
113
+ * Base path for auth endpoints relative to this middleware mount point
114
+ * @default ''
115
+ */
116
+ basePath?: string;
117
+ /**
118
+ * Resolve the authenticated subject from server-side auth middleware/session state.
119
+ */
120
+ resolveSession?: (req: Request, res: Response) => Promise<ResolvedSession | null> | ResolvedSession | null;
121
+ }
122
+ /**
123
+ * Create Express middleware that mounts Arete auth endpoints
124
+ */
125
+ declare function createViteAuthMiddleware(options?: ViteAuthMiddlewareOptions): (req: Request, res: Response, next: () => void) => Promise<void>;
126
+ /**
127
+ * Create a Vite plugin that injects the auth endpoints
128
+ * This is for use with Vite's configureServer hook
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * // vite.config.ts
133
+ * import { defineConfig } from 'vite';
134
+ * import { createViteAuthPlugin } from '@usearete/sdk/ssr/vite';
135
+ *
136
+ * export default defineConfig({
137
+ * plugins: [
138
+ * createViteAuthPlugin({
139
+ * basePath: '/api/arete',
140
+ * resolveSession: async (req) => {
141
+ * const user = await getAuthenticatedUser(req);
142
+ * if (!user) return null;
143
+ * return { subject: user.id };
144
+ * },
145
+ * }),
146
+ * ],
147
+ * });
148
+ * ```
149
+ */
150
+ declare function createViteAuthPlugin(options?: ViteAuthMiddlewareOptions): {
151
+ name: string;
152
+ configureServer(server: {
153
+ middlewares: {
154
+ use: (path: string, middleware: unknown) => void;
155
+ };
156
+ }): void;
157
+ };
158
+ /**
159
+ * Helper to inject token into HTML for client-side hydration
160
+ */
161
+ declare function injectAreteToken(html: string, token: string | undefined): string;
162
+
163
+ export { createViteAuthMiddleware, createViteAuthPlugin, injectAreteToken };
164
+ export type { AuthHandlerConfig, ResolvedSession, TokenResponse, ViteAuthMiddlewareOptions };