@jeffjassky/oauth-host 0.2.0 → 0.3.0
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/dist/index.cjs +46 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +46 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/types/index.d.ts +60 -6
package/dist/index.cjs
CHANGED
|
@@ -29,9 +29,11 @@ function clientSchema() {
|
|
|
29
29
|
{
|
|
30
30
|
clientId: { type: String, required: true, unique: true },
|
|
31
31
|
name: { type: String, required: true },
|
|
32
|
-
// `public`
|
|
33
|
-
//
|
|
34
|
-
//
|
|
32
|
+
// `public` is a client that holds no secret and is bound by PKCE instead.
|
|
33
|
+
// Two ways in and they are independent: a CIMD row is written public, and
|
|
34
|
+
// `clients.create({ type: 'public' })` registers one by hand. The enum was
|
|
35
|
+
// written with this widening in mind, so it was one member rather than a
|
|
36
|
+
// migration.
|
|
35
37
|
type: { type: String, enum: ["confidential", "public"], default: "confidential" },
|
|
36
38
|
// How the row got here. A `cimd` row is re-derived from the client's own
|
|
37
39
|
// metadata document, so this is what tells the re-fetch path which fields
|
|
@@ -1364,6 +1366,15 @@ function assertResources(ctx, input) {
|
|
|
1364
1366
|
}
|
|
1365
1367
|
return [...input];
|
|
1366
1368
|
}
|
|
1369
|
+
function assertClientType(value) {
|
|
1370
|
+
if (value === void 0) return "confidential";
|
|
1371
|
+
if (value !== "confidential" && value !== "public") {
|
|
1372
|
+
throw new TypeError(
|
|
1373
|
+
`oauth-host: client type must be 'confidential' or 'public' (got ${JSON.stringify(value)})`
|
|
1374
|
+
);
|
|
1375
|
+
}
|
|
1376
|
+
return value;
|
|
1377
|
+
}
|
|
1367
1378
|
function assertName(value) {
|
|
1368
1379
|
if (typeof value !== "string" || !value.trim()) {
|
|
1369
1380
|
throw new TypeError("oauth-host: a client needs a non-empty `name` \u2014 it is what the consent screen shows");
|
|
@@ -1385,35 +1396,38 @@ async function revokeTokensMatching(ctx, filter) {
|
|
|
1385
1396
|
return res.modifiedCount ?? 0;
|
|
1386
1397
|
}
|
|
1387
1398
|
function createClientsApi(ctx) {
|
|
1399
|
+
async function create(spec) {
|
|
1400
|
+
if (!spec || typeof spec !== "object") {
|
|
1401
|
+
throw new TypeError("oauth-host: clients.create(spec) requires a spec object");
|
|
1402
|
+
}
|
|
1403
|
+
const name = assertName(spec.name);
|
|
1404
|
+
const type = assertClientType(spec.type);
|
|
1405
|
+
const redirectUris = assertRedirectUris(spec.redirectUris);
|
|
1406
|
+
const allowedScopes = assertScopes(ctx, spec.allowedScopes);
|
|
1407
|
+
const allowedResources = assertResources(ctx, spec.allowedResources);
|
|
1408
|
+
const clientId = spec.clientId ?? generateClientId();
|
|
1409
|
+
const clientSecret = type === "confidential" ? generateClientSecret() : void 0;
|
|
1410
|
+
const doc = await ctx.models.Client.create({
|
|
1411
|
+
clientId,
|
|
1412
|
+
name,
|
|
1413
|
+
type,
|
|
1414
|
+
registration: "manual",
|
|
1415
|
+
trusted: Boolean(spec.trusted),
|
|
1416
|
+
// Only the digest is stored. `clientSecret` below is the only time the
|
|
1417
|
+
// raw value exists outside the caller's variable. Empty for a public
|
|
1418
|
+
// client, which is the same shape a CIMD row is written with.
|
|
1419
|
+
secrets: clientSecret ? [{ hash: sha256(clientSecret), label: "initial", createdAt: /* @__PURE__ */ new Date() }] : [],
|
|
1420
|
+
redirectUris,
|
|
1421
|
+
allowedScopes,
|
|
1422
|
+
allowedResources,
|
|
1423
|
+
branding: spec.branding ?? {},
|
|
1424
|
+
status: "active"
|
|
1425
|
+
});
|
|
1426
|
+
await ctx.audit({ type: "oauth.client_created", actor: "admin", clientId, meta: { type } });
|
|
1427
|
+
return clientSecret ? { client: toPublicClient(doc), clientId, type: "confidential", clientSecret } : { client: toPublicClient(doc), clientId, type: "public" };
|
|
1428
|
+
}
|
|
1388
1429
|
return {
|
|
1389
|
-
|
|
1390
|
-
if (!spec || typeof spec !== "object") {
|
|
1391
|
-
throw new TypeError("oauth-host: clients.create(spec) requires a spec object");
|
|
1392
|
-
}
|
|
1393
|
-
const name = assertName(spec.name);
|
|
1394
|
-
const redirectUris = assertRedirectUris(spec.redirectUris);
|
|
1395
|
-
const allowedScopes = assertScopes(ctx, spec.allowedScopes);
|
|
1396
|
-
const allowedResources = assertResources(ctx, spec.allowedResources);
|
|
1397
|
-
const clientId = spec.clientId ?? generateClientId();
|
|
1398
|
-
const clientSecret = generateClientSecret();
|
|
1399
|
-
const doc = await ctx.models.Client.create({
|
|
1400
|
-
clientId,
|
|
1401
|
-
name,
|
|
1402
|
-
type: "confidential",
|
|
1403
|
-
registration: "manual",
|
|
1404
|
-
trusted: Boolean(spec.trusted),
|
|
1405
|
-
// Only the digest is stored. `clientSecret` below is the only time the
|
|
1406
|
-
// raw value exists outside the caller's variable.
|
|
1407
|
-
secrets: [{ hash: sha256(clientSecret), label: "initial", createdAt: /* @__PURE__ */ new Date() }],
|
|
1408
|
-
redirectUris,
|
|
1409
|
-
allowedScopes,
|
|
1410
|
-
allowedResources,
|
|
1411
|
-
branding: spec.branding ?? {},
|
|
1412
|
-
status: "active"
|
|
1413
|
-
});
|
|
1414
|
-
await ctx.audit({ type: "oauth.client_created", actor: "admin", clientId });
|
|
1415
|
-
return { client: toPublicClient(doc), clientId, clientSecret };
|
|
1416
|
-
},
|
|
1430
|
+
create,
|
|
1417
1431
|
async rotateSecret(clientId, opts = {}) {
|
|
1418
1432
|
const doc = await ctx.models.Client.findOne({ clientId });
|
|
1419
1433
|
if (!doc) throw notFound(clientId);
|
|
@@ -1442,7 +1456,7 @@ function createClientsApi(ctx) {
|
|
|
1442
1456
|
clientId,
|
|
1443
1457
|
meta: { retireAfter, retiresAt }
|
|
1444
1458
|
});
|
|
1445
|
-
return { client: toPublicClient(doc), clientId, clientSecret };
|
|
1459
|
+
return { client: toPublicClient(doc), clientId, type: "confidential", clientSecret };
|
|
1446
1460
|
},
|
|
1447
1461
|
async update(clientId, patch) {
|
|
1448
1462
|
const doc = await ctx.models.Client.findOne({ clientId });
|