@authyon/server 0.2.0-beta.11 → 0.2.0-beta.14
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 +49 -62
- package/dist/{authorization-CeP_GqT7.d.cts → authorization-B7ynKAud.d.cts} +1 -1
- package/dist/{authorization-D_A6L9Ie.d.ts → authorization-BF015NDJ.d.ts} +1 -1
- package/dist/{authyonServerClient-D-DxoL30.d.cts → authyonServerClient-DmNnjw4z.d.cts} +141 -115
- package/dist/{authyonServerClient-D-DxoL30.d.ts → authyonServerClient-DmNnjw4z.d.ts} +141 -115
- package/dist/bff.cjs +29 -6
- package/dist/bff.d.cts +1 -1
- package/dist/bff.d.ts +1 -1
- package/dist/bff.js +1 -1
- package/dist/{chunk-56H66KLG.js → chunk-TWUVXZOT.js} +29 -6
- package/dist/index.cjs +127 -147
- package/dist/index.d.cts +27 -9
- package/dist/index.d.ts +27 -9
- package/dist/index.js +84 -125
- package/dist/next.d.cts +2 -2
- package/dist/next.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -37,11 +37,9 @@ __export(index_exports, {
|
|
|
37
37
|
FetchHttpAdapter: () => FetchHttpAdapter,
|
|
38
38
|
JwksTokenVerifier: () => JwksTokenVerifier,
|
|
39
39
|
LoggingHttpAdapter: () => LoggingHttpAdapter,
|
|
40
|
-
PlatformScopedClient: () => PlatformScopedClient,
|
|
41
40
|
TenantScopedClient: () => TenantScopedClient,
|
|
42
41
|
TokenVerificationError: () => TokenVerificationError,
|
|
43
42
|
UserScopedClient: () => UserScopedClient,
|
|
44
|
-
WorkspaceInvitesClient: () => WorkspaceInvitesClient,
|
|
45
43
|
authorizeRequest: () => authorizeRequest,
|
|
46
44
|
authorizeToken: () => authorizeToken,
|
|
47
45
|
createAuthorizationErrorResponse: () => createAuthorizationErrorResponse,
|
|
@@ -126,9 +124,9 @@ function credentialDetail(value) {
|
|
|
126
124
|
accessTokenLifetimeSeconds: value.accessTokenLifetimeSeconds
|
|
127
125
|
};
|
|
128
126
|
}
|
|
129
|
-
async function credentialPage(request,
|
|
127
|
+
async function credentialPage(request, path2, options = {}) {
|
|
130
128
|
const query = credentialQuery(options);
|
|
131
|
-
const page = await request(
|
|
129
|
+
const page = await request(path2, { query });
|
|
132
130
|
if (!page || !Array.isArray(page.data))
|
|
133
131
|
throw new TypeError("Authyon: expected a paginated credential response.");
|
|
134
132
|
return {
|
|
@@ -141,13 +139,13 @@ async function credentialPage(request, path, options = {}) {
|
|
|
141
139
|
hasPrev: page.hasPrev
|
|
142
140
|
};
|
|
143
141
|
}
|
|
144
|
-
async function allCredentials(request,
|
|
142
|
+
async function allCredentials(request, path2) {
|
|
145
143
|
const result = [];
|
|
146
144
|
const seen = /* @__PURE__ */ new Set();
|
|
147
145
|
let skip = 0;
|
|
148
146
|
for (let iteration = 0; iteration < 1e3; iteration++) {
|
|
149
147
|
const page = await request(
|
|
150
|
-
|
|
148
|
+
path2,
|
|
151
149
|
iteration === 0 ? {} : { query: { skip, take: 100 } }
|
|
152
150
|
);
|
|
153
151
|
if (Array.isArray(page)) {
|
|
@@ -170,134 +168,67 @@ async function allCredentials(request, path) {
|
|
|
170
168
|
throw new Error("Authyon: use listPage for more than 1000 credential pages.");
|
|
171
169
|
}
|
|
172
170
|
|
|
171
|
+
// ../../internal/core/financial/subjectFinancialAuthorizations.ts
|
|
172
|
+
function path(id, suffix = "") {
|
|
173
|
+
if (typeof id !== "string" || !id.trim())
|
|
174
|
+
throw new TypeError("Authyon: a financial authorization id is required.");
|
|
175
|
+
return `/auth/authorizations/${encodeURIComponent(id)}${suffix}`;
|
|
176
|
+
}
|
|
177
|
+
function subjectFinancialAuthorizations(request) {
|
|
178
|
+
return {
|
|
179
|
+
/** GET /auth/authorizations/{id} — the pending transaction, to show before asking for the code. */
|
|
180
|
+
get: (id) => request(path(id)),
|
|
181
|
+
/** POST /auth/authorizations/{id}/webauthn/options — passkey options for approving this authorization. */
|
|
182
|
+
webauthnOptions: (id) => request(path(id, "/webauthn/options"), { method: "POST" }),
|
|
183
|
+
/**
|
|
184
|
+
* POST /auth/authorizations/{id}/confirm — approves the transaction.
|
|
185
|
+
*
|
|
186
|
+
* Pass the authenticator code or passkey assertion to verify the second
|
|
187
|
+
* factor inline (recommended). Without `input`, the session itself must
|
|
188
|
+
* have used a passkey or authenticator code within the last 5 minutes,
|
|
189
|
+
* otherwise the API answers `step_up_required`.
|
|
190
|
+
*/
|
|
191
|
+
confirm: (id, input) => request(path(id, "/confirm"), { method: "POST", body: input }),
|
|
192
|
+
/** POST /auth/authorizations/{id}/reject — the customer declines the transaction. */
|
|
193
|
+
reject: (id) => request(path(id, "/reject"), { method: "POST" })
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
173
197
|
// src/client/scopedManagementClient.ts
|
|
174
198
|
function scopedRequest(request, source) {
|
|
175
|
-
return async (
|
|
199
|
+
return async (path2, options = {}) => {
|
|
176
200
|
const token = typeof source === "function" ? await source() : source;
|
|
177
201
|
if (typeof token !== "string" || !token.trim() || /\s/u.test(token))
|
|
178
202
|
throw new TypeError("Authyon: a valid access token is required.");
|
|
179
|
-
return request(
|
|
203
|
+
return request(path2, {
|
|
180
204
|
...options,
|
|
181
205
|
headers: { ...options.headers, Authorization: `Bearer ${token}` }
|
|
182
206
|
});
|
|
183
207
|
};
|
|
184
208
|
}
|
|
185
|
-
function environmentPath(scope) {
|
|
186
|
-
return `/platform/workspaces/${segment(scope.workspaceId)}/environments/${segment(scope.environmentId)}`;
|
|
187
|
-
}
|
|
188
|
-
function tenantPath(scope) {
|
|
189
|
-
return `${environmentPath(scope)}/tenants/${segment(scope.tenantId)}`;
|
|
190
|
-
}
|
|
191
|
-
function credentialPath(scope) {
|
|
192
|
-
return `${scope.tenantId === void 0 ? environmentPath(scope) : tenantPath(scope)}/credentials`;
|
|
193
|
-
}
|
|
194
|
-
function workspacePath(id) {
|
|
195
|
-
return `/platform/workspaces/${segment(id)}`;
|
|
196
|
-
}
|
|
197
|
-
function workspaceRole(role) {
|
|
198
|
-
if (role !== "admin" && role !== "auditor")
|
|
199
|
-
throw new TypeError("Authyon: workspace role must be admin or auditor.");
|
|
200
|
-
return role;
|
|
201
|
-
}
|
|
202
209
|
var _request;
|
|
203
|
-
var PlatformScopedClient = class {
|
|
204
|
-
/** @hidden */
|
|
205
|
-
constructor(request, token) {
|
|
206
|
-
__privateAdd(this, _request);
|
|
207
|
-
this.credentials = {
|
|
208
|
-
list: (scope, options = {}) => credentialPage(__privateGet(this, _request), credentialPath(scope), options),
|
|
209
|
-
get: async (scope, credentialId) => credentialDetail(await __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}`)),
|
|
210
|
-
create: (scope, input) => __privateGet(this, _request).call(this, credentialPath(scope), {
|
|
211
|
-
method: "POST",
|
|
212
|
-
body: { description: input.description, ...lifetimeBody(input), ...permissionsBody(input) }
|
|
213
|
-
}),
|
|
214
|
-
updatePermissions: (scope, credentialId, input) => __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}/permissions`, {
|
|
215
|
-
method: "PUT",
|
|
216
|
-
body: permissionsBody(input)
|
|
217
|
-
}),
|
|
218
|
-
updateScopes: (scope, credentialId, scopes) => this.credentials.updatePermissions(scope, credentialId, { scopes }),
|
|
219
|
-
/** Returns a new secret once. API may require an explicit step-up first. */
|
|
220
|
-
rotate: (scope, credentialId) => __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}/rotate`, { method: "POST" }),
|
|
221
|
-
revoke: (scope, credentialId) => __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}`, { method: "DELETE" })
|
|
222
|
-
};
|
|
223
|
-
this.workspaces = {
|
|
224
|
-
team: (workspaceId) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/team`),
|
|
225
|
-
members: {
|
|
226
|
-
invite: (workspaceId, input) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/invites`, {
|
|
227
|
-
method: "POST",
|
|
228
|
-
body: { email: input.email, role: workspaceRole(input.role) }
|
|
229
|
-
}),
|
|
230
|
-
/** memberId comes from team.members; it is not the platform userId. */
|
|
231
|
-
remove: (workspaceId, memberId) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/members/${segment(memberId)}`, {
|
|
232
|
-
method: "DELETE"
|
|
233
|
-
}),
|
|
234
|
-
changeRole: (workspaceId, memberId, role) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/members/${segment(memberId)}`, {
|
|
235
|
-
method: "PATCH",
|
|
236
|
-
body: { role: workspaceRole(role) }
|
|
237
|
-
})
|
|
238
|
-
},
|
|
239
|
-
invites: {
|
|
240
|
-
create: (workspaceId, input) => this.workspaces.members.invite(workspaceId, input),
|
|
241
|
-
revoke: (workspaceId, inviteId) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/invites/${segment(inviteId)}`, {
|
|
242
|
-
method: "DELETE"
|
|
243
|
-
})
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
this.tenants = {
|
|
247
|
-
members: {
|
|
248
|
-
list: (scope, options = {}) => __privateGet(this, _request).call(this, `${tenantPath(scope)}/members`, { query: options }),
|
|
249
|
-
add: (scope, userId, roles) => __privateGet(this, _request).call(this, `${tenantPath(scope)}/members`, { method: "POST", body: { userId, roles } }),
|
|
250
|
-
remove: (scope, userId) => __privateGet(this, _request).call(this, `${tenantPath(scope)}/members/${segment(userId)}`, { method: "DELETE" })
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
this.auth = {
|
|
254
|
-
/** Explicitly confirms the current platform session; passwords are not retained. */
|
|
255
|
-
stepUp: (currentPassword) => __privateGet(this, _request).call(this, "/platform/auth/step-up", { method: "POST", body: { currentPassword } })
|
|
256
|
-
};
|
|
257
|
-
__privateSet(this, _request, scopedRequest(request, token));
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
_request = new WeakMap();
|
|
261
|
-
var _request2;
|
|
262
210
|
var UserScopedClient = class {
|
|
263
211
|
/** @hidden */
|
|
264
212
|
constructor(request, token) {
|
|
265
|
-
__privateAdd(this,
|
|
213
|
+
__privateAdd(this, _request);
|
|
266
214
|
this.tenants = {
|
|
267
215
|
members: {
|
|
268
|
-
list: (tenantId, options = {}) => __privateGet(this,
|
|
216
|
+
list: (tenantId, options = {}) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members`, { query: options }),
|
|
269
217
|
/** Adds an existing environment user by email; does not send an invitation email. */
|
|
270
|
-
invite: (tenantId, input) => __privateGet(this,
|
|
218
|
+
invite: (tenantId, input) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members`, {
|
|
271
219
|
method: "POST",
|
|
272
220
|
body: { email: input.email, roles: input.roles }
|
|
273
221
|
}),
|
|
274
|
-
remove: (tenantId, userId) => __privateGet(this,
|
|
222
|
+
remove: (tenantId, userId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members/${segment(userId)}`, {
|
|
275
223
|
method: "DELETE"
|
|
276
224
|
})
|
|
277
225
|
}
|
|
278
226
|
};
|
|
279
|
-
__privateSet(this,
|
|
280
|
-
|
|
281
|
-
};
|
|
282
|
-
_request2 = new WeakMap();
|
|
283
|
-
var _request3;
|
|
284
|
-
var WorkspaceInvitesClient = class {
|
|
285
|
-
/** @hidden */
|
|
286
|
-
constructor(request) {
|
|
287
|
-
__privateAdd(this, _request3);
|
|
288
|
-
__privateSet(this, _request3, request);
|
|
289
|
-
}
|
|
290
|
-
preview(token) {
|
|
291
|
-
return __privateGet(this, _request3).call(this, `/platform/workspace-invites/${segment(token)}`);
|
|
292
|
-
}
|
|
293
|
-
accept(token, input = {}) {
|
|
294
|
-
return __privateGet(this, _request3).call(this, `/platform/workspace-invites/${segment(token)}/accept`, {
|
|
295
|
-
method: "POST",
|
|
296
|
-
body: { name: input.name, password: input.password }
|
|
297
|
-
});
|
|
227
|
+
__privateSet(this, _request, scopedRequest(request, token));
|
|
228
|
+
this.financialAuthorizations = subjectFinancialAuthorizations(__privateGet(this, _request));
|
|
298
229
|
}
|
|
299
230
|
};
|
|
300
|
-
|
|
231
|
+
_request = new WeakMap();
|
|
301
232
|
|
|
302
233
|
// ../../internal/core/config/defaults.ts
|
|
303
234
|
var DEFAULT_BASE_URL = "https://api.authyon.com";
|
|
@@ -344,16 +275,37 @@ var ErrorCodes = {
|
|
|
344
275
|
EmailTaken: "user.email_taken",
|
|
345
276
|
PasswordWeak: "user.password_weak",
|
|
346
277
|
PasswordPwned: "user.password_pwned",
|
|
347
|
-
RateLimited: "rate_limited"
|
|
278
|
+
RateLimited: "rate_limited",
|
|
279
|
+
StepUpRequired: "step_up_required",
|
|
280
|
+
InvalidSecondFactorCode: "invalid_code",
|
|
281
|
+
VerificationAttemptsExhausted: "verification_attempts_exhausted",
|
|
282
|
+
MethodNotEnrolled: "method_not_enrolled",
|
|
283
|
+
InvalidAuthorizationState: "invalid_authorization_state",
|
|
284
|
+
TransactionMismatch: "transaction_mismatch",
|
|
285
|
+
AuthorizationNotConsumable: "authorization_not_consumable",
|
|
286
|
+
IdempotencyConflict: "idempotency_conflict"
|
|
348
287
|
};
|
|
288
|
+
var STANDARD_ERROR_FIELDS = /* @__PURE__ */ new Set([
|
|
289
|
+
"type",
|
|
290
|
+
"status",
|
|
291
|
+
"title",
|
|
292
|
+
"detail",
|
|
293
|
+
"code",
|
|
294
|
+
"error",
|
|
295
|
+
"error_description"
|
|
296
|
+
]);
|
|
349
297
|
var AuthyonError = class extends Error {
|
|
350
298
|
constructor(status, body, options = {}) {
|
|
351
|
-
|
|
299
|
+
const detail = body.detail ?? body.error_description;
|
|
300
|
+
super(detail ?? body.title ?? `Authyon request failed with status ${status}`);
|
|
352
301
|
this.name = "AuthyonError";
|
|
353
302
|
this.status = status;
|
|
354
|
-
this.code = body.code ?? "unknown";
|
|
303
|
+
this.code = body.code ?? body.error ?? "unknown";
|
|
355
304
|
this.title = body.title ?? "Error";
|
|
356
|
-
this.detail =
|
|
305
|
+
this.detail = detail;
|
|
306
|
+
this.extensions = Object.fromEntries(
|
|
307
|
+
Object.entries(body).filter(([key]) => !STANDARD_ERROR_FIELDS.has(key))
|
|
308
|
+
);
|
|
357
309
|
this.requestId = options.requestId;
|
|
358
310
|
this.retryAfter = options.retryAfter;
|
|
359
311
|
this.cause = options.cause;
|
|
@@ -403,6 +355,7 @@ var AuthyonError = class extends Error {
|
|
|
403
355
|
};
|
|
404
356
|
function classifyError(status, code) {
|
|
405
357
|
if (code === ErrorCodes.NetworkError) return "network";
|
|
358
|
+
if (code === ErrorCodes.StepUpRequired) return "authentication";
|
|
406
359
|
if (code === ErrorCodes.Timeout || status === 408) return "timeout";
|
|
407
360
|
if (code === ErrorCodes.RateLimited || status === 429) return "rate_limit";
|
|
408
361
|
if (code === ErrorCodes.EmailTaken || status === 409) return "conflict";
|
|
@@ -441,14 +394,14 @@ function isRetryable(category) {
|
|
|
441
394
|
}
|
|
442
395
|
|
|
443
396
|
// ../../internal/core/http/query.ts
|
|
444
|
-
function appendQuery(
|
|
445
|
-
if (!params) return
|
|
397
|
+
function appendQuery(path2, params) {
|
|
398
|
+
if (!params) return path2;
|
|
446
399
|
const query = new URLSearchParams();
|
|
447
400
|
for (const [key, value2] of Object.entries(params)) {
|
|
448
401
|
if (value2 !== void 0) query.set(key, String(value2));
|
|
449
402
|
}
|
|
450
403
|
const value = query.toString();
|
|
451
|
-
return value ? `${
|
|
404
|
+
return value ? `${path2}${path2.includes("?") ? "&" : "?"}${value}` : path2;
|
|
452
405
|
}
|
|
453
406
|
|
|
454
407
|
// ../../internal/core/http/httpAdapter.ts
|
|
@@ -517,7 +470,6 @@ function sanitizeUrl(value) {
|
|
|
517
470
|
url.username = "";
|
|
518
471
|
url.password = "";
|
|
519
472
|
url.hash = "";
|
|
520
|
-
url.pathname = url.pathname.replace(/(\/platform\/workspace-invites\/)[^/]+/u, "$1REDACTED");
|
|
521
473
|
const queryKeys = /* @__PURE__ */ new Set();
|
|
522
474
|
url.searchParams.forEach((_value, key) => queryKeys.add(key));
|
|
523
475
|
url.search = queryKeys.size > 0 ? [...queryKeys].map((key) => `${encodeURIComponent(key)}=REDACTED`).join("&") : "";
|
|
@@ -547,12 +499,12 @@ function createSharedTransport(options) {
|
|
|
547
499
|
const httpAdapter = options.httpLogger ? new LoggingHttpAdapter(baseAdapter, options.httpLogger) : baseAdapter;
|
|
548
500
|
return {
|
|
549
501
|
baseUrl,
|
|
550
|
-
async request(
|
|
502
|
+
async request(path2, init) {
|
|
551
503
|
const controller = new AbortController();
|
|
552
504
|
const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
|
|
553
505
|
try {
|
|
554
506
|
return await httpAdapter.request({
|
|
555
|
-
url: `${baseUrl}${
|
|
507
|
+
url: `${baseUrl}${path2}`,
|
|
556
508
|
method: init.method ?? "GET",
|
|
557
509
|
headers: normalizeHeaders(init.headers),
|
|
558
510
|
body: init.body,
|
|
@@ -610,11 +562,11 @@ var JsonHttpClient = class {
|
|
|
610
562
|
constructor(transport) {
|
|
611
563
|
this.transport = transport;
|
|
612
564
|
}
|
|
613
|
-
async send(
|
|
565
|
+
async send(path2, options = {}) {
|
|
614
566
|
const headers = { ...options.headers };
|
|
615
567
|
if (options.body !== void 0) headers["Content-Type"] = "application/json";
|
|
616
568
|
try {
|
|
617
|
-
return await this.transport.request(appendQuery(
|
|
569
|
+
return await this.transport.request(appendQuery(path2, options.query), {
|
|
618
570
|
method: options.method ?? "GET",
|
|
619
571
|
headers,
|
|
620
572
|
body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
|
|
@@ -628,7 +580,9 @@ var JsonHttpClient = class {
|
|
|
628
580
|
if (!response.ok) {
|
|
629
581
|
let body = {};
|
|
630
582
|
try {
|
|
631
|
-
|
|
583
|
+
const parsed = await response.json();
|
|
584
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
585
|
+
body = parsed;
|
|
632
586
|
} catch {
|
|
633
587
|
}
|
|
634
588
|
throw new AuthyonError(response.status, body, responseMetadata(response));
|
|
@@ -636,8 +590,8 @@ var JsonHttpClient = class {
|
|
|
636
590
|
if (response.status === 204) return void 0;
|
|
637
591
|
return await response.json();
|
|
638
592
|
}
|
|
639
|
-
async request(
|
|
640
|
-
return this.parse(await this.send(
|
|
593
|
+
async request(path2, options = {}) {
|
|
594
|
+
return this.parse(await this.send(path2, options));
|
|
641
595
|
}
|
|
642
596
|
};
|
|
643
597
|
|
|
@@ -846,9 +800,6 @@ var AuthyonServerClient = class {
|
|
|
846
800
|
}
|
|
847
801
|
})
|
|
848
802
|
};
|
|
849
|
-
this.workspaceInvites = new WorkspaceInvitesClient(
|
|
850
|
-
(path, options) => this.http.request(path, options)
|
|
851
|
-
);
|
|
852
803
|
// ── Environment management (users, tenants, roles, permissions, audit) ───
|
|
853
804
|
this.environment = {
|
|
854
805
|
users: {
|
|
@@ -943,12 +894,12 @@ var AuthyonServerClient = class {
|
|
|
943
894
|
credentials: {
|
|
944
895
|
/** GET /env/tenants/{tenantId}/credentials. Returns metadata only, including revoked credentials. */
|
|
945
896
|
list: (tenantId) => allCredentials(
|
|
946
|
-
(
|
|
897
|
+
(path2, options) => this.request(path2, { ...options, envBearer: true }),
|
|
947
898
|
`/env/tenants/${segment(tenantId)}/credentials`
|
|
948
899
|
),
|
|
949
900
|
/** Paginated searchable listing. Prefer this over loading every credential. */
|
|
950
901
|
listPage: (tenantId, options = {}) => credentialPage(
|
|
951
|
-
(
|
|
902
|
+
(path2, requestOptions) => this.request(path2, { ...requestOptions, envBearer: true }),
|
|
952
903
|
`/env/tenants/${segment(tenantId)}/credentials`,
|
|
953
904
|
options
|
|
954
905
|
),
|
|
@@ -1119,6 +1070,41 @@ var AuthyonServerClient = class {
|
|
|
1119
1070
|
/** GET /permissions/reserved — reserved permission names you can't redefine. */
|
|
1120
1071
|
reserved: () => this.request("/permissions/reserved", { envBearer: true })
|
|
1121
1072
|
},
|
|
1073
|
+
/**
|
|
1074
|
+
* Transaction-bound step-up for financial operations. The environment
|
|
1075
|
+
* credential needs the `authyon:financial:authorize` scope.
|
|
1076
|
+
*
|
|
1077
|
+
* 1. `create()` the authorization for the transaction and the customer.
|
|
1078
|
+
* 2. The customer approves it with their authenticator code or passkey
|
|
1079
|
+
* (`@authyon/auth` → `financialAuthorizations.confirm`).
|
|
1080
|
+
* 3. `consume()` it with the same transaction right before executing it.
|
|
1081
|
+
*/
|
|
1082
|
+
financialAuthorizations: {
|
|
1083
|
+
/** POST /env/authorizations — registers a transaction awaiting the customer's approval. */
|
|
1084
|
+
create: (input) => {
|
|
1085
|
+
const { idempotencyKey, ...body } = input;
|
|
1086
|
+
if (typeof idempotencyKey !== "string" || !idempotencyKey.trim())
|
|
1087
|
+
throw new TypeError("Authyon: `idempotencyKey` is required.");
|
|
1088
|
+
return this.request("/env/authorizations", {
|
|
1089
|
+
method: "POST",
|
|
1090
|
+
envBearer: true,
|
|
1091
|
+
headers: { "Idempotency-Key": idempotencyKey },
|
|
1092
|
+
body
|
|
1093
|
+
});
|
|
1094
|
+
},
|
|
1095
|
+
/** GET /env/authorizations/{id} — current status and, once approved, the assurance evidence. */
|
|
1096
|
+
get: (id) => this.request(`/env/authorizations/${segment(id)}`, { envBearer: true }),
|
|
1097
|
+
/**
|
|
1098
|
+
* POST /env/authorizations/{id}/consume — redeems an approved
|
|
1099
|
+
* authorization exactly once. Resend the same transaction given to
|
|
1100
|
+
* `create()`; any difference fails with `transaction_mismatch`.
|
|
1101
|
+
*/
|
|
1102
|
+
consume: (id, transaction) => this.request(`/env/authorizations/${segment(id)}/consume`, {
|
|
1103
|
+
method: "POST",
|
|
1104
|
+
envBearer: true,
|
|
1105
|
+
body: transaction
|
|
1106
|
+
})
|
|
1107
|
+
},
|
|
1122
1108
|
audit: {
|
|
1123
1109
|
/** GET /env/audit — paginated list of the environment's audit events. */
|
|
1124
1110
|
list: (params = {}) => this.request("/env/audit", { envBearer: true, query: params }),
|
|
@@ -1169,7 +1155,7 @@ var AuthyonServerClient = class {
|
|
|
1169
1155
|
};
|
|
1170
1156
|
});
|
|
1171
1157
|
}
|
|
1172
|
-
async request(
|
|
1158
|
+
async request(path2, options = {}) {
|
|
1173
1159
|
const headers = {
|
|
1174
1160
|
...clientIpHeaders({ clientIp: this.clientIp }),
|
|
1175
1161
|
...options.headers
|
|
@@ -1178,7 +1164,7 @@ var AuthyonServerClient = class {
|
|
|
1178
1164
|
headers.Authorization = `Bearer ${await this.getEnvironmentAccessToken()}`;
|
|
1179
1165
|
}
|
|
1180
1166
|
if (this.envKey) headers["X-Authyon-Environment"] = this.envKey;
|
|
1181
|
-
return this.http.request(
|
|
1167
|
+
return this.http.request(path2, { ...options, headers });
|
|
1182
1168
|
}
|
|
1183
1169
|
/** Mints (and caches) an environment access token from `clientId`/`clientSecret`. */
|
|
1184
1170
|
async getEnvironmentAccessToken() {
|
|
@@ -1233,17 +1219,13 @@ var AuthyonServerClient = class {
|
|
|
1233
1219
|
tenant(credentials) {
|
|
1234
1220
|
return new TenantScopedClient(this, credentials);
|
|
1235
1221
|
}
|
|
1236
|
-
/** Uses only the supplied platform-user access token. */
|
|
1237
|
-
platform(token) {
|
|
1238
|
-
return new PlatformScopedClient((path, options) => this.http.request(path, options), token);
|
|
1239
|
-
}
|
|
1240
1222
|
/** Uses an end-user token; the configured environment key selects the environment. */
|
|
1241
1223
|
user(token) {
|
|
1242
|
-
return new UserScopedClient((
|
|
1224
|
+
return new UserScopedClient((path2, options) => this.request(path2, options), token);
|
|
1243
1225
|
}
|
|
1244
1226
|
/** @internal used by {@link TenantScopedClient} to share the base URL/fetch/error handling. */
|
|
1245
|
-
_requestAsTenant(accessToken,
|
|
1246
|
-
return this.request(
|
|
1227
|
+
_requestAsTenant(accessToken, path2, options = {}) {
|
|
1228
|
+
return this.request(path2, {
|
|
1247
1229
|
...options,
|
|
1248
1230
|
headers: { ...options.headers, Authorization: `Bearer ${accessToken}` },
|
|
1249
1231
|
envBearer: false
|
|
@@ -1320,8 +1302,8 @@ var TenantScopedClient = class {
|
|
|
1320
1302
|
async getAccessToken() {
|
|
1321
1303
|
return this.tokenProvider.getAccessToken();
|
|
1322
1304
|
}
|
|
1323
|
-
async request(
|
|
1324
|
-
return this.server._requestAsTenant(await this.getAccessToken(),
|
|
1305
|
+
async request(path2, options = {}) {
|
|
1306
|
+
return this.server._requestAsTenant(await this.getAccessToken(), path2, options);
|
|
1325
1307
|
}
|
|
1326
1308
|
/** POST /tenant/auth/validate — validates this tenant client's current bearer token. */
|
|
1327
1309
|
async validate(context) {
|
|
@@ -1494,18 +1476,18 @@ function matchesField(pattern, field) {
|
|
|
1494
1476
|
return pattern.endsWith(".*") && field.startsWith(pattern.slice(0, -1));
|
|
1495
1477
|
}
|
|
1496
1478
|
function matchesConditions(subject, conditions) {
|
|
1497
|
-
return Object.entries(conditions).every(([
|
|
1498
|
-
if (
|
|
1479
|
+
return Object.entries(conditions).every(([path2, expected]) => {
|
|
1480
|
+
if (path2 === "$and" && Array.isArray(expected)) {
|
|
1499
1481
|
return expected.every(
|
|
1500
1482
|
(condition) => matchesConditions(subject, condition)
|
|
1501
1483
|
);
|
|
1502
1484
|
}
|
|
1503
|
-
if (
|
|
1485
|
+
if (path2 === "$or" && Array.isArray(expected)) {
|
|
1504
1486
|
return expected.some(
|
|
1505
1487
|
(condition) => matchesConditions(subject, condition)
|
|
1506
1488
|
);
|
|
1507
1489
|
}
|
|
1508
|
-
return matchesValue(readPath(subject,
|
|
1490
|
+
return matchesValue(readPath(subject, path2), expected);
|
|
1509
1491
|
});
|
|
1510
1492
|
}
|
|
1511
1493
|
function matchesValue(actual, expected) {
|
|
@@ -1537,8 +1519,8 @@ function matchesValue(actual, expected) {
|
|
|
1537
1519
|
}
|
|
1538
1520
|
});
|
|
1539
1521
|
}
|
|
1540
|
-
function readPath(value,
|
|
1541
|
-
return
|
|
1522
|
+
function readPath(value, path2) {
|
|
1523
|
+
return path2.split(".").reduce((current, part) => isRecord2(current) ? current[part] : void 0, value);
|
|
1542
1524
|
}
|
|
1543
1525
|
function defaultSubjectType(subject) {
|
|
1544
1526
|
const explicit = subject.__type ?? subject.type ?? subject.kind;
|
|
@@ -1692,11 +1674,9 @@ function unauthenticated() {
|
|
|
1692
1674
|
FetchHttpAdapter,
|
|
1693
1675
|
JwksTokenVerifier,
|
|
1694
1676
|
LoggingHttpAdapter,
|
|
1695
|
-
PlatformScopedClient,
|
|
1696
1677
|
TenantScopedClient,
|
|
1697
1678
|
TokenVerificationError,
|
|
1698
1679
|
UserScopedClient,
|
|
1699
|
-
WorkspaceInvitesClient,
|
|
1700
1680
|
authorizeRequest,
|
|
1701
1681
|
authorizeToken,
|
|
1702
1682
|
createAuthorizationErrorResponse,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-
|
|
2
|
-
export { b as
|
|
3
|
-
export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRequirement, f as AbilityRule, A as AbilitySubject, g as AuthorizationContext, a as AuthorizationError, h as AuthorizationOptions, i as AuthyonAbility, j as AuthyonAbilityBuilder, k as AuthyonAbilityOptions, l as AuthyonPermissionSource, E as ExpressAuthorizationMiddlewareOptions, m as ExpressNext, n as ExpressRequestLike, o as ExpressResponseLike, P as PermissionGroup, R as RequestAuthorizationOptions, p as authorizeRequest, q as authorizeToken, r as createAuthorizationErrorResponse, s as createAuthyonAbility, t as createAuthyonRules, u as createExpressAuthorizationMiddleware, v as hasPermission, w as hasPermissionGroup } from './authorization-
|
|
1
|
+
import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-DmNnjw4z.cjs';
|
|
2
|
+
export { b as AccessTokenSource, c as AuditEvent, d as AuthyonJwksDiscoveryOptions, e as AuthyonJwtClaims, f as AuthyonServerClientOptions, C as ClientCredentials, g as ClientRequestContext, h as ConfirmFinancialAuthorizationInput, i as ConsumedFinancialAuthorization, j as CreateCredentialInput, k as CreateFinancialAuthorizationInput, l as CreateOrganizationInput, m as CreatePermissionInput, n as CreateTenantCredentialInput, o as CreateUserInput, p as CredentialCreator, q as CredentialDetail, r as CredentialListOptions, s as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, t as FinancialAssurance, u as FinancialAuthorization, v as FinancialAuthorizationStatus, w as FinancialTransaction, x as FinancialWebAuthnOptions, y as HttpAdapterRequest, z as HttpLogEvent, B as HttpLogger, I as IntrospectResult, D as InviteTenantMemberInput, J as JsonWebKeySet, G as JwksTokenVerifier, K as JwksTokenVerifierOptions, L as LoggingHttpAdapter, M as LoginActivity, O as OpenIdConfiguration, N as Organization, P as Paged, Q as PaginationOptions, R as Permission, S as PermissionsByRole, T as ReservedPermissions, U as Role, V as RoleGrant, W as RoleInput, X as RoleList, Y as RolePermissions, Z as SafeJwtAlgorithm, _ as TenantClientValidationResult, $ as TenantCredentialIssued, a0 as TenantCredentialSummary, a1 as TenantMember, a2 as TenantMemberPage, a3 as TenantMembership, a4 as TenantScopedClient, a5 as TokenResult, a6 as TokenVerificationError, a7 as TokenVerificationErrorCode, a8 as UpdateOrganizationInput, a9 as User, aa as UserScopedClient, ab as ValidateResult, ac as VerifiedAccessToken, ad as createClient, ae as normalizeClientIp } from './authyonServerClient-DmNnjw4z.cjs';
|
|
3
|
+
export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRequirement, f as AbilityRule, A as AbilitySubject, g as AuthorizationContext, a as AuthorizationError, h as AuthorizationOptions, i as AuthyonAbility, j as AuthyonAbilityBuilder, k as AuthyonAbilityOptions, l as AuthyonPermissionSource, E as ExpressAuthorizationMiddlewareOptions, m as ExpressNext, n as ExpressRequestLike, o as ExpressResponseLike, P as PermissionGroup, R as RequestAuthorizationOptions, p as authorizeRequest, q as authorizeToken, r as createAuthorizationErrorResponse, s as createAuthyonAbility, t as createAuthyonRules, u as createExpressAuthorizationMiddleware, v as hasPermission, w as hasPermissionGroup } from './authorization-B7ynKAud.cjs';
|
|
4
4
|
import 'jose';
|
|
5
5
|
|
|
6
6
|
declare const ErrorCodes: {
|
|
@@ -15,6 +15,14 @@ declare const ErrorCodes: {
|
|
|
15
15
|
readonly PasswordWeak: "user.password_weak";
|
|
16
16
|
readonly PasswordPwned: "user.password_pwned";
|
|
17
17
|
readonly RateLimited: "rate_limited";
|
|
18
|
+
readonly StepUpRequired: "step_up_required";
|
|
19
|
+
readonly InvalidSecondFactorCode: "invalid_code";
|
|
20
|
+
readonly VerificationAttemptsExhausted: "verification_attempts_exhausted";
|
|
21
|
+
readonly MethodNotEnrolled: "method_not_enrolled";
|
|
22
|
+
readonly InvalidAuthorizationState: "invalid_authorization_state";
|
|
23
|
+
readonly TransactionMismatch: "transaction_mismatch";
|
|
24
|
+
readonly AuthorizationNotConsumable: "authorization_not_consumable";
|
|
25
|
+
readonly IdempotencyConflict: "idempotency_conflict";
|
|
18
26
|
};
|
|
19
27
|
type KnownErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|
|
20
28
|
type AuthyonErrorCategory = "network" | "timeout" | "authentication" | "authorization" | "validation" | "not_found" | "conflict" | "rate_limit" | "server" | "unknown";
|
|
@@ -26,6 +34,14 @@ interface AuthyonErrorInterpretation {
|
|
|
26
34
|
retryAfter?: number;
|
|
27
35
|
requestId?: string;
|
|
28
36
|
}
|
|
37
|
+
/** Error body as sent by the API: RFC 7807, or OAuth-style `error`/`error_description`. */
|
|
38
|
+
type AuthyonErrorBody = Partial<{
|
|
39
|
+
title: string;
|
|
40
|
+
detail: string;
|
|
41
|
+
code: string;
|
|
42
|
+
error: string;
|
|
43
|
+
error_description: string;
|
|
44
|
+
}> & Record<string, unknown>;
|
|
29
45
|
/** Shared RFC 7807 error implementation used by both public SDKs. */
|
|
30
46
|
declare class AuthyonError extends Error {
|
|
31
47
|
readonly status: number;
|
|
@@ -35,11 +51,13 @@ declare class AuthyonError extends Error {
|
|
|
35
51
|
readonly requestId?: string;
|
|
36
52
|
readonly retryAfter?: number;
|
|
37
53
|
readonly cause?: unknown;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Extra fields from the error body beyond code/title/detail — e.g.
|
|
56
|
+
* `attemptsRemaining` on `invalid_code` or `requiredMethods` on
|
|
57
|
+
* `step_up_required`. Not included in {@link toJSON}.
|
|
58
|
+
*/
|
|
59
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
60
|
+
constructor(status: number, body: AuthyonErrorBody, options?: {
|
|
43
61
|
requestId?: string;
|
|
44
62
|
retryAfter?: number;
|
|
45
63
|
cause?: unknown;
|
|
@@ -68,4 +86,4 @@ declare class AuthyonServerClientBuilder {
|
|
|
68
86
|
build(): AuthyonServerClient;
|
|
69
87
|
}
|
|
70
88
|
|
|
71
|
-
export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };
|
|
89
|
+
export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-
|
|
2
|
-
export { b as
|
|
3
|
-
export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRequirement, f as AbilityRule, A as AbilitySubject, g as AuthorizationContext, a as AuthorizationError, h as AuthorizationOptions, i as AuthyonAbility, j as AuthyonAbilityBuilder, k as AuthyonAbilityOptions, l as AuthyonPermissionSource, E as ExpressAuthorizationMiddlewareOptions, m as ExpressNext, n as ExpressRequestLike, o as ExpressResponseLike, P as PermissionGroup, R as RequestAuthorizationOptions, p as authorizeRequest, q as authorizeToken, r as createAuthorizationErrorResponse, s as createAuthyonAbility, t as createAuthyonRules, u as createExpressAuthorizationMiddleware, v as hasPermission, w as hasPermissionGroup } from './authorization-
|
|
1
|
+
import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-DmNnjw4z.js';
|
|
2
|
+
export { b as AccessTokenSource, c as AuditEvent, d as AuthyonJwksDiscoveryOptions, e as AuthyonJwtClaims, f as AuthyonServerClientOptions, C as ClientCredentials, g as ClientRequestContext, h as ConfirmFinancialAuthorizationInput, i as ConsumedFinancialAuthorization, j as CreateCredentialInput, k as CreateFinancialAuthorizationInput, l as CreateOrganizationInput, m as CreatePermissionInput, n as CreateTenantCredentialInput, o as CreateUserInput, p as CredentialCreator, q as CredentialDetail, r as CredentialListOptions, s as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, t as FinancialAssurance, u as FinancialAuthorization, v as FinancialAuthorizationStatus, w as FinancialTransaction, x as FinancialWebAuthnOptions, y as HttpAdapterRequest, z as HttpLogEvent, B as HttpLogger, I as IntrospectResult, D as InviteTenantMemberInput, J as JsonWebKeySet, G as JwksTokenVerifier, K as JwksTokenVerifierOptions, L as LoggingHttpAdapter, M as LoginActivity, O as OpenIdConfiguration, N as Organization, P as Paged, Q as PaginationOptions, R as Permission, S as PermissionsByRole, T as ReservedPermissions, U as Role, V as RoleGrant, W as RoleInput, X as RoleList, Y as RolePermissions, Z as SafeJwtAlgorithm, _ as TenantClientValidationResult, $ as TenantCredentialIssued, a0 as TenantCredentialSummary, a1 as TenantMember, a2 as TenantMemberPage, a3 as TenantMembership, a4 as TenantScopedClient, a5 as TokenResult, a6 as TokenVerificationError, a7 as TokenVerificationErrorCode, a8 as UpdateOrganizationInput, a9 as User, aa as UserScopedClient, ab as ValidateResult, ac as VerifiedAccessToken, ad as createClient, ae as normalizeClientIp } from './authyonServerClient-DmNnjw4z.js';
|
|
3
|
+
export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRequirement, f as AbilityRule, A as AbilitySubject, g as AuthorizationContext, a as AuthorizationError, h as AuthorizationOptions, i as AuthyonAbility, j as AuthyonAbilityBuilder, k as AuthyonAbilityOptions, l as AuthyonPermissionSource, E as ExpressAuthorizationMiddlewareOptions, m as ExpressNext, n as ExpressRequestLike, o as ExpressResponseLike, P as PermissionGroup, R as RequestAuthorizationOptions, p as authorizeRequest, q as authorizeToken, r as createAuthorizationErrorResponse, s as createAuthyonAbility, t as createAuthyonRules, u as createExpressAuthorizationMiddleware, v as hasPermission, w as hasPermissionGroup } from './authorization-BF015NDJ.js';
|
|
4
4
|
import 'jose';
|
|
5
5
|
|
|
6
6
|
declare const ErrorCodes: {
|
|
@@ -15,6 +15,14 @@ declare const ErrorCodes: {
|
|
|
15
15
|
readonly PasswordWeak: "user.password_weak";
|
|
16
16
|
readonly PasswordPwned: "user.password_pwned";
|
|
17
17
|
readonly RateLimited: "rate_limited";
|
|
18
|
+
readonly StepUpRequired: "step_up_required";
|
|
19
|
+
readonly InvalidSecondFactorCode: "invalid_code";
|
|
20
|
+
readonly VerificationAttemptsExhausted: "verification_attempts_exhausted";
|
|
21
|
+
readonly MethodNotEnrolled: "method_not_enrolled";
|
|
22
|
+
readonly InvalidAuthorizationState: "invalid_authorization_state";
|
|
23
|
+
readonly TransactionMismatch: "transaction_mismatch";
|
|
24
|
+
readonly AuthorizationNotConsumable: "authorization_not_consumable";
|
|
25
|
+
readonly IdempotencyConflict: "idempotency_conflict";
|
|
18
26
|
};
|
|
19
27
|
type KnownErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|
|
20
28
|
type AuthyonErrorCategory = "network" | "timeout" | "authentication" | "authorization" | "validation" | "not_found" | "conflict" | "rate_limit" | "server" | "unknown";
|
|
@@ -26,6 +34,14 @@ interface AuthyonErrorInterpretation {
|
|
|
26
34
|
retryAfter?: number;
|
|
27
35
|
requestId?: string;
|
|
28
36
|
}
|
|
37
|
+
/** Error body as sent by the API: RFC 7807, or OAuth-style `error`/`error_description`. */
|
|
38
|
+
type AuthyonErrorBody = Partial<{
|
|
39
|
+
title: string;
|
|
40
|
+
detail: string;
|
|
41
|
+
code: string;
|
|
42
|
+
error: string;
|
|
43
|
+
error_description: string;
|
|
44
|
+
}> & Record<string, unknown>;
|
|
29
45
|
/** Shared RFC 7807 error implementation used by both public SDKs. */
|
|
30
46
|
declare class AuthyonError extends Error {
|
|
31
47
|
readonly status: number;
|
|
@@ -35,11 +51,13 @@ declare class AuthyonError extends Error {
|
|
|
35
51
|
readonly requestId?: string;
|
|
36
52
|
readonly retryAfter?: number;
|
|
37
53
|
readonly cause?: unknown;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Extra fields from the error body beyond code/title/detail — e.g.
|
|
56
|
+
* `attemptsRemaining` on `invalid_code` or `requiredMethods` on
|
|
57
|
+
* `step_up_required`. Not included in {@link toJSON}.
|
|
58
|
+
*/
|
|
59
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
60
|
+
constructor(status: number, body: AuthyonErrorBody, options?: {
|
|
43
61
|
requestId?: string;
|
|
44
62
|
retryAfter?: number;
|
|
45
63
|
cause?: unknown;
|
|
@@ -68,4 +86,4 @@ declare class AuthyonServerClientBuilder {
|
|
|
68
86
|
build(): AuthyonServerClient;
|
|
69
87
|
}
|
|
70
88
|
|
|
71
|
-
export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };
|
|
89
|
+
export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };
|