@blimu/backend 1.2.1 → 1.2.2

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 +9 -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 +101 -92
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.mts +31 -18
  11. package/dist/index.d.ts +31 -18
  12. package/dist/index.mjs +99 -92
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/{schema-CGYqiv8k.d.mts → schema-CdEZKE7E.d.mts} +17 -2
  15. package/dist/{schema-CGYqiv8k.d.ts → schema-CdEZKE7E.d.ts} +17 -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,7 @@ __export(schema_zod_exports, {
667
713
  EntitlementsListResultSchema: () => EntitlementsListResultSchema,
668
714
  IntrospectionRequestSchema: () => IntrospectionRequestSchema,
669
715
  IntrospectionResponseSchema: () => IntrospectionResponseSchema,
716
+ JWKSchema: () => JWKSchema,
670
717
  OauthCheckConsentRequiredQuerySchema: () => OauthCheckConsentRequiredQuerySchema,
671
718
  PlanAssignBodySchema: () => PlanAssignBodySchema,
672
719
  PlanDeleteResponseSchema: () => PlanDeleteResponseSchema,
@@ -832,6 +879,16 @@ var IntrospectionResponseSchema = import_zod.z.object({
832
879
  /** Username or user ID */
833
880
  username: import_zod.z.string().optional()
834
881
  });
882
+ var JWKSchema = import_zod.z.object({
883
+ keys: import_zod.z.object({
884
+ alg: import_zod.z.string(),
885
+ e: import_zod.z.string(),
886
+ kid: import_zod.z.string(),
887
+ kty: import_zod.z.string(),
888
+ n: import_zod.z.string(),
889
+ use: import_zod.z.string()
890
+ }).array()
891
+ });
835
892
  var PlanDeleteResponseSchema = import_zod.z.object({ success: import_zod.z.boolean() });
836
893
  var ResourceMemberListSchema = import_zod.z.object({
837
894
  items: import_zod.z.object({
@@ -1189,6 +1246,10 @@ var ResourceListSchema = import_zod.z.object({
1189
1246
  page: import_zod.z.number(),
1190
1247
  total: import_zod.z.number()
1191
1248
  });
1249
+ var AuthJwksGetOAuthAppJwksQuerySchema = import_zod.z.object({
1250
+ /** OAuth app client ID to get public keys for */
1251
+ client_id: import_zod.z.string().optional()
1252
+ });
1192
1253
  var EntitlementsListForResourceQuerySchema = import_zod.z.object({
1193
1254
  /** The unique identifier of the user */
1194
1255
  userId: import_zod.z.string()
@@ -1257,40 +1318,14 @@ var UsersListQuerySchema = import_zod.z.object({
1257
1318
  // src/token-verifier.ts
1258
1319
  var crypto = __toESM(require("crypto"));
1259
1320
  var jwt = __toESM(require("jsonwebtoken"));
1321
+ var import_fetch4 = require("@blimu/fetch");
1260
1322
  var TokenVerifier = class {
1261
1323
  cache = /* @__PURE__ */ new Map();
1262
1324
  cacheTTL;
1263
- runtimeApiUrl;
1325
+ baseURL;
1264
1326
  constructor(options) {
1265
1327
  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;
1328
+ this.baseURL = options?.runtimeApiUrl ?? "https://api.blimu.dev";
1294
1329
  }
1295
1330
  /**
1296
1331
  * Convert JWK to KeyObject
@@ -1309,25 +1344,19 @@ var TokenVerifier = class {
1309
1344
  /**
1310
1345
  * Get public key for a specific key ID
1311
1346
  */
1312
- async getPublicKey(kid, cacheKey, endpoint, headers) {
1347
+ async getPublicKey(kid, cacheKey, fetchJwks) {
1313
1348
  const cached = this.cache.get(cacheKey);
1314
1349
  if (cached && cached.expiresAt > Date.now()) {
1315
- console.log(`[TokenVerifier] \u2705 Using cached key for kid: ${kid}`);
1316
1350
  return cached.key;
1317
1351
  }
1318
- console.log(`[TokenVerifier] \u{1F50D} Cache miss or expired. Fetching new key for kid: ${kid}`);
1319
- const jwkSet = await this.fetchJWKSet(endpoint, headers);
1352
+ const jwkSet = await fetchJwks();
1320
1353
  const jwk = jwkSet.keys.find((k) => k.kid === kid);
1321
1354
  if (!jwk) {
1322
1355
  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
1356
  throw new Error(
1327
1357
  `Key with kid '${kid}' not found in JWK Set. Available kids: ${availableKids}`
1328
1358
  );
1329
1359
  }
1330
- console.log(`[TokenVerifier] \u2705 Found key with kid: ${kid}`);
1331
1360
  const keyObject = this.jwkToKeyObject(jwk);
1332
1361
  this.cache.set(cacheKey, {
1333
1362
  key: keyObject,
@@ -1337,15 +1366,16 @@ var TokenVerifier = class {
1337
1366
  return keyObject;
1338
1367
  }
1339
1368
  /**
1340
- * Verify JWT token using JWKs from runtime-api
1369
+ * Verify JWT token using JWKs from Blimu runtime API.
1370
+ * Supports: environment/session tokens (secretKey) or OAuth app tokens (clientId).
1341
1371
  */
1342
1372
  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");
1373
+ const { secretKey, clientId, token, runtimeApiUrl } = options;
1374
+ const provided = [secretKey, clientId].filter(Boolean);
1375
+ if (provided.length !== 1) {
1376
+ throw new Error(
1377
+ "Exactly one of secretKey or clientId must be provided. Use secretKey for environment/session tokens, clientId for OAuth app access tokens."
1378
+ );
1349
1379
  }
1350
1380
  const decoded = jwt.decode(token, { complete: true });
1351
1381
  if (!decoded || typeof decoded === "string") {
@@ -1355,67 +1385,38 @@ var TokenVerifier = class {
1355
1385
  if (!header.kid) {
1356
1386
  throw new Error("Token missing kid in header");
1357
1387
  }
1358
- let endpoint;
1388
+ const baseURL = runtimeApiUrl ?? this.baseURL;
1359
1389
  let cacheKey;
1360
- let headers;
1390
+ let fetchJwks;
1361
1391
  if (secretKey) {
1362
- const apiUrl = runtimeApiUrl ?? this.runtimeApiUrl;
1363
- endpoint = `${apiUrl}/v1/auth/.well-known/jwks.json`;
1364
1392
  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
- );
1393
+ const core = new import_fetch4.FetchClient({
1394
+ baseURL,
1395
+ authStrategies: buildAuthStrategies({ apiKey: secretKey, baseURL })
1396
+ });
1397
+ const authJwks = new AuthJwksService(core);
1398
+ fetchJwks = () => authJwks.getJwks();
1371
1399
  } else {
1372
- endpoint = url;
1373
- cacheKey = url;
1374
- console.log(
1375
- `[TokenVerifier] \u{1F50D} Verifying token with kid: ${header.kid}, endpoint: ${endpoint}`
1376
- );
1400
+ cacheKey = `oauth:${clientId}`;
1401
+ const core = new import_fetch4.FetchClient({ baseURL });
1402
+ const authJwks = new AuthJwksService(core);
1403
+ fetchJwks = () => authJwks.getOAuthAppJwks({ client_id: clientId });
1377
1404
  }
1378
1405
  let publicKey;
1379
1406
  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
- );
1407
+ publicKey = await this.getPublicKey(header.kid, cacheKey, fetchJwks);
1408
+ } catch {
1386
1409
  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;
1410
+ publicKey = await this.getPublicKey(header.kid, cacheKey, fetchJwks);
1411
1411
  }
1412
+ return jwt.verify(token, publicKey, { algorithms: ["RS256"] });
1412
1413
  }
1413
1414
  /**
1414
1415
  * Clear cache (useful for testing or key rotation)
1415
1416
  */
1416
- clearCache(secretKeyOrUrl) {
1417
- if (secretKeyOrUrl) {
1418
- this.cache.delete(secretKeyOrUrl);
1417
+ clearCache(cacheKey) {
1418
+ if (cacheKey) {
1419
+ this.cache.delete(cacheKey);
1419
1420
  } else {
1420
1421
  this.cache.clear();
1421
1422
  }
@@ -1425,8 +1426,15 @@ async function verifyToken(options) {
1425
1426
  const verifier = new TokenVerifier();
1426
1427
  return verifier.verifyToken(options);
1427
1428
  }
1429
+ async function verifyOAuthToken(options) {
1430
+ return verifyToken({
1431
+ ...options,
1432
+ clientId: options.clientId
1433
+ });
1434
+ }
1428
1435
  // Annotate the CommonJS export names for ESM import in node:
1429
1436
  0 && (module.exports = {
1437
+ AuthJwksService,
1430
1438
  Blimu,
1431
1439
  BlimuError,
1432
1440
  BulkResourcesService,
@@ -1447,6 +1455,7 @@ async function verifyToken(options) {
1447
1455
  paginate,
1448
1456
  parseNDJSONStream,
1449
1457
  parseSSEStream,
1458
+ verifyOAuthToken,
1450
1459
  verifyToken,
1451
1460
  ...require("@blimu/fetch")
1452
1461
  });