cauthy-auth 0.1.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/README.md +12 -1
- package/dist/cauthy-C5_lopMQ.d.ts +108 -0
- package/dist/cauthy-mNADGlNl.d.mts +108 -0
- package/dist/cli.js +202 -2
- package/dist/fastify.d.mts +3 -2
- package/dist/fastify.d.ts +3 -2
- package/dist/index.d.mts +48 -2
- package/dist/index.d.ts +48 -2
- package/dist/index.js +343 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +335 -13
- package/dist/index.mjs.map +1 -1
- package/dist/permissions-B-a3eN0h.d.mts +52 -0
- package/dist/permissions-B-a3eN0h.d.ts +52 -0
- package/dist/react.d.mts +4 -2
- package/dist/react.d.ts +4 -2
- package/dist/react.js +18 -0
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +17 -0
- package/dist/react.mjs.map +1 -1
- package/dist/system-BWLddIt2.d.mts +233 -0
- package/dist/system-BWLddIt2.d.ts +233 -0
- package/package.json +1 -1
- package/dist/cauthy-By2cryXN.d.ts +0 -56
- package/dist/cauthy-DsUNqjg6.d.mts +0 -56
- package/dist/types-BwCjBn-K.d.mts +0 -97
- package/dist/types-BwCjBn-K.d.ts +0 -97
package/dist/index.js
CHANGED
|
@@ -20,10 +20,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
+
CauthyApiError: () => CauthyApiError,
|
|
23
24
|
CauthyConfigError: () => CauthyConfigError,
|
|
25
|
+
CauthyWebhookError: () => CauthyWebhookError,
|
|
26
|
+
can: () => can,
|
|
27
|
+
connectSystem: () => connectSystem,
|
|
24
28
|
createCauthy: () => createCauthy,
|
|
29
|
+
createSystem: () => createSystem,
|
|
30
|
+
pushPolicy: () => pushPolicy,
|
|
25
31
|
pushTheme: () => pushTheme,
|
|
26
|
-
themeFromStackmyth: () => themeFromStackmyth
|
|
32
|
+
themeFromStackmyth: () => themeFromStackmyth,
|
|
33
|
+
verifyWebhook: () => verifyWebhook
|
|
27
34
|
});
|
|
28
35
|
module.exports = __toCommonJS(src_exports);
|
|
29
36
|
|
|
@@ -83,6 +90,9 @@ async function unseal(sealed, key) {
|
|
|
83
90
|
}
|
|
84
91
|
}
|
|
85
92
|
|
|
93
|
+
// src/system.ts
|
|
94
|
+
var import_jose2 = require("jose");
|
|
95
|
+
|
|
86
96
|
// src/types.ts
|
|
87
97
|
var CauthyConfigError = class extends Error {
|
|
88
98
|
constructor(message) {
|
|
@@ -91,12 +101,243 @@ var CauthyConfigError = class extends Error {
|
|
|
91
101
|
}
|
|
92
102
|
};
|
|
93
103
|
|
|
104
|
+
// src/system.ts
|
|
105
|
+
var ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
|
|
106
|
+
var SKEW_MS = 3e4;
|
|
107
|
+
var CauthyApiError = class extends Error {
|
|
108
|
+
constructor(status, code, message) {
|
|
109
|
+
super(`cauthy-auth: ${message}`);
|
|
110
|
+
this.status = status;
|
|
111
|
+
this.code = code;
|
|
112
|
+
this.name = "CauthyApiError";
|
|
113
|
+
}
|
|
114
|
+
status;
|
|
115
|
+
code;
|
|
116
|
+
};
|
|
117
|
+
function env(name) {
|
|
118
|
+
return typeof process !== "undefined" ? process.env?.[name] : void 0;
|
|
119
|
+
}
|
|
120
|
+
function toOrganization(o) {
|
|
121
|
+
return {
|
|
122
|
+
id: o.id,
|
|
123
|
+
system: o.system,
|
|
124
|
+
name: o.name,
|
|
125
|
+
kind: o.kind,
|
|
126
|
+
externalId: o.external_id,
|
|
127
|
+
status: o.status,
|
|
128
|
+
metadata: o.metadata ?? {},
|
|
129
|
+
members: o.members,
|
|
130
|
+
createdAt: o.created_at,
|
|
131
|
+
updatedAt: o.updated_at
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function toMember(m) {
|
|
135
|
+
return { userId: m.user_id, email: m.email, name: m.name, status: m.status, role: m.role, ...m.invited === void 0 ? {} : { invited: m.invited } };
|
|
136
|
+
}
|
|
137
|
+
function asJwk(k) {
|
|
138
|
+
if (typeof k.privateKey !== "string") return k.privateKey;
|
|
139
|
+
return k.privateKey.includes("BEGIN") ? void 0 : JSON.parse(k.privateKey);
|
|
140
|
+
}
|
|
141
|
+
async function loadKey(k) {
|
|
142
|
+
const jwk = asJwk(k);
|
|
143
|
+
return jwk ? (0, import_jose2.importJWK)(jwk, "RS256") : (0, import_jose2.importPKCS8)(k.privateKey, "RS256", { extractable: true });
|
|
144
|
+
}
|
|
145
|
+
function createSystem(given = {}) {
|
|
146
|
+
const issuer = (given.issuer ?? env("CAUTHY_ISSUER") ?? "").replace(/\/+$/, "");
|
|
147
|
+
const clientId = given.clientId ?? env("CAUTHY_CLIENT_ID") ?? "";
|
|
148
|
+
const clientSecret = given.clientSecret ?? env("CAUTHY_CLIENT_SECRET") ?? "";
|
|
149
|
+
const envKey = env("CAUTHY_SYSTEM_KEY");
|
|
150
|
+
const key = given.key ?? (envKey ? { privateKey: envKey, keyId: env("CAUTHY_SYSTEM_KEY_ID") ?? "" } : void 0);
|
|
151
|
+
const doFetch = (...args) => (given.fetch ?? fetch)(...args);
|
|
152
|
+
const tokenEndpoint = `${issuer}/v1/oauth/token`;
|
|
153
|
+
function configured() {
|
|
154
|
+
if (!/^https?:\/\//.test(issuer)) throw new CauthyConfigError("issuer (CAUTHY_ISSUER) must be Cauthy's address");
|
|
155
|
+
if (clientId === "") throw new CauthyConfigError("clientId (CAUTHY_CLIENT_ID) is required");
|
|
156
|
+
if (key ? key.keyId === "" : clientSecret === "") {
|
|
157
|
+
throw new CauthyConfigError(key ? "the key needs its id (CAUTHY_SYSTEM_KEY_ID)" : "to act on its own the application needs its secret (CAUTHY_CLIENT_SECRET) or a key (CAUTHY_SYSTEM_KEY)");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
let imported;
|
|
161
|
+
const signingKey = () => imported ??= loadKey(key);
|
|
162
|
+
async function fail(res, what) {
|
|
163
|
+
const body = await res.json().catch(() => null);
|
|
164
|
+
const first = body?.errors?.[0];
|
|
165
|
+
throw new CauthyApiError(res.status, first?.code ?? "error", `Cauthy refused ${what} (${res.status}): ${first?.message ?? res.statusText}`);
|
|
166
|
+
}
|
|
167
|
+
let held;
|
|
168
|
+
let asking;
|
|
169
|
+
async function ask() {
|
|
170
|
+
configured();
|
|
171
|
+
const form = new URLSearchParams({ grant_type: "client_credentials", client_id: clientId });
|
|
172
|
+
if (key) {
|
|
173
|
+
const assertion = await new import_jose2.SignJWT({}).setProtectedHeader({ alg: "RS256", kid: key.keyId }).setIssuer(clientId).setSubject(clientId).setAudience(tokenEndpoint).setJti(crypto.randomUUID()).setIssuedAt().setExpirationTime("2m").sign(await signingKey());
|
|
174
|
+
form.set("client_assertion_type", ASSERTION_TYPE);
|
|
175
|
+
form.set("client_assertion", assertion);
|
|
176
|
+
} else {
|
|
177
|
+
form.set("client_secret", clientSecret);
|
|
178
|
+
}
|
|
179
|
+
const res = await doFetch(tokenEndpoint, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: form });
|
|
180
|
+
if (!res.ok) await fail(res, "the application's own token");
|
|
181
|
+
const t = await res.json();
|
|
182
|
+
held = { value: t.access_token, until: Date.now() + t.expires_in * 1e3 - SKEW_MS };
|
|
183
|
+
return t.access_token;
|
|
184
|
+
}
|
|
185
|
+
function token() {
|
|
186
|
+
if (held && Date.now() < held.until) return Promise.resolve(held.value);
|
|
187
|
+
return asking ??= ask().finally(() => {
|
|
188
|
+
asking = void 0;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
async function call(method, path, body) {
|
|
192
|
+
const send = async () => doFetch(`${issuer}${path}`, {
|
|
193
|
+
method,
|
|
194
|
+
headers: { authorization: `Bearer ${await token()}`, ...body === void 0 ? {} : { "content-type": "application/json" } },
|
|
195
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
196
|
+
});
|
|
197
|
+
let res = await send();
|
|
198
|
+
if (res.status === 401 && held) {
|
|
199
|
+
held = void 0;
|
|
200
|
+
res = await send();
|
|
201
|
+
}
|
|
202
|
+
if (!res.ok) await fail(res, `${method} ${path}`);
|
|
203
|
+
return res.status === 204 ? void 0 : res.json();
|
|
204
|
+
}
|
|
205
|
+
const data = async (method, path, body) => (await call(method, path, body))?.data;
|
|
206
|
+
const id = encodeURIComponent;
|
|
207
|
+
return {
|
|
208
|
+
token,
|
|
209
|
+
request: data,
|
|
210
|
+
organizations: {
|
|
211
|
+
async list(query = {}) {
|
|
212
|
+
const q = new URLSearchParams();
|
|
213
|
+
for (const [k, v] of Object.entries(query)) if (v !== void 0) q.set(k, String(v));
|
|
214
|
+
const out2 = await call("GET", `/v1/organizations${q.size ? `?${q}` : ""}`);
|
|
215
|
+
return { items: out2.data.map(toOrganization), total: out2.total_count };
|
|
216
|
+
},
|
|
217
|
+
async create(input) {
|
|
218
|
+
return toOrganization(await data(
|
|
219
|
+
"POST",
|
|
220
|
+
"/v1/organizations",
|
|
221
|
+
{ name: input.name, kind: input.kind, external_id: input.externalId, metadata: input.metadata }
|
|
222
|
+
));
|
|
223
|
+
},
|
|
224
|
+
async get(orgId) {
|
|
225
|
+
return toOrganization(await data("GET", `/v1/organizations/${id(orgId)}`));
|
|
226
|
+
},
|
|
227
|
+
async update(orgId, patch) {
|
|
228
|
+
return toOrganization(await data("PATCH", `/v1/organizations/${id(orgId)}`, patch));
|
|
229
|
+
},
|
|
230
|
+
async remove(orgId) {
|
|
231
|
+
await call("DELETE", `/v1/organizations/${id(orgId)}`);
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
members: {
|
|
235
|
+
async list(orgId) {
|
|
236
|
+
return (await data("GET", `/v1/organizations/${id(orgId)}/members`)).map(toMember);
|
|
237
|
+
},
|
|
238
|
+
async add(orgId, m) {
|
|
239
|
+
return toMember(await data(
|
|
240
|
+
"POST",
|
|
241
|
+
`/v1/organizations/${id(orgId)}/members`,
|
|
242
|
+
{ role: m.role, user_id: m.userId, email: m.email, name: m.name, locale: m.locale, client_id: clientId }
|
|
243
|
+
));
|
|
244
|
+
},
|
|
245
|
+
async setRole(orgId, userId, role) {
|
|
246
|
+
return toMember(await data("PUT", `/v1/organizations/${id(orgId)}/members/${id(userId)}`, { role }));
|
|
247
|
+
},
|
|
248
|
+
async remove(orgId, userId) {
|
|
249
|
+
await call("DELETE", `/v1/organizations/${id(orgId)}/members/${id(userId)}`);
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
async invite(person) {
|
|
253
|
+
const u = await data("POST", "/v1/users", { ...person, client_id: clientId });
|
|
254
|
+
return { id: u.id, email: u.email };
|
|
255
|
+
},
|
|
256
|
+
async publicJwks() {
|
|
257
|
+
if (!key) return { keys: [] };
|
|
258
|
+
const { kty, n, e } = asJwk(key) ?? await (0, import_jose2.exportJWK)(await signingKey());
|
|
259
|
+
return { keys: [{ kty, n, e, kid: key.keyId, alg: "RS256", use: "sig" }] };
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/webhook.ts
|
|
265
|
+
var import_jose3 = require("jose");
|
|
266
|
+
var CauthyWebhookError = class extends Error {
|
|
267
|
+
constructor(reason) {
|
|
268
|
+
super(`cauthy-auth: webhook refused: ${reason}`);
|
|
269
|
+
this.reason = reason;
|
|
270
|
+
this.name = "CauthyWebhookError";
|
|
271
|
+
}
|
|
272
|
+
reason;
|
|
273
|
+
};
|
|
274
|
+
var keys = /* @__PURE__ */ new Map();
|
|
275
|
+
function keysOf(issuer) {
|
|
276
|
+
let set = keys.get(issuer);
|
|
277
|
+
if (set === void 0) {
|
|
278
|
+
set = (0, import_jose3.createRemoteJWKSet)(new URL(`${issuer}/.well-known/jwks.json`), { cooldownDuration: 3e4 });
|
|
279
|
+
keys.set(issuer, set);
|
|
280
|
+
}
|
|
281
|
+
return set;
|
|
282
|
+
}
|
|
283
|
+
var hex = (s) => typeof s === "string" && s !== "" ? s : void 0;
|
|
284
|
+
async function verifyWebhook(request, options = {}) {
|
|
285
|
+
const env3 = typeof process !== "undefined" ? process.env?.CAUTHY_ISSUER : void 0;
|
|
286
|
+
const issuer = (options.issuer ?? env3 ?? "").replace(/\/+$/, "");
|
|
287
|
+
if (issuer === "") throw new CauthyWebhookError("issuer (CAUTHY_ISSUER) is not set");
|
|
288
|
+
const signature = request.headers.get("x-cauthy-signature-jwt");
|
|
289
|
+
if (!signature) throw new CauthyWebhookError("no signature");
|
|
290
|
+
const raw = new Uint8Array(await request.arrayBuffer());
|
|
291
|
+
const audience = options.url ?? request.url.split("?")[0];
|
|
292
|
+
let claims;
|
|
293
|
+
try {
|
|
294
|
+
const verified = await (0, import_jose3.jwtVerify)(signature, options.jwks ?? keysOf(issuer), {
|
|
295
|
+
algorithms: ["RS256"],
|
|
296
|
+
issuer,
|
|
297
|
+
audience,
|
|
298
|
+
typ: "cauthy-webhook+jwt",
|
|
299
|
+
requiredClaims: ["exp", "iat", "jti", "body_sha256"],
|
|
300
|
+
currentDate: options.now,
|
|
301
|
+
clockTolerance: 30
|
|
302
|
+
});
|
|
303
|
+
claims = verified.payload;
|
|
304
|
+
} catch (err) {
|
|
305
|
+
throw new CauthyWebhookError(err instanceof Error ? err.message : "bad signature");
|
|
306
|
+
}
|
|
307
|
+
const now = Math.floor((options.now ?? /* @__PURE__ */ new Date()).getTime() / 1e3);
|
|
308
|
+
if (typeof claims.iat !== "number" || claims.iat > now + 30) throw new CauthyWebhookError("signed in the future");
|
|
309
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", raw));
|
|
310
|
+
let b64 = "";
|
|
311
|
+
for (const b of digest) b64 += String.fromCharCode(b);
|
|
312
|
+
const hash = btoa(b64).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
313
|
+
if (hash !== claims.body_sha256) throw new CauthyWebhookError("the body is not the one that was signed");
|
|
314
|
+
let body;
|
|
315
|
+
try {
|
|
316
|
+
body = JSON.parse(new TextDecoder().decode(raw));
|
|
317
|
+
} catch {
|
|
318
|
+
throw new CauthyWebhookError("the body is not JSON");
|
|
319
|
+
}
|
|
320
|
+
if (body.id !== claims.jti || body.event !== claims.evt || body.tenant_id !== claims.tid) {
|
|
321
|
+
throw new CauthyWebhookError("the body and its signature disagree");
|
|
322
|
+
}
|
|
323
|
+
const inner = body.data ?? {};
|
|
324
|
+
return {
|
|
325
|
+
id: String(body.id),
|
|
326
|
+
type: String(body.event),
|
|
327
|
+
tenantId: String(body.tenant_id),
|
|
328
|
+
createdAt: String(inner.created_at ?? body.created_at ?? ""),
|
|
329
|
+
...hex(inner.user_id) ? { userId: inner.user_id } : {},
|
|
330
|
+
...hex(inner.actor_id) ? { actorId: inner.actor_id } : {},
|
|
331
|
+
data: inner.data ?? {}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
94
335
|
// src/cauthy.ts
|
|
95
336
|
var SESSION_DAYS = 30;
|
|
96
337
|
var FLOW_SECONDS = 600;
|
|
97
338
|
var SKEW_SECONDS = 30;
|
|
98
339
|
var ORGANIZATIONS_TTL_MS = 6e4;
|
|
99
|
-
function
|
|
340
|
+
function env2(name) {
|
|
100
341
|
return typeof process !== "undefined" ? process.env?.[name] : void 0;
|
|
101
342
|
}
|
|
102
343
|
function b64url(bytes) {
|
|
@@ -123,11 +364,11 @@ function redirect(location, cookies = []) {
|
|
|
123
364
|
return new Response(null, { status: 302, headers: h });
|
|
124
365
|
}
|
|
125
366
|
function createCauthy(given = {}) {
|
|
126
|
-
const issuer = (given.issuer ??
|
|
127
|
-
const clientId = given.clientId ??
|
|
128
|
-
const clientSecret = given.clientSecret ??
|
|
129
|
-
const secret = given.secret ??
|
|
130
|
-
const system = given.system ??
|
|
367
|
+
const issuer = (given.issuer ?? env2("CAUTHY_ISSUER") ?? "").replace(/\/+$/, "");
|
|
368
|
+
const clientId = given.clientId ?? env2("CAUTHY_CLIENT_ID") ?? "";
|
|
369
|
+
const clientSecret = given.clientSecret ?? env2("CAUTHY_CLIENT_SECRET");
|
|
370
|
+
const secret = given.secret ?? env2("CAUTHY_SECRET") ?? "";
|
|
371
|
+
const system = given.system ?? env2("CAUTHY_SYSTEM") ?? "";
|
|
131
372
|
if (!/^https?:\/\//.test(issuer)) throw new CauthyConfigError("issuer (CAUTHY_ISSUER) must be Cauthy's address, e.g. https://id.example.com");
|
|
132
373
|
if (clientId === "") throw new CauthyConfigError("clientId (CAUTHY_CLIENT_ID) is required");
|
|
133
374
|
if (secret.length < 32) throw new CauthyConfigError("secret (CAUTHY_SECRET) must be at least 32 characters: it encrypts the session cookie");
|
|
@@ -265,7 +506,8 @@ function createCauthy(given = {}) {
|
|
|
265
506
|
kind: String(o.kind ?? ""),
|
|
266
507
|
role: String(o.role ?? ""),
|
|
267
508
|
metadata: o.metadata ?? {},
|
|
268
|
-
...o.external_id ? { externalId: String(o.external_id) } : {}
|
|
509
|
+
...o.external_id ? { externalId: String(o.external_id) } : {},
|
|
510
|
+
...Array.isArray(o.permissions) ? { permissions: o.permissions.map(String), denied: Array.isArray(o.denied) ? o.denied.map(String) : [] } : {}
|
|
269
511
|
})
|
|
270
512
|
);
|
|
271
513
|
if (orgCache.size > 5e3) orgCache.clear();
|
|
@@ -391,8 +633,11 @@ function createCauthy(given = {}) {
|
|
|
391
633
|
const to = value === null ? urls.signIn(back) : `${basePath}/refresh?return_to=${encodeURIComponent(back)}`;
|
|
392
634
|
return { response: redirect(to) };
|
|
393
635
|
}
|
|
636
|
+
const webhook = (request, o = {}) => verifyWebhook(request, { issuer, url: o.url ?? `${originOf(request)}${new URL(request.url).pathname}`, jwks: o.jwks, now: o.now });
|
|
394
637
|
return {
|
|
395
638
|
handler,
|
|
639
|
+
webhook,
|
|
640
|
+
system: createSystem({ issuer, clientId, clientSecret, key: given.systemKey, fetch: given.fetch }),
|
|
396
641
|
getSession,
|
|
397
642
|
status,
|
|
398
643
|
resolve: resolve2,
|
|
@@ -605,11 +850,11 @@ function toWire(theme) {
|
|
|
605
850
|
return wire;
|
|
606
851
|
}
|
|
607
852
|
async function pushTheme(o) {
|
|
608
|
-
const
|
|
609
|
-
const issuer = (o.issuer ??
|
|
610
|
-
const clientId = o.clientId ??
|
|
611
|
-
const tenant = o.tenant ??
|
|
612
|
-
const token = o.token ??
|
|
853
|
+
const env3 = (n) => typeof process !== "undefined" ? process.env?.[n] : void 0;
|
|
854
|
+
const issuer = (o.issuer ?? env3("CAUTHY_ISSUER") ?? "").replace(/\/+$/, "");
|
|
855
|
+
const clientId = o.clientId ?? env3("CAUTHY_CLIENT_ID") ?? "";
|
|
856
|
+
const tenant = o.tenant ?? env3("CAUTHY_TENANT") ?? "";
|
|
857
|
+
const token = o.token ?? env3("CAUTHY_TOKEN") ?? "";
|
|
613
858
|
for (const [name, v] of Object.entries({ CAUTHY_ISSUER: issuer, CAUTHY_CLIENT_ID: clientId, CAUTHY_TENANT: tenant, CAUTHY_TOKEN: token })) {
|
|
614
859
|
if (v === "") throw new Error(`cauthy-auth: ${name} is required to push a theme`);
|
|
615
860
|
}
|
|
@@ -623,11 +868,95 @@ async function pushTheme(o) {
|
|
|
623
868
|
throw new Error(`cauthy-auth: Cauthy refused the theme (${res.status}): ${body?.errors?.[0]?.message ?? res.statusText}`);
|
|
624
869
|
}
|
|
625
870
|
}
|
|
871
|
+
|
|
872
|
+
// src/permissions.ts
|
|
873
|
+
function matches(entry, resource, action) {
|
|
874
|
+
const i = entry.lastIndexOf(":");
|
|
875
|
+
if (i < 0) return false;
|
|
876
|
+
const r = entry.slice(0, i);
|
|
877
|
+
const a = entry.slice(i + 1);
|
|
878
|
+
return (r === "*" || r === resource) && (a === "*" || a === action);
|
|
879
|
+
}
|
|
880
|
+
function can(organization, resource, action) {
|
|
881
|
+
if (!organization?.permissions) return false;
|
|
882
|
+
if ((organization.denied ?? []).some((d) => matches(d, resource, action))) return false;
|
|
883
|
+
return organization.permissions.some((p) => matches(p, resource, action));
|
|
884
|
+
}
|
|
885
|
+
async function pushPolicy(o) {
|
|
886
|
+
const env3 = (n) => typeof process !== "undefined" ? process.env?.[n] : void 0;
|
|
887
|
+
const issuer = (o.issuer ?? env3("CAUTHY_ISSUER") ?? "").replace(/\/+$/, "");
|
|
888
|
+
const system = o.system ?? env3("CAUTHY_SYSTEM") ?? "";
|
|
889
|
+
const tenant = o.tenant ?? env3("CAUTHY_TENANT") ?? "";
|
|
890
|
+
const token = o.token ?? env3("CAUTHY_TOKEN") ?? "";
|
|
891
|
+
for (const [name, v] of Object.entries({ CAUTHY_ISSUER: issuer, CAUTHY_SYSTEM: system, CAUTHY_TENANT: tenant, CAUTHY_TOKEN: token })) {
|
|
892
|
+
if (v === "") throw new Error(`cauthy-auth: ${name} is required to push a policy`);
|
|
893
|
+
}
|
|
894
|
+
const res = await (o.fetch ?? fetch)(`${issuer}/v1/systems/${encodeURIComponent(system)}/policy`, {
|
|
895
|
+
method: "PUT",
|
|
896
|
+
headers: { authorization: `Bearer ${token}`, "x-tenant-key": tenant, "content-type": "application/json" },
|
|
897
|
+
body: JSON.stringify({ roles: o.roles })
|
|
898
|
+
});
|
|
899
|
+
if (!res.ok) {
|
|
900
|
+
const body = await res.json().catch(() => null);
|
|
901
|
+
throw new Error(`cauthy-auth: Cauthy refused the policy (${res.status}): ${body?.errors?.[0]?.message ?? res.statusText}`);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// src/connect.ts
|
|
906
|
+
function sessionSecret() {
|
|
907
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
908
|
+
let s = "";
|
|
909
|
+
for (const b of bytes) s += String.fromCharCode(b);
|
|
910
|
+
return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
911
|
+
}
|
|
912
|
+
async function connectSystem(o) {
|
|
913
|
+
const env3 = (n) => typeof process !== "undefined" ? process.env?.[n] : void 0;
|
|
914
|
+
const issuer = (o.issuer ?? env3("CAUTHY_ISSUER") ?? "").replace(/\/+$/, "");
|
|
915
|
+
const tenant = o.tenant ?? env3("CAUTHY_TENANT") ?? "";
|
|
916
|
+
const token = o.token ?? env3("CAUTHY_TOKEN") ?? "";
|
|
917
|
+
for (const [name, v] of Object.entries({ CAUTHY_ISSUER: issuer, CAUTHY_TENANT: tenant, CAUTHY_TOKEN: token })) {
|
|
918
|
+
if (v === "") throw new Error(`cauthy-auth: ${name} is required to connect a system`);
|
|
919
|
+
}
|
|
920
|
+
const res = await (o.fetch ?? fetch)(`${issuer}/v1/connect`, {
|
|
921
|
+
method: "POST",
|
|
922
|
+
headers: { authorization: `Bearer ${token}`, "x-tenant-key": tenant, "content-type": "application/json" },
|
|
923
|
+
body: JSON.stringify({
|
|
924
|
+
system: o.system,
|
|
925
|
+
app_url: o.appUrl,
|
|
926
|
+
name: o.name,
|
|
927
|
+
callback_path: o.callbackPath,
|
|
928
|
+
events_url: o.eventsUrl,
|
|
929
|
+
events: o.events,
|
|
930
|
+
jwks_uri: o.jwksUri
|
|
931
|
+
})
|
|
932
|
+
});
|
|
933
|
+
const body = await res.json().catch(() => null);
|
|
934
|
+
if (!res.ok || !body?.data) {
|
|
935
|
+
const why = (body?.errors ?? []).map((e) => e.message).filter(Boolean).join("; ") || res.statusText;
|
|
936
|
+
throw new Error(`cauthy-auth: Cauthy did not connect the system (${res.status}): ${why}`);
|
|
937
|
+
}
|
|
938
|
+
const d = body.data;
|
|
939
|
+
return {
|
|
940
|
+
system: d.system,
|
|
941
|
+
clientId: d.client.client_id,
|
|
942
|
+
clientSecret: d.client_secret,
|
|
943
|
+
redirectUris: d.client.redirect_uris,
|
|
944
|
+
webhook: d.webhook,
|
|
945
|
+
env: { ...d.env, CAUTHY_SECRET: sessionSecret() }
|
|
946
|
+
};
|
|
947
|
+
}
|
|
626
948
|
// Annotate the CommonJS export names for ESM import in node:
|
|
627
949
|
0 && (module.exports = {
|
|
950
|
+
CauthyApiError,
|
|
628
951
|
CauthyConfigError,
|
|
952
|
+
CauthyWebhookError,
|
|
953
|
+
can,
|
|
954
|
+
connectSystem,
|
|
629
955
|
createCauthy,
|
|
956
|
+
createSystem,
|
|
957
|
+
pushPolicy,
|
|
630
958
|
pushTheme,
|
|
631
|
-
themeFromStackmyth
|
|
959
|
+
themeFromStackmyth,
|
|
960
|
+
verifyWebhook
|
|
632
961
|
});
|
|
633
962
|
//# sourceMappingURL=index.js.map
|