@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.js
CHANGED
|
@@ -22,9 +22,11 @@ function clientSchema() {
|
|
|
22
22
|
{
|
|
23
23
|
clientId: { type: String, required: true, unique: true },
|
|
24
24
|
name: { type: String, required: true },
|
|
25
|
-
// `public`
|
|
26
|
-
//
|
|
27
|
-
//
|
|
25
|
+
// `public` is a client that holds no secret and is bound by PKCE instead.
|
|
26
|
+
// Two ways in and they are independent: a CIMD row is written public, and
|
|
27
|
+
// `clients.create({ type: 'public' })` registers one by hand. The enum was
|
|
28
|
+
// written with this widening in mind, so it was one member rather than a
|
|
29
|
+
// migration.
|
|
28
30
|
type: { type: String, enum: ["confidential", "public"], default: "confidential" },
|
|
29
31
|
// How the row got here. A `cimd` row is re-derived from the client's own
|
|
30
32
|
// metadata document, so this is what tells the re-fetch path which fields
|
|
@@ -1357,6 +1359,15 @@ function assertResources(ctx, input) {
|
|
|
1357
1359
|
}
|
|
1358
1360
|
return [...input];
|
|
1359
1361
|
}
|
|
1362
|
+
function assertClientType(value) {
|
|
1363
|
+
if (value === void 0) return "confidential";
|
|
1364
|
+
if (value !== "confidential" && value !== "public") {
|
|
1365
|
+
throw new TypeError(
|
|
1366
|
+
`oauth-host: client type must be 'confidential' or 'public' (got ${JSON.stringify(value)})`
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
return value;
|
|
1370
|
+
}
|
|
1360
1371
|
function assertName(value) {
|
|
1361
1372
|
if (typeof value !== "string" || !value.trim()) {
|
|
1362
1373
|
throw new TypeError("oauth-host: a client needs a non-empty `name` \u2014 it is what the consent screen shows");
|
|
@@ -1378,35 +1389,38 @@ async function revokeTokensMatching(ctx, filter) {
|
|
|
1378
1389
|
return res.modifiedCount ?? 0;
|
|
1379
1390
|
}
|
|
1380
1391
|
function createClientsApi(ctx) {
|
|
1392
|
+
async function create(spec) {
|
|
1393
|
+
if (!spec || typeof spec !== "object") {
|
|
1394
|
+
throw new TypeError("oauth-host: clients.create(spec) requires a spec object");
|
|
1395
|
+
}
|
|
1396
|
+
const name = assertName(spec.name);
|
|
1397
|
+
const type = assertClientType(spec.type);
|
|
1398
|
+
const redirectUris = assertRedirectUris(spec.redirectUris);
|
|
1399
|
+
const allowedScopes = assertScopes(ctx, spec.allowedScopes);
|
|
1400
|
+
const allowedResources = assertResources(ctx, spec.allowedResources);
|
|
1401
|
+
const clientId = spec.clientId ?? generateClientId();
|
|
1402
|
+
const clientSecret = type === "confidential" ? generateClientSecret() : void 0;
|
|
1403
|
+
const doc = await ctx.models.Client.create({
|
|
1404
|
+
clientId,
|
|
1405
|
+
name,
|
|
1406
|
+
type,
|
|
1407
|
+
registration: "manual",
|
|
1408
|
+
trusted: Boolean(spec.trusted),
|
|
1409
|
+
// Only the digest is stored. `clientSecret` below is the only time the
|
|
1410
|
+
// raw value exists outside the caller's variable. Empty for a public
|
|
1411
|
+
// client, which is the same shape a CIMD row is written with.
|
|
1412
|
+
secrets: clientSecret ? [{ hash: sha256(clientSecret), label: "initial", createdAt: /* @__PURE__ */ new Date() }] : [],
|
|
1413
|
+
redirectUris,
|
|
1414
|
+
allowedScopes,
|
|
1415
|
+
allowedResources,
|
|
1416
|
+
branding: spec.branding ?? {},
|
|
1417
|
+
status: "active"
|
|
1418
|
+
});
|
|
1419
|
+
await ctx.audit({ type: "oauth.client_created", actor: "admin", clientId, meta: { type } });
|
|
1420
|
+
return clientSecret ? { client: toPublicClient(doc), clientId, type: "confidential", clientSecret } : { client: toPublicClient(doc), clientId, type: "public" };
|
|
1421
|
+
}
|
|
1381
1422
|
return {
|
|
1382
|
-
|
|
1383
|
-
if (!spec || typeof spec !== "object") {
|
|
1384
|
-
throw new TypeError("oauth-host: clients.create(spec) requires a spec object");
|
|
1385
|
-
}
|
|
1386
|
-
const name = assertName(spec.name);
|
|
1387
|
-
const redirectUris = assertRedirectUris(spec.redirectUris);
|
|
1388
|
-
const allowedScopes = assertScopes(ctx, spec.allowedScopes);
|
|
1389
|
-
const allowedResources = assertResources(ctx, spec.allowedResources);
|
|
1390
|
-
const clientId = spec.clientId ?? generateClientId();
|
|
1391
|
-
const clientSecret = generateClientSecret();
|
|
1392
|
-
const doc = await ctx.models.Client.create({
|
|
1393
|
-
clientId,
|
|
1394
|
-
name,
|
|
1395
|
-
type: "confidential",
|
|
1396
|
-
registration: "manual",
|
|
1397
|
-
trusted: Boolean(spec.trusted),
|
|
1398
|
-
// Only the digest is stored. `clientSecret` below is the only time the
|
|
1399
|
-
// raw value exists outside the caller's variable.
|
|
1400
|
-
secrets: [{ hash: sha256(clientSecret), label: "initial", createdAt: /* @__PURE__ */ new Date() }],
|
|
1401
|
-
redirectUris,
|
|
1402
|
-
allowedScopes,
|
|
1403
|
-
allowedResources,
|
|
1404
|
-
branding: spec.branding ?? {},
|
|
1405
|
-
status: "active"
|
|
1406
|
-
});
|
|
1407
|
-
await ctx.audit({ type: "oauth.client_created", actor: "admin", clientId });
|
|
1408
|
-
return { client: toPublicClient(doc), clientId, clientSecret };
|
|
1409
|
-
},
|
|
1423
|
+
create,
|
|
1410
1424
|
async rotateSecret(clientId, opts = {}) {
|
|
1411
1425
|
const doc = await ctx.models.Client.findOne({ clientId });
|
|
1412
1426
|
if (!doc) throw notFound(clientId);
|
|
@@ -1435,7 +1449,7 @@ function createClientsApi(ctx) {
|
|
|
1435
1449
|
clientId,
|
|
1436
1450
|
meta: { retireAfter, retiresAt }
|
|
1437
1451
|
});
|
|
1438
|
-
return { client: toPublicClient(doc), clientId, clientSecret };
|
|
1452
|
+
return { client: toPublicClient(doc), clientId, type: "confidential", clientSecret };
|
|
1439
1453
|
},
|
|
1440
1454
|
async update(clientId, patch) {
|
|
1441
1455
|
const doc = await ctx.models.Client.findOne({ clientId });
|