@every-app/sdk 0.1.13 → 0.1.14

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 (32) hide show
  1. package/dist/shared/bypassGatewayLocalOnly.d.ts +2 -1
  2. package/dist/shared/bypassGatewayLocalOnly.d.ts.map +1 -1
  3. package/dist/shared/bypassGatewayLocalOnly.js +6 -2
  4. package/dist/tanstack/server/authenticateRequest.d.ts +2 -0
  5. package/dist/tanstack/server/authenticateRequest.d.ts.map +1 -1
  6. package/dist/tanstack/server/authenticateRequest.js +75 -3
  7. package/package.json +3 -3
  8. package/src/cloudflare/getLocalD1Url.ts +0 -64
  9. package/src/cloudflare/index.ts +0 -1
  10. package/src/cloudflare/lazyInit.ts +0 -67
  11. package/src/cloudflare/server/gateway.test.ts +0 -262
  12. package/src/cloudflare/server/gateway.ts +0 -114
  13. package/src/cloudflare/server/index.ts +0 -2
  14. package/src/core/authenticatedFetch.ts +0 -54
  15. package/src/core/index.ts +0 -12
  16. package/src/core/sessionManager.test.ts +0 -939
  17. package/src/core/sessionManager.ts +0 -492
  18. package/src/env.d.ts +0 -13
  19. package/src/shared/bypassGatewayLocalOnly.ts +0 -55
  20. package/src/shared/parseMessagePayload.ts +0 -22
  21. package/src/tanstack/EmbeddedAppProvider.tsx +0 -96
  22. package/src/tanstack/GatewayRequiredError.tsx +0 -150
  23. package/src/tanstack/_internal/useEveryAppSession.test.ts +0 -40
  24. package/src/tanstack/_internal/useEveryAppSession.tsx +0 -74
  25. package/src/tanstack/index.ts +0 -3
  26. package/src/tanstack/server/authConfig.ts +0 -19
  27. package/src/tanstack/server/authenticateRequest.test.ts +0 -482
  28. package/src/tanstack/server/authenticateRequest.ts +0 -143
  29. package/src/tanstack/server/index.ts +0 -3
  30. package/src/tanstack/server/types.ts +0 -4
  31. package/src/tanstack/useEveryAppRouter.tsx +0 -83
  32. package/src/tanstack/useSessionTokenClientMiddleware.ts +0 -43
