@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.
- package/README.md +10 -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 +111 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +41 -18
- package/dist/index.d.ts +41 -18
- package/dist/index.mjs +109 -92
- package/dist/index.mjs.map +1 -1
- package/dist/{schema-CGYqiv8k.d.mts → schema-DlLjJUTG.d.mts} +27 -2
- package/dist/{schema-CGYqiv8k.d.ts → schema-DlLjJUTG.d.ts} +27 -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,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
|
-
|
|
1335
|
+
baseURL;
|
|
1264
1336
|
constructor(options) {
|
|
1265
1337
|
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;
|
|
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,
|
|
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
|
-
|
|
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
|
|
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 {
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
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
|
-
|
|
1398
|
+
const baseURL = runtimeApiUrl ?? this.baseURL;
|
|
1359
1399
|
let cacheKey;
|
|
1360
|
-
let
|
|
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
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
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
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
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,
|
|
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
|
-
);
|
|
1417
|
+
publicKey = await this.getPublicKey(header.kid, cacheKey, fetchJwks);
|
|
1418
|
+
} catch {
|
|
1386
1419
|
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;
|
|
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(
|
|
1417
|
-
if (
|
|
1418
|
-
this.cache.delete(
|
|
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
|
});
|