@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.
- package/README.md +9 -0
- package/dist/client.cjs +43 -0
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.mts +3 -1
- package/dist/client.d.ts +3 -1
- package/dist/client.mjs +43 -0
- package/dist/client.mjs.map +1 -1
- package/dist/index.cjs +101 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +31 -18
- package/dist/index.d.ts +31 -18
- package/dist/index.mjs +99 -92
- package/dist/index.mjs.map +1 -1
- package/dist/{schema-CGYqiv8k.d.mts → schema-CdEZKE7E.d.mts} +17 -2
- package/dist/{schema-CGYqiv8k.d.ts → schema-CdEZKE7E.d.ts} +17 -2
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.mts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/services/auth_jwks.cjs +69 -0
- package/dist/services/auth_jwks.cjs.map +1 -0
- package/dist/services/auth_jwks.d.mts +13 -0
- package/dist/services/auth_jwks.d.ts +13 -0
- package/dist/services/auth_jwks.mjs +44 -0
- package/dist/services/auth_jwks.mjs.map +1 -0
- package/dist/services/bulk_resources.d.mts +1 -1
- package/dist/services/bulk_resources.d.ts +1 -1
- package/dist/services/bulk_roles.d.mts +1 -1
- package/dist/services/bulk_roles.d.ts +1 -1
- package/dist/services/entitlements.d.mts +1 -1
- package/dist/services/entitlements.d.ts +1 -1
- package/dist/services/oauth.d.mts +1 -1
- package/dist/services/oauth.d.ts +1 -1
- package/dist/services/plans.d.mts +1 -1
- package/dist/services/plans.d.ts +1 -1
- package/dist/services/resource_members.d.mts +1 -1
- package/dist/services/resource_members.d.ts +1 -1
- package/dist/services/resources.d.mts +1 -1
- package/dist/services/resources.d.ts +1 -1
- package/dist/services/roles.d.mts +1 -1
- package/dist/services/roles.d.ts +1 -1
- package/dist/services/usage.d.mts +1 -1
- package/dist/services/usage.d.ts +1 -1
- package/dist/services/users.d.mts +1 -1
- package/dist/services/users.d.ts +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- 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
|
-
|
|
1325
|
+
baseURL;
|
|
1264
1326
|
constructor(options) {
|
|
1265
1327
|
this.cacheTTL = options?.cacheTTL ?? 60 * 60 * 1e3;
|
|
1266
|
-
this.
|
|
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,
|
|
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
|
-
|
|
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
|
|
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 {
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
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
|
-
|
|
1388
|
+
const baseURL = runtimeApiUrl ?? this.baseURL;
|
|
1359
1389
|
let cacheKey;
|
|
1360
|
-
let
|
|
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
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
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
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
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,
|
|
1381
|
-
|
|
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
|
-
|
|
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(
|
|
1417
|
-
if (
|
|
1418
|
-
this.cache.delete(
|
|
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
|
});
|