@blimu/backend 1.2.1 → 1.2.4

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 (46) hide show
  1. package/README.md +10 -0
  2. package/dist/client.cjs +43 -0
  3. package/dist/client.cjs.map +1 -1
  4. package/dist/client.d.mts +3 -1
  5. package/dist/client.d.ts +3 -1
  6. package/dist/client.mjs +43 -0
  7. package/dist/client.mjs.map +1 -1
  8. package/dist/index.cjs +111 -92
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.mts +41 -18
  11. package/dist/index.d.ts +41 -18
  12. package/dist/index.mjs +109 -92
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/{schema-CGYqiv8k.d.mts → schema-DlLjJUTG.d.mts} +27 -2
  15. package/dist/{schema-CGYqiv8k.d.ts → schema-DlLjJUTG.d.ts} +27 -2
  16. package/dist/schema.cjs.map +1 -1
  17. package/dist/schema.d.mts +1 -1
  18. package/dist/schema.d.ts +1 -1
  19. package/dist/services/auth_jwks.cjs +69 -0
  20. package/dist/services/auth_jwks.cjs.map +1 -0
  21. package/dist/services/auth_jwks.d.mts +13 -0
  22. package/dist/services/auth_jwks.d.ts +13 -0
  23. package/dist/services/auth_jwks.mjs +44 -0
  24. package/dist/services/auth_jwks.mjs.map +1 -0
  25. package/dist/services/bulk_resources.d.mts +1 -1
  26. package/dist/services/bulk_resources.d.ts +1 -1
  27. package/dist/services/bulk_roles.d.mts +1 -1
  28. package/dist/services/bulk_roles.d.ts +1 -1
  29. package/dist/services/entitlements.d.mts +1 -1
  30. package/dist/services/entitlements.d.ts +1 -1
  31. package/dist/services/oauth.d.mts +1 -1
  32. package/dist/services/oauth.d.ts +1 -1
  33. package/dist/services/plans.d.mts +1 -1
  34. package/dist/services/plans.d.ts +1 -1
  35. package/dist/services/resource_members.d.mts +1 -1
  36. package/dist/services/resource_members.d.ts +1 -1
  37. package/dist/services/resources.d.mts +1 -1
  38. package/dist/services/resources.d.ts +1 -1
  39. package/dist/services/roles.d.mts +1 -1
  40. package/dist/services/roles.d.ts +1 -1
  41. package/dist/services/usage.d.mts +1 -1
  42. package/dist/services/usage.d.ts +1 -1
  43. package/dist/services/users.d.mts +1 -1
  44. package/dist/services/users.d.ts +1 -1
  45. package/dist/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var index_exports = {};