@@ -1,482 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
- import { SignJWT, generateKeyPair, exportJWK } from "jose";
3
-
4
- // Mock the cloudflare:workers module
5
- vi.mock("cloudflare:workers", () => ({
6
- env: {
7
- GATEWAY_URL: "https://gateway.example.com",
8
- EVERY_APP_GATEWAY: null,
9
- },
10
- }));
11
-
12
- // Mock @tanstack/react-start/server
13
- vi.mock("@tanstack/react-start/server", () => ({
14
- getRequest: vi.fn(),
15
- }));
16
-
17
- import { authenticateRequest } from "./authenticateRequest";
18
- import type { AuthConfig } from "./types";
19
- import { env } from "cloudflare:workers";
20
-
21
- describe("authenticateRequest", () => {
22
- let keyPair: Awaited<ReturnType<typeof generateKeyPair>>;
23
- let jwks: { keys: object[] };
24
-
25
- const authConfig: AuthConfig = {
26
- issuer: "https://gateway.example.com",
27
- audience: "test-app",
28
- };
29
- const workersEnv = env as unknown as {
30
- BYPASS_GATEWAY_LOCAL_ONLY?: string;
31
- };
32
-
33
- beforeEach(async () => {
34
- // Generate a fresh key pair for each test
35
- keyPair = await generateKeyPair("RS256");
36
- const publicJwk = await exportJWK(keyPair.publicKey);
37
-
38
- jwks = {
39
- keys: [
40
- {
41
- ...publicJwk,
42
- kid: "test-key-1",
43
- use: "sig",
44
- alg: "RS256",
45
- },
46
- ],
47
- };
48
-
49
- // Mock global fetch for JWKS endpoint
50
- global.fetch = vi.fn().mockImplementation(async (url: string) => {
51
- if (url.includes("/api/embedded/jwks")) {
52
- return new Response(JSON.stringify(jwks), {
53
- status: 200,
54
- headers: { "Content-Type": "application/json" },
55
- });
56
- }
57
- return new Response("Not Found", { status: 404 });
58
- });
59
- });
60
-
61
- afterEach(() => {
62
- vi.restoreAllMocks();
63
- delete workersEnv.BYPASS_GATEWAY_LOCAL_ONLY;
64
- });
65
-
66
- async function createValidToken(overrides: Record<string, unknown> = {}) {
67
- // Token now only contains minimal claims: sub, email, iss, aud, exp, iat
68
- // appId is represented by aud claim, permissions and embeddedApp were removed
69
- const jwt = await new SignJWT({
70
- email: "user@example.com",
71
- ...overrides,
72
- })
73
- .setProtectedHeader({ alg: "RS256" })
74
- .setSubject("user-123")
75
- .setIssuer(authConfig.issuer)
76
- .setAudience(authConfig.audience)
77
- .setExpirationTime("1h")
78
- .setIssuedAt()
79
- .sign(keyPair.privateKey);
80
-
81
- return jwt;
82
- }
83
-
84
- function createRequest(authHeader?: string): Request {
85
- const headers = new Headers();
86
- if (authHeader) {
87
- headers.set("authorization", authHeader);
88
- }
89
- return new Request("https://app.example.com/api/test", { headers });
90
- }
91
-
92
- describe("missing or invalid authorization header", () => {
93
- it("returns null when no authorization header is present", async () => {
94
- const request = createRequest();
95
- const result = await authenticateRequest(authConfig, request);
96
- expect(result).toBeNull();
97
- });
98
-
99
- it("returns null for empty authorization header", async () => {
100
- const request = createRequest("");
101
- const result = await authenticateRequest(authConfig, request);
102
- expect(result).toBeNull();
103
- });
104
-
105
- it("returns null for non-Bearer authorization", async () => {
106
- const request = createRequest("Basic dXNlcjpwYXNz");
107
- const result = await authenticateRequest(authConfig, request);
108
- expect(result).toBeNull();
109
- });
110
-
111
- it("returns null for malformed Bearer token (no space)", async () => {
112
- const request = createRequest("BearereyJhbGciOiJSUzI1NiJ9");
113
- const result = await authenticateRequest(authConfig, request);
114
- expect(result).toBeNull();
115
- });
116
-
117
- it("returns null for lowercase bearer prefix", async () => {
118
- const token = await createValidToken();
119
- const request = createRequest(`bearer ${token}`);
120
- const result = await authenticateRequest(authConfig, request);
121
- expect(result).toBeNull();
122
- });
123
- });
124
-
125
- describe("BYPASS_GATEWAY_LOCAL_ONLY mode", () => {
126
- it("accepts the local bypass token when BYPASS_GATEWAY_LOCAL_ONLY is true", async () => {
127
- workersEnv.BYPASS_GATEWAY_LOCAL_ONLY = "true";
128
- const request = createRequest("Bearer BYPASS_GATEWAY_LOCAL_ONLY");
129
-
130
- const result = await authenticateRequest(authConfig, request);
131
-
132
- expect(result).toMatchObject({
133
- sub: "demo-local-user",
134
- email: "demo-local-user@local",
135
- iss: "local",
136
- aud: authConfig.audience,
137
- });
138
- expect(global.fetch).not.toHaveBeenCalled();
139
- });
140
-
141
- it("rejects non-bypass tokens when BYPASS_GATEWAY_LOCAL_ONLY is true", async () => {
142
- workersEnv.BYPASS_GATEWAY_LOCAL_ONLY = "true";
143
- const request = createRequest("Bearer regular-token");
144
-
145
- const result = await authenticateRequest(authConfig, request);
146
-
147
- expect(result).toBeNull();
148
- expect(global.fetch).not.toHaveBeenCalled();
149
- });
150
- });
151
-
152
- describe("valid token verification", () => {
153
- it("returns payload for valid token with correct issuer and audience", async () => {
154
- const token = await createValidToken();
155
- const request = createRequest(`Bearer ${token}`);
156
-
157
- const result = await authenticateRequest(authConfig, request);
158
-
159
- expect(result).not.toBeNull();
160
- expect(result!.sub).toBe("user-123");
161
- expect(result!.email).toBe("user@example.com");
162
- expect(result!.iss).toBe(authConfig.issuer);
163
- // audience contains the appId
164
- expect(result!.aud).toBe(authConfig.audience);
165
- });
166
-
167
- it("includes iat and exp claims in returned payload", async () => {
168
- const token = await createValidToken();
169
- const request = createRequest(`Bearer ${token}`);
170
-
171
- const result = await authenticateRequest(authConfig, request);
172
-
173
- expect(result).not.toBeNull();
174
- expect(typeof result!.iat).toBe("number");
175
- expect(typeof result!.exp).toBe("number");
176
- expect(result!.exp).toBeGreaterThan(result!.iat);
177
- });
178
- });
179
-
180
- describe("token expiration", () => {
181
- it("returns null for expired token", async () => {
182
- const jwt = await new SignJWT({ email: "user@example.com" })
183
- .setProtectedHeader({ alg: "RS256" })
184
- .setSubject("user-123")
185
- .setIssuer(authConfig.issuer)
186
- .setAudience(authConfig.audience)
187
- .setExpirationTime("-1h") // Expired 1 hour ago
188
- .setIssuedAt(Math.floor(Date.now() / 1000) - 7200) // Issued 2 hours ago
189
- .sign(keyPair.privateKey);
190
-
191
- const request = createRequest(`Bearer ${jwt}`);
192
- const result = await authenticateRequest(authConfig, request);
193
-
194
- expect(result).toBeNull();
195
- });
196
- });
197
-
198
- describe("issuer validation", () => {
199
- it("returns null for token with wrong issuer", async () => {
200
- const jwt = await new SignJWT({ email: "user@example.com" })
201
- .setProtectedHeader({ alg: "RS256" })
202
- .setSubject("user-123")
203
- .setIssuer("https://malicious.example.com") // Wrong issuer
204
- .setAudience(authConfig.audience)
205
- .setExpirationTime("1h")
206
- .setIssuedAt()
207
- .sign(keyPair.privateKey);
208
-
209
- const request = createRequest(`Bearer ${jwt}`);
210
- const result = await authenticateRequest(authConfig, request);
211
-
212
- expect(result).toBeNull();
213
- });
214
-
215
- it("returns null for token with missing issuer", async () => {
216
- const jwt = await new SignJWT({ email: "user@example.com" })
217
- .setProtectedHeader({ alg: "RS256" })
218
- .setSubject("user-123")
219
- // No issuer set
220
- .setAudience(authConfig.audience)
221
- .setExpirationTime("1h")
222
- .setIssuedAt()
223
- .sign(keyPair.privateKey);
224
-
225
- const request = createRequest(`Bearer ${jwt}`);
226
- const result = await authenticateRequest(authConfig, request);
227
-
228
- expect(result).toBeNull();
229
- });
230
- });
231
-
232
- describe("audience validation", () => {
233
- it("returns null for token with wrong audience", async () => {
234
- const jwt = await new SignJWT({ email: "user@example.com" })
235
- .setProtectedHeader({ alg: "RS256" })
236
- .setSubject("user-123")
237
- .setIssuer(authConfig.issuer)
238
- .setAudience("wrong-app") // Wrong audience
239
- .setExpirationTime("1h")
240
- .setIssuedAt()
241
- .sign(keyPair.privateKey);
242
-
243
- const request = createRequest(`Bearer ${jwt}`);
244
- const result = await authenticateRequest(authConfig, request);
245
-
246
- expect(result).toBeNull();
247
- });
248
-
249
- it("returns null for token with missing audience", async () => {
250
- const jwt = await new SignJWT({ email: "user@example.com" })
251
- .setProtectedHeader({ alg: "RS256" })
252
- .setSubject("user-123")
253
- .setIssuer(authConfig.issuer)
254
- // No audience set
255
- .setExpirationTime("1h")
256
- .setIssuedAt()
257
- .sign(keyPair.privateKey);
258
-
259
- const request = createRequest(`Bearer ${jwt}`);
260
- const result = await authenticateRequest(authConfig, request);
261
-
262
- expect(result).toBeNull();
263
- });
264
- });
265
-
266
- describe("signature validation", () => {
267
- it("returns null for token signed with different key", async () => {
268
- // Generate a different key pair
269
- const differentKeyPair = await generateKeyPair("RS256");
270
-
271
- const jwt = await new SignJWT({ email: "user@example.com" })
272
- .setProtectedHeader({ alg: "RS256" })
273
- .setSubject("user-123")
274
- .setIssuer(authConfig.issuer)
275
- .setAudience(authConfig.audience)
276
- .setExpirationTime("1h")
277
- .setIssuedAt()
278
- .sign(differentKeyPair.privateKey); // Different key!
279
-
280
- const request = createRequest(`Bearer ${jwt}`);
281
- const result = await authenticateRequest(authConfig, request);
282
-
283
- expect(result).toBeNull();
284
- });
285
-
286
- it("returns null for tampered token payload", async () => {
287
- const token = await createValidToken();
288
- // Tamper with the payload by modifying the base64
289
- const [header, _payload, signature] = token.split(".");
290
- const tamperedPayload = btoa(
291
- JSON.stringify({ sub: "attacker-id", email: "attacker@evil.com" }),
292
- )
293
- .replace(/=/g, "")
294
- .replace(/\+/g, "-")
295
- .replace(/\//g, "_");
296
- const tamperedToken = `${header}.${tamperedPayload}.${signature}`;
297
-
298
- const request = createRequest(`Bearer ${tamperedToken}`);
299
- const result = await authenticateRequest(authConfig, request);
300
-
301
- expect(result).toBeNull();
302
- });
303
-
304
- it("returns null for malformed JWT structure", async () => {
305
- const malformedTokens = [
306
- "not.a.valid.jwt.structure",
307
- "only-one-part",
308
- "two.parts",
309
- "",
310
- "header.payload.", // Missing signature
311
- ".payload.signature", // Missing header
312
- ];
313
-
314
- for (const token of malformedTokens) {
315
- const request = createRequest(`Bearer ${token}`);
316
- const result = await authenticateRequest(authConfig, request);
317
- expect(result).toBeNull();
318
- }
319
- });
320
- });
321
-
322
- describe("algorithm restrictions", () => {
323
- it("returns null for HS256-signed token against RSA JWKS", async () => {
324
- // Create HS256 token using a symmetric secret
325
- const secret = new TextEncoder().encode("super-secret-key");
326
- const jwt = await new SignJWT({ email: "user@example.com" })
327
- .setProtectedHeader({ alg: "HS256" })
328
- .setSubject("user-123")
329
- .setIssuer(authConfig.issuer)
330
- .setAudience(authConfig.audience)
331
- .setExpirationTime("1h")
332
- .setIssuedAt()
333
- .sign(secret);
334
-
335
- const request = createRequest(`Bearer ${jwt}`);
336
- const result = await authenticateRequest(authConfig, request);
337
-
338
- expect(result).toBeNull();
339
- });
340
-
341
- it("returns null for unsecured 'none' algorithm token", async () => {
342
- // Craft a JWT with alg: none and no signature
343
- const header = Buffer.from(JSON.stringify({ alg: "none", typ: "JWT" }))
344
- .toString("base64")
345
- .replace(/=/g, "")
346
- .replace(/\+/g, "-")
347
- .replace(/\//g, "_");
348
-
349
- const payload = Buffer.from(
350
- JSON.stringify({
351
- sub: "user-123",
352
- iss: authConfig.issuer,
353
- aud: authConfig.audience,
354
- iat: Math.floor(Date.now() / 1000),
355
- exp: Math.floor(Date.now() / 1000) + 3600,
356
- email: "user@example.com",
357
- }),
358
- )
359
- .toString("base64")
360
- .replace(/=/g, "")
361
- .replace(/\+/g, "-")
362
- .replace(/\//g, "_");
363
-
364
- // Note the trailing dot for empty signature
365
- const unsecuredToken = `${header}.${payload}.`;
366
-
367
- const request = createRequest(`Bearer ${unsecuredToken}`);
368
- const result = await authenticateRequest(authConfig, request);
369
-
370
- expect(result).toBeNull();
371
- });
372
- });
373
-
374
- describe("JWKS fetch failures", () => {
375
- it("returns null when JWKS endpoint returns 404", async () => {
376
- global.fetch = vi
377
- .fn()
378
- .mockResolvedValue(new Response("Not Found", { status: 404 }));
379
-
380
- const token = await createValidToken();
381
- const request = createRequest(`Bearer ${token}`);
382
- const result = await authenticateRequest(authConfig, request);
383
-
384
- expect(result).toBeNull();
385
- });
386
-
387
- it("returns null when JWKS endpoint returns 500", async () => {
388
- global.fetch = vi
389
- .fn()
390
- .mockResolvedValue(
391
- new Response("Internal Server Error", { status: 500 }),
392
- );
393
-
394
- const token = await createValidToken();
395
- const request = createRequest(`Bearer ${token}`);
396
- const result = await authenticateRequest(authConfig, request);
397
-
398
- expect(result).toBeNull();
399
- });
400
-
401
- it("returns null when JWKS fetch throws network error", async () => {
402
- global.fetch = vi.fn().mockRejectedValue(new Error("Network error"));
403
-
404
- const token = await createValidToken();
405
- const request = createRequest(`Bearer ${token}`);
406
- const result = await authenticateRequest(authConfig, request);
407
-
408
- expect(result).toBeNull();
409
- });
410
-
411
- it("returns null when JWKS returns invalid JSON", async () => {
412
- global.fetch = vi.fn().mockResolvedValue(
413
- new Response("not valid json", {
414
- status: 200,
415
- headers: { "Content-Type": "application/json" },
416
- }),
417
- );
418
-
419
- const token = await createValidToken();
420
- const request = createRequest(`Bearer ${token}`);
421
- const result = await authenticateRequest(authConfig, request);
422
-
423
- expect(result).toBeNull();
424
- });
425
-
426
- it("returns null when JWKS has no matching key", async () => {
427
- // Return JWKS with a different key
428
- const differentKeyPair = await generateKeyPair("RS256");
429
- const differentJwk = await exportJWK(differentKeyPair.publicKey);
430
-
431
- global.fetch = vi.fn().mockResolvedValue(
432
- new Response(
433
- JSON.stringify({
434
- keys: [{ ...differentJwk, kid: "different-key", alg: "RS256" }],
435
- }),
436
- { status: 200, headers: { "Content-Type": "application/json" } },
437
- ),
438
- );
439
-
440
- const token = await createValidToken();
441
- const request = createRequest(`Bearer ${token}`);
442
- const result = await authenticateRequest(authConfig, request);
443
-
444
- expect(result).toBeNull();
445
- });
446
- });
447
-
448
- describe("error logging", () => {
449
- it("omits stack details in production logs", async () => {
450
- const originalProd = import.meta.env.PROD;
451
- import.meta.env.PROD = true;
452
-
453
- const consoleErrorSpy = vi
454
- .spyOn(console, "error")
455
- .mockImplementation(() => undefined);
456
-
457
- try {
458
- const request = createRequest("Bearer malformed.token");
459
- const result = await authenticateRequest(authConfig, request);
460
-
461
- expect(result).toBeNull();
462
- expect(consoleErrorSpy).toHaveBeenCalledTimes(1);
463
-
464
- const [payload] = consoleErrorSpy.mock.calls[0];
465
- expect(typeof payload).toBe("string");
466
-
467
- const parsed = JSON.parse(payload as string) as {
468
- stack?: string;
469
- message: string;
470
- issuer: string;
471
- audience: string;
472
- };
473
- expect(parsed.message).toBe("Error verifying session token");
474
- expect(parsed.issuer).toBe(authConfig.issuer);
475
- expect(parsed.audience).toBe(authConfig.audience);
476
- expect(parsed.stack).toBeUndefined();
477
- } finally {
478
- import.meta.env.PROD = originalProd;
479
- }
480
- });
481
- });
482
- });
@@ -1,143 +0,0 @@
1
- import { getRequest } from "@tanstack/react-start/server";
2
- import {
3
- createLocalJWKSet,
4
- jwtVerify,
5
- JWTVerifyOptions,
6
- JSONWebKeySet,
7
- } from "jose";
8
-
9
- import type { AuthConfig } from "./types.js";
10
- import { env } from "cloudflare:workers";
11
- import {
12
- BYPASS_GATEWAY_LOCAL_ONLY_TOKEN,
13
- createBypassGatewayLocalOnlySessionPayload,
14
- isBypassGatewayLocalOnlyServer,
15
- } from "../../shared/bypassGatewayLocalOnly.js";
16
-
17
- /**
18
- * JWT payload structure for embedded app session tokens.
19
- * Contains minimal claims for security - only what's needed for authentication.
20
- */
21
- interface SessionTokenPayload {
22
- /** User ID (subject claim) */
23
- sub: string;
24
- /** Gateway URL (issuer claim) */
25
- iss: string;
26
- /** App ID (audience claim) - scopes token to specific app */
27
- aud: string;
28
- /** Expiration timestamp */
29
- exp: number;
30
- /** Issued at timestamp */
31
- iat: number;
32
- /** User email - used for user provisioning in apps */
33
- email?: string;
34
- }
35
-
36
- export async function authenticateRequest(
37
- authConfig: AuthConfig,
38
- providedRequest?: Request,
39
- ): Promise<SessionTokenPayload | null> {
40
- const request = providedRequest || getRequest();
41
- const authHeader = request.headers.get("authorization");
42
-
43
- const bypassGatewayLocalOnlyEnv = (
44
- env as { BYPASS_GATEWAY_LOCAL_ONLY?: string }
45
- ).BYPASS_GATEWAY_LOCAL_ONLY;
46
- const isBypassGatewayLocalOnly =
47
- import.meta.env.PROD !== true &&
48
- (bypassGatewayLocalOnlyEnv === "true" ||
49
- isBypassGatewayLocalOnlyServer() === true);
50
-
51
- if (!authHeader) {
52
- return null;
53
- }
54
-
55
- const token = extractBearerToken(authHeader);
56
-
57
- if (!token) {
58
- return null;
59
- }
60
-
61
- if (isBypassGatewayLocalOnly) {
62
- if (token !== BYPASS_GATEWAY_LOCAL_ONLY_TOKEN) {
63
- return null;
64
- }
65
-
66
- return createBypassGatewayLocalOnlySessionPayload(authConfig.audience);
67
- }
68
-
69
- try {
70
- const session = await verifySessionToken(token, authConfig);
71
- return session;
72
- } catch (error) {
73
- const isProd = import.meta.env.PROD === true;
74
- console.error(
75
- JSON.stringify({
76
- message: "Error verifying session token",
77
- error: error instanceof Error ? error.message : String(error),
78
- stack:
79
- isProd === true
80
- ? undefined
81
- : error instanceof Error
82
- ? error.stack
83
- : undefined,
84
- errorType: error instanceof Error ? error.constructor.name : "Unknown",
85
- issuer: authConfig.issuer,
86
- audience: authConfig.audience,
87
- }),
88
- );
89
- return null;
90
- }
91
- }
92
-
93
- async function verifySessionToken(
94
- token: string,
95
- config: AuthConfig,
96
- ): Promise<SessionTokenPayload> {
97
- const { issuer, audience } = config;
98
-
99
- if (!issuer) {
100
- throw new Error("Issuer must be provided for token verification");
101
- }
102
-
103
- if (!audience) {
104
- throw new Error("Audience must be provided for token verification");
105
- }
106
-
107
- // Fetch JWKS - use service binding in production, direct fetch in development
108
- const jwksResponse =
109
- import.meta.env.PROD && env.EVERY_APP_GATEWAY
110
- ? await env.EVERY_APP_GATEWAY.fetch("http://localhost/api/embedded/jwks")
111
- : await fetch(`${env.GATEWAY_URL}/api/embedded/jwks`);
112
-
113
- if (!jwksResponse.ok) {
114
- throw new Error(
115
- `Failed to fetch JWKS: ${jwksResponse.status} ${jwksResponse.statusText}`,
116
- );
117
- }
118
-
119
- const jwks = (await jwksResponse.json()) as JSONWebKeySet;
120
- const localJWKS = createLocalJWKSet(jwks);
121
-
122
- const options: JWTVerifyOptions = {
123
- issuer,
124
- audience,
125
- algorithms: ["RS256"],
126
- };
127
-
128
- const { payload } = await jwtVerify(token, localJWKS, options);
129
- return payload as SessionTokenPayload;
130
- }
131
-
132
- /**
133
- * Extracts the bearer token from an Authorization header.
134
- *
135
- * @param authHeader - The Authorization header value (e.g., "Bearer eyJ...")
136
- * @returns The token string if valid, null otherwise
137
- */
138
- export function extractBearerToken(authHeader: string | null): string | null {
139
- if (!authHeader || !authHeader.startsWith("Bearer ")) {
140
- return null;
141
- }
142
- return authHeader.substring(7);
143
- }
@@ -1,3 +0,0 @@
1
- export { authenticateRequest } from "./authenticateRequest.js";
2
- export type { AuthConfig } from "./types.js";
3
- export { getAuthConfig } from "./authConfig.js";
@@ -1,4 +0,0 @@
1
- export interface AuthConfig {
2
- issuer: string;
3
- audience: string;
4
- }