33
33
  __export(index_exports, {
34
+ AuthJwksService: () => AuthJwksService,
34
35
  Blimu: () => Blimu,
35
36
  BlimuError: () => BlimuError,
36
37
  BulkResourcesService: () => BulkResourcesService,
@@ -51,6 +52,7 @@ __export(index_exports, {
51
52
  paginate: () => paginate,
52
53
  parseNDJSONStream: () => import_fetch3.parseNDJSONStream,
53
54
  parseSSEStream: () => import_fetch3.parseSSEStream,
55
+ verifyOAuthToken: () => verifyOAuthToken,
54
56
  verifyToken: () => verifyToken
55
57
  });
56
58
  module.exports = __toCommonJS(index_exports);
@@ -73,6 +75,47 @@ function buildAuthStrategies(cfg) {
73
75
  return authStrategies;
74
76
  }
75
77
 
78
+ // src/services/auth_jwks.ts
79
+ var AuthJwksService = class {
80
+ constructor(core) {
81
+ this.core = core;
82
+ }
83
+ /**
84
+ * GET /v1/auth/.well-known/jwks.json*
85
+ * @summary Get JSON Web Key Set for environment (Public)*
86
+ * @description Returns the public keys used to verify JWT tokens issued by this environment. Authenticate using either x-api-key header (secretKey) or x-blimu-publishable-key header (publishableKey).*/
87
+ getJwks(init) {
88
+ return this.core.request({
89
+ method: "GET",
90
+ path: `/v1/auth/.well-known/jwks.json`,
91
+ ...init ?? {}
92
+ });
93
+ }
94
+ /**
95
+ * GET /v1/auth/.well-known/public-key.pem*
96
+ * @summary Get environment public key (PEM)*
97
+ * @description Returns the public key in PEM format for verifying JWT tokens. Authenticate with x-api-key or x-blimu-publishable-key.*/
98
+ getPublicKeyPem(init) {
99
+ return this.core.request({
100
+ method: "GET",
101
+ path: `/v1/auth/.well-known/public-key.pem`,
102
+ ...init ?? {}
103
+ });
104
+ }
105
+ /**
106
+ * GET /v1/auth/oauth/.well-known/jwks.json*
107
+ * @summary Get JSON Web Key Set for OAuth app (Public)*
108
+ * @description Returns the public key for a specific OAuth app to verify JWT tokens. This is a public endpoint following OAuth2/OIDC standards. Provide client_id to get keys for a specific OAuth app, or use authenticated endpoint for environment keys.*/
109
+ getOAuthAppJwks(query, init) {
110
+ return this.core.request({
111
+ method: "GET",
112
+ path: `/v1/auth/oauth/.well-known/jwks.json`,
113
+ query,
114
+ ...init ?? {}
115
+ });
116
+ }
117
+ };
118
+
76
119
  // src/services/bulk_resources.ts
77
120
  var BulkResourcesService = class {
78
121
  constructor(core) {
@@ -580,6 +623,7 @@ var UsersService = class {
580
623
 
581
624
  // src/client.ts
582
625
  var Blimu = class {
626
+ authJwks;
583
627
  bulkResources;
584
628
  bulkRoles;
585
629
  entitlements;
@@ -599,6 +643,7 @@ var Blimu = class {
599
643
  baseURL: options?.baseURL ?? "https://api.blimu.dev",
600
644
  ...authStrategies.length > 0 ? { authStrategies } : {}
601
645
  });
646
+ this.authJwks = new AuthJwksService(core);
602
647
  this.bulkResources = new BulkResourcesService(core);
603
648
  this.bulkRoles = new BulkRolesService(core);
604
649
  this.entitlements = new EntitlementsService(core);
@@ -649,6 +694,7 @@ var schema_exports = {};
649
694
  // src/schema.zod.ts
650
695
  var schema_zod_exports = {};
651
696
  __export(schema_zod_exports, {
697
+ AuthJwksGetOAuthAppJwksQuerySchema: () => AuthJwksGetOAuthAppJwksQuerySchema,
652
698
  AuthorizeRequestSchema: () => AuthorizeRequestSchema,
653
699
  BalanceResponseSchema: () => BalanceResponseSchema,
654
700
  CheckLimitResponseSchema: () => CheckLimitResponseSchema,
@@ -667,6 +713,8 @@ __export(schema_zod_exports, {
667
713
  EntitlementsListResultSchema: () => EntitlementsListResultSchema,
668
714
  IntrospectionRequestSchema: () => IntrospectionRequestSchema,
669
715
  IntrospectionResponseSchema: () => IntrospectionResponseSchema,
716
+ JWKSchema: () => JWKSchema,
717
+ OAuthAccessTokenPayloadSchema: () => OAuthAccessTokenPayloadSchema,
670
718
  OauthCheckConsentRequiredQuerySchema: () => OauthCheckConsentRequiredQuerySchema,
671
719
  PlanAssignBodySchema: () => PlanAssignBodySchema,
672
720
  PlanDeleteResponseSchema: () => PlanDeleteResponseSchema,
@@ -832,6 +880,25 @@ var IntrospectionResponseSchema = import_zod.z.object({
832
880
  /** Username or user ID */
833
881
  username: import_zod.z.string().optional()
834
882
  });
883
+ var JWKSchema = import_zod.z.object({
884
+ keys: import_zod.z.object({
885
+ alg: import_zod.z.string(),
886
+ e: import_zod.z.string(),
887
+ kid: import_zod.z.string(),
888
+ kty: import_zod.z.string(),
889
+ n: import_zod.z.string(),
890
+ use: import_zod.z.string()
891
+ }).array()
892
+ });
893
+ var OAuthAccessTokenPayloadSchema = import_zod.z.object({
894
+ client_id: import_zod.z.string(),
895
+ environment_id: import_zod.z.string(),
896
+ exp: import_zod.z.number().int(),
897
+ iat: import_zod.z.number().int(),
898
+ scope: import_zod.z.string(),
899
+ sub: import_zod.z.string(),
900
+ token_type: import_zod.z.string()
901
+ });
835
902
  var PlanDeleteResponseSchema = import_zod.z.object({ success: import_zod.z.boolean() });
836
903
  var ResourceMemberListSchema = import_zod.z.object({
837
904
  items: import_zod.z.object({
@@ -1189,6 +1256,10 @@ var ResourceListSchema = import_zod.z.object({
1189
1256
  page: import_zod.z.number(),
1190
1257
  total: import_zod.z.number()
1191
1258
  });
1259
+ var AuthJwksGetOAuthAppJwksQuerySchema = import_zod.z.object({
1260
+ /** OAuth app client ID to get public keys for */
1261
+ client_id: import_zod.z.string().optional()
1262
+ });
1192
1263
  var EntitlementsListForResourceQuerySchema = import_zod.z.object({
1193
1264
  /** The unique identifier of the user */
1194
1265
  userId: import_zod.z.string()
@@ -1257,40 +1328,14 @@ var UsersListQuerySchema = import_zod.z.object({
1257
1328
  // src/token-verifier.ts
1258
1329
  var crypto = __toESM(require("crypto"));
1259
1330
  var jwt = __toESM(require("jsonwebtoken"));
1331
+ var import_fetch4 = require("@blimu/fetch");
1260
1332
  var TokenVerifier = class {
1261
1333
  cache = /* @__PURE__ */ new Map();
1262
1334
  cacheTTL;
1263
- runtimeApiUrl;
1335
+ baseURL;
1264
1336
  constructor(options) {
1265
1337
  this.cacheTTL = options?.cacheTTL ?? 60 * 60 * 1e3;
1266
- this.runtimeApiUrl = options?.runtimeApiUrl ?? "https://api.blimu.dev";
1267
- }
1268
- /**
1269
- * Fetch JWK Set from runtime-api
1270
- */
1271
- async fetchJWKSet(endpoint, headers) {
1272
- console.log(`[TokenVerifier] \u{1F4E1} Fetching JWK Set from: ${endpoint}`);
1273
- if (headers) {
1274
- console.log(
1275
- `[TokenVerifier] \u{1F4E1} Request headers: ${JSON.stringify(Object.keys(headers).map((k) => `${k}: ${k === "x-api-key" ? "***" : headers[k]}`))}`
1276
- );
1277
- }
1278
- const response = await fetch(endpoint, {
1279
- method: "GET",
1280
- headers: {
1281
- "Content-Type": "application/json",
1282
- ...headers
1283
- }
1284
- });
1285
- console.log(`[TokenVerifier] \u{1F4E1} Response status: ${response.status} ${response.statusText}`);
1286
- if (!response.ok) {
1287
- const errorText = await response.text();
1288
- console.error(`[TokenVerifier] \u274C Failed to fetch JWKs: ${response.status} ${errorText}`);
1289
- throw new import_fetch.FetchError("Failed to fetch JWKs", response.status, errorText);
1290
- }
1291
- const jwkSet = await response.json();
1292
- console.log(`[TokenVerifier] \u2705 Successfully fetched JWK Set with ${jwkSet.keys.length} keys`);
1293
- return jwkSet;
1338
+ this.baseURL = options?.runtimeApiUrl ?? "https://api.blimu.dev";
1294
1339
  }
1295
1340
  /**
1296
1341
  * Convert JWK to KeyObject
@@ -1309,25 +1354,19 @@ var TokenVerifier = class {
1309
1354
  /**
1310
1355
  * Get public key for a specific key ID
1311
1356
  */
1312
- async getPublicKey(kid, cacheKey, endpoint, headers) {
1357
+ async getPublicKey(kid, cacheKey, fetchJwks) {
1313
1358
  const cached = this.cache.get(cacheKey);
1314
1359
  if (cached && cached.expiresAt > Date.now()) {
1315
- console.log(`[TokenVerifier] \u2705 Using cached key for kid: ${kid}`);
1316
1360
  return cached.key;
1317
1361
  }
1318
- console.log(`[TokenVerifier] \u{1F50D} Cache miss or expired. Fetching new key for kid: ${kid}`);
1319
- const jwkSet = await this.fetchJWKSet(endpoint, headers);
1362
+ const jwkSet = await fetchJwks();
1320
1363
  const jwk = jwkSet.keys.find((k) => k.kid === kid);
1321
1364
  if (!jwk) {
1322
1365
  const availableKids = jwkSet.keys.map((k) => k.kid).join(", ");
1323
- console.error(
1324
- `[TokenVerifier] \u274C Key with kid '${kid}' not found in JWK Set. Available kids: ${availableKids}`
1325
- );
1326
1366
  throw new Error(
1327
1367
  `Key with kid '${kid}' not found in JWK Set. Available kids: ${availableKids}`
1328
1368
  );
1329
1369
  }
1330
- console.log(`[TokenVerifier] \u2705 Found key with kid: ${kid}`);
1331
1370
  const keyObject = this.jwkToKeyObject(jwk);
1332
1371
  this.cache.set(cacheKey, {
1333
1372
  key: keyObject,
@@ -1337,15 +1376,16 @@ var TokenVerifier = class {
1337
1376
  return keyObject;
1338
1377
  }
1339
1378
  /**
1340
- * Verify JWT token using JWKs from runtime-api
1379
+ * Verify JWT token using JWKs from Blimu runtime API.
1380
+ * Supports: environment/session tokens (secretKey) or OAuth app tokens (clientId).
1341
1381
  */
1342
1382
  async verifyToken(options) {
1343
- const { url, secretKey, token, runtimeApiUrl } = options;
1344
- if (!url && !secretKey) {
1345
- throw new Error("Either url or secretKey must be provided");
1346
- }
1347
- if (url && secretKey) {
1348
- throw new Error("Cannot provide both url and secretKey");
1383
+ const { secretKey, clientId, token, runtimeApiUrl } = options;
1384
+ const provided = [secretKey, clientId].filter(Boolean);
1385
+ if (provided.length !== 1) {
1386
+ throw new Error(
1387
+ "Exactly one of secretKey or clientId must be provided. Use secretKey for environment/session tokens, clientId for OAuth app access tokens."
1388
+ );
1349
1389
  }
1350
1390
  const decoded = jwt.decode(token, { complete: true });
1351
1391
  if (!decoded || typeof decoded === "string") {
@@ -1355,67 +1395,38 @@ var TokenVerifier = class {
1355
1395
  if (!header.kid) {
1356
1396
  throw new Error("Token missing kid in header");
1357
1397
  }
1358
- let endpoint;
1398
+ const baseURL = runtimeApiUrl ?? this.baseURL;
1359
1399
  let cacheKey;
1360
- let headers;
1400
+ let fetchJwks;
1361
1401
  if (secretKey) {
1362
- const apiUrl = runtimeApiUrl ?? this.runtimeApiUrl;
1363
- endpoint = `${apiUrl}/v1/auth/.well-known/jwks.json`;
1364
1402
  cacheKey = secretKey;
1365
- headers = {
1366
- "x-api-key": secretKey
1367
- };
1368
- console.log(
1369
- `[TokenVerifier] \u{1F50D} Verifying token with kid: ${header.kid}, endpoint: ${endpoint}`
1370
- );
1403
+ const core = new import_fetch4.FetchClient({
1404
+ baseURL,
1405
+ authStrategies: buildAuthStrategies({ apiKey: secretKey, baseURL })
1406
+ });
1407
+ const authJwks = new AuthJwksService(core);
1408
+ fetchJwks = () => authJwks.getJwks();
1371
1409
  } else {
1372
- endpoint = url;
1373
- cacheKey = url;
1374
- console.log(
1375
- `[TokenVerifier] \u{1F50D} Verifying token with kid: ${header.kid}, endpoint: ${endpoint}`
1376
- );
1410
+ cacheKey = `oauth:${baseURL}:${clientId}`;
1411
+ const core = new import_fetch4.FetchClient({ baseURL });
1412
+ const authJwks = new AuthJwksService(core);
1413
+ fetchJwks = () => authJwks.getOAuthAppJwks({ client_id: clientId });
1377
1414
  }
1378
1415
  let publicKey;
1379
1416
  try {
1380
- publicKey = await this.getPublicKey(header.kid, cacheKey, endpoint, headers);
1381
- console.log(`[TokenVerifier] \u2705 Successfully retrieved public key for kid: ${header.kid}`);
1382
- } catch (error) {
1383
- console.error(
1384
- `[TokenVerifier] \u274C Failed to get public key (first attempt): ${error instanceof Error ? error.message : String(error)}`
1385
- );
1417
+ publicKey = await this.getPublicKey(header.kid, cacheKey, fetchJwks);
1418
+ } catch {
1386
1419
  this.clearCache(cacheKey);
1387
- console.log(`[TokenVerifier] \u{1F504} Retrying after cache clear...`);
1388
- try {
1389
- publicKey = await this.getPublicKey(header.kid, cacheKey, endpoint, headers);
1390
- console.log(
1391
- `[TokenVerifier] \u2705 Successfully retrieved public key for kid: ${header.kid} (retry)`
1392
- );
1393
- } catch (retryError) {
1394
- console.error(
1395
- `[TokenVerifier] \u274C Failed to get public key (retry): ${retryError instanceof Error ? retryError.message : String(retryError)}`
1396
- );
1397
- throw retryError;
1398
- }
1399
- }
1400
- try {
1401
- const payload = jwt.verify(token, publicKey, {
1402
- algorithms: ["RS256"]
1403
- });
1404
- console.log(`[TokenVerifier] \u2705 Token verified successfully`);
1405
- return payload;
1406
- } catch (error) {
1407
- console.error(
1408
- `[TokenVerifier] \u274C JWT verification failed: ${error instanceof Error ? error.message : String(error)}`
1409
- );
1410
- throw error;
1420
+ publicKey = await this.getPublicKey(header.kid, cacheKey, fetchJwks);
1411
1421
  }
1422
+ return jwt.verify(token, publicKey, { algorithms: ["RS256"] });
1412
1423
  }
1413
1424
  /**
1414
1425
  * Clear cache (useful for testing or key rotation)
1415
1426
  */
1416
- clearCache(secretKeyOrUrl) {
1417
- if (secretKeyOrUrl) {
1418
- this.cache.delete(secretKeyOrUrl);
1427
+ clearCache(cacheKey) {
1428
+ if (cacheKey) {
1429
+ this.cache.delete(cacheKey);
1419
1430
  } else {
1420
1431
  this.cache.clear();
1421
1432
  }
@@ -1425,8 +1436,15 @@ async function verifyToken(options) {
1425
1436
  const verifier = new TokenVerifier();
1426
1437
  return verifier.verifyToken(options);
1427
1438
  }
1439
+ async function verifyOAuthToken(options) {
1440
+ return verifyToken({
1441
+ ...options,
1442
+ clientId: options.clientId
1443
+ });
1444
+ }
1428
1445
  // Annotate the CommonJS export names for ESM import in node:
1429
1446
  0 && (module.exports = {
1447
+ AuthJwksService,
1430
1448
  Blimu,
1431
1449
  BlimuError,
1432
1450
  BulkResourcesService,
@@ -1447,6 +1465,7 @@ async function verifyToken(options) {
1447
1465
  paginate,
1448
1466
  parseNDJSONStream,
1449
1467
  parseSSEStream,
1468
+ verifyOAuthToken,
1450
1469
  verifyToken,
1451
1470
  ...require("@blimu/fetch")
1452
1471
  });