@authyon/server 0.2.0-beta.14 → 0.2.0-beta.16
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 +72 -23
- package/dist/{authorization-BF015NDJ.d.ts → authorization-BvjIWPcU.d.ts} +1 -1
- package/dist/{authorization-B7ynKAud.d.cts → authorization-C0Mg5gUv.d.cts} +1 -1
- package/dist/{authyonServerClient-DmNnjw4z.d.cts → authyonServerClient-1_1qNRDa.d.cts} +333 -118
- package/dist/{authyonServerClient-DmNnjw4z.d.ts → authyonServerClient-1_1qNRDa.d.ts} +333 -118
- package/dist/bff.cjs +12 -4
- package/dist/bff.d.cts +1 -1
- package/dist/bff.d.ts +1 -1
- package/dist/bff.js +1 -1
- package/dist/{chunk-TWUVXZOT.js → chunk-TDJNBD3Z.js} +12 -4
- package/dist/index.cjs +179 -45
- package/dist/index.d.cts +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.js +168 -42
- package/dist/next.d.cts +2 -2
- package/dist/next.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
JsonHttpClient,
|
|
8
8
|
LoggingHttpAdapter,
|
|
9
9
|
createSharedTransport
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TDJNBD3Z.js";
|
|
11
11
|
import {
|
|
12
12
|
AuthorizationError,
|
|
13
13
|
AuthyonAbility,
|
|
@@ -146,29 +146,34 @@ async function allCredentials(request, path2) {
|
|
|
146
146
|
throw new Error("Authyon: use listPage for more than 1000 credential pages.");
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
// ../../internal/core/
|
|
149
|
+
// ../../internal/core/security/approvals.ts
|
|
150
150
|
function path(id, suffix = "") {
|
|
151
151
|
if (typeof id !== "string" || !id.trim())
|
|
152
|
-
throw new TypeError("Authyon:
|
|
152
|
+
throw new TypeError("Authyon: an approval id is required.");
|
|
153
153
|
return `/auth/authorizations/${encodeURIComponent(id)}${suffix}`;
|
|
154
154
|
}
|
|
155
|
-
|
|
155
|
+
var NO_METHODS = {
|
|
156
|
+
password: false,
|
|
157
|
+
authenticator: false,
|
|
158
|
+
emailCode: false,
|
|
159
|
+
passkey: false,
|
|
160
|
+
passkeyCount: 0,
|
|
161
|
+
recoveryCodes: 0,
|
|
162
|
+
sso: [],
|
|
163
|
+
twoFactor: false
|
|
164
|
+
};
|
|
165
|
+
function subjectSecurity(request) {
|
|
156
166
|
return {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
* otherwise the API answers `step_up_required`.
|
|
168
|
-
*/
|
|
169
|
-
confirm: (id, input) => request(path(id, "/confirm"), { method: "POST", body: input }),
|
|
170
|
-
/** POST /auth/authorizations/{id}/reject — the customer declines the transaction. */
|
|
171
|
-
reject: (id) => request(path(id, "/reject"), { method: "POST" })
|
|
167
|
+
methods: async () => {
|
|
168
|
+
const me = await request("/auth/me");
|
|
169
|
+
return me.security ?? NO_METHODS;
|
|
170
|
+
},
|
|
171
|
+
approvals: {
|
|
172
|
+
get: (id) => request(path(id)),
|
|
173
|
+
webauthnOptions: (id) => request(path(id, "/webauthn/options"), { method: "POST" }),
|
|
174
|
+
confirm: (id, input) => request(path(id, "/confirm"), { method: "POST", body: input }),
|
|
175
|
+
reject: (id) => request(path(id, "/reject"), { method: "POST" })
|
|
176
|
+
}
|
|
172
177
|
};
|
|
173
178
|
}
|
|
174
179
|
|
|
@@ -200,10 +205,35 @@ var UserScopedClient = class {
|
|
|
200
205
|
remove: (tenantId, userId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members/${segment(userId)}`, {
|
|
201
206
|
method: "DELETE"
|
|
202
207
|
})
|
|
208
|
+
},
|
|
209
|
+
/**
|
|
210
|
+
* Invites by e-mail or by link, acting as the user. Requires the
|
|
211
|
+
* `tenants:members:invite` permission on the tenant.
|
|
212
|
+
*/
|
|
213
|
+
invites: {
|
|
214
|
+
list: (tenantId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/invites`),
|
|
215
|
+
/** Always returns `acceptUrl`; `sendEmail: false` skips the e-mail. */
|
|
216
|
+
create: (tenantId, input) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/invites`, {
|
|
217
|
+
method: "POST",
|
|
218
|
+
body: {
|
|
219
|
+
email: input.email,
|
|
220
|
+
roles: input.roles,
|
|
221
|
+
sendEmail: input.sendEmail ?? true,
|
|
222
|
+
redirectUri: input.redirectUri
|
|
223
|
+
}
|
|
224
|
+
}),
|
|
225
|
+
/** New link (the previous one stops working), mailed unless `sendEmail` is `false`. */
|
|
226
|
+
resend: (tenantId, inviteId, input = {}) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/invites/${segment(inviteId)}/resend`, {
|
|
227
|
+
method: "POST",
|
|
228
|
+
body: { sendEmail: input.sendEmail ?? true }
|
|
229
|
+
}),
|
|
230
|
+
revoke: (tenantId, inviteId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/invites/${segment(inviteId)}`, {
|
|
231
|
+
method: "DELETE"
|
|
232
|
+
})
|
|
203
233
|
}
|
|
204
234
|
};
|
|
205
235
|
__privateSet(this, _request, scopedRequest(request, token));
|
|
206
|
-
this.
|
|
236
|
+
this.security = subjectSecurity(__privateGet(this, _request));
|
|
207
237
|
}
|
|
208
238
|
};
|
|
209
239
|
_request = new WeakMap();
|
|
@@ -493,6 +523,61 @@ var AuthyonServerClient = class {
|
|
|
493
523
|
{ method: "DELETE", envBearer: true }
|
|
494
524
|
)
|
|
495
525
|
},
|
|
526
|
+
/**
|
|
527
|
+
* Invites by e-mail or by link — for addresses that may not have an
|
|
528
|
+
* account yet; accepting creates it. Managing them needs the
|
|
529
|
+
* credential's `authyon:users:write` scope (listing, `authyon:tenants:read`).
|
|
530
|
+
*/
|
|
531
|
+
invites: {
|
|
532
|
+
/** GET /env/tenants/{tenantId}/invites — every invite with its status, newest first. */
|
|
533
|
+
list: (tenantId) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}/invites`, { envBearer: true }),
|
|
534
|
+
/**
|
|
535
|
+
* POST /env/tenants/{tenantId}/invites — invite an address. Always
|
|
536
|
+
* returns `acceptUrl`; with `sendEmail: false` Authyon does not mail
|
|
537
|
+
* it and you deliver the link yourself. Valid 7 days, single use, and
|
|
538
|
+
* not readable again later.
|
|
539
|
+
*/
|
|
540
|
+
create: (tenantId, input) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}/invites`, {
|
|
541
|
+
method: "POST",
|
|
542
|
+
envBearer: true,
|
|
543
|
+
body: {
|
|
544
|
+
email: input.email,
|
|
545
|
+
roles: input.roles,
|
|
546
|
+
sendEmail: input.sendEmail ?? true,
|
|
547
|
+
redirectUri: input.redirectUri
|
|
548
|
+
}
|
|
549
|
+
}),
|
|
550
|
+
/** POST .../invites/{inviteId}/resend — new link (the previous one stops working), mailed unless `sendEmail` is `false`. */
|
|
551
|
+
resend: (tenantId, inviteId, input = {}) => this.request(
|
|
552
|
+
`/env/tenants/${encodeURIComponent(tenantId)}/invites/${encodeURIComponent(inviteId)}/resend`,
|
|
553
|
+
{ method: "POST", envBearer: true, body: { sendEmail: input.sendEmail ?? true } }
|
|
554
|
+
),
|
|
555
|
+
/** DELETE /env/tenants/{tenantId}/invites/{inviteId} — revoke a pending invite. */
|
|
556
|
+
revoke: (tenantId, inviteId) => this.request(
|
|
557
|
+
`/env/tenants/${encodeURIComponent(tenantId)}/invites/${encodeURIComponent(inviteId)}`,
|
|
558
|
+
{ method: "DELETE", envBearer: true }
|
|
559
|
+
),
|
|
560
|
+
/**
|
|
561
|
+
* POST /auth/tenant-invites/preview — for a backend hosting the accept
|
|
562
|
+
* page. Public: needs only `envKey`, the token is the credential.
|
|
563
|
+
*/
|
|
564
|
+
preview: (token) => this.request("/auth/tenant-invites/preview", { method: "POST", body: { token } }),
|
|
565
|
+
/**
|
|
566
|
+
* Joins the tenant; for an address with no account, also creates it
|
|
567
|
+
* (password required) with the e-mail already confirmed. Does not
|
|
568
|
+
* sign the user in.
|
|
569
|
+
*
|
|
570
|
+
* Without metadata: POST /auth/tenant-invites/accept — public, needs
|
|
571
|
+
* only `envKey`. With `publicMetadata`/`privateMetadata`: POST
|
|
572
|
+
* /env/tenant-invites/accept with the environment credential
|
|
573
|
+
* (`authyon:users:write`), since only your backend may set them.
|
|
574
|
+
*/
|
|
575
|
+
accept: (input) => input.publicMetadata !== void 0 || input.privateMetadata !== void 0 ? this.request("/env/tenant-invites/accept", {
|
|
576
|
+
method: "POST",
|
|
577
|
+
envBearer: true,
|
|
578
|
+
body: input
|
|
579
|
+
}) : this.request("/auth/tenant-invites/accept", { method: "POST", body: input })
|
|
580
|
+
},
|
|
496
581
|
roles: {
|
|
497
582
|
/** GET /env/tenants/{tenantId}/roles — list a tenant's roles. */
|
|
498
583
|
list: (tenantId) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}/roles`, { envBearer: true }),
|
|
@@ -555,46 +640,65 @@ var AuthyonServerClient = class {
|
|
|
555
640
|
/** GET /permissions/reserved — reserved permission names you can't redefine. */
|
|
556
641
|
reserved: () => this.request("/permissions/reserved", { envBearer: true })
|
|
557
642
|
},
|
|
643
|
+
audit: {
|
|
644
|
+
/** GET /env/audit — paginated list of the environment's audit events. */
|
|
645
|
+
list: (params = {}) => this.request("/env/audit", { envBearer: true, query: params }),
|
|
646
|
+
/** GET /env/audit/login-activity — paginated login activity in the environment. */
|
|
647
|
+
loginActivity: (params = {}) => this.request("/env/audit/login-activity", { envBearer: true, query: params })
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
// ── Security: one-time codes and approvals ───────────────────────────────
|
|
651
|
+
//
|
|
652
|
+
// Everything here runs with the environment credential: `otp` needs the
|
|
653
|
+
// `authyon:otp:verify` scope, `approvals` needs `authyon:financial:authorize`.
|
|
654
|
+
// Keep those credentials on the server.
|
|
655
|
+
this.security = {
|
|
656
|
+
otp: {
|
|
657
|
+
/**
|
|
658
|
+
* POST /env/users/{userId}/otp/verify — checks the user's authenticator
|
|
659
|
+
* app (TOTP) code. A wrong code returns `{ valid: false }` instead of
|
|
660
|
+
* throwing. Each code is accepted once; 3 wrong codes in a row sign the
|
|
661
|
+
* user out everywhere (`sessionsRevoked: true`); 5 lock the check for 15
|
|
662
|
+
* minutes (`rate_limited`). More than 50 wrong codes in 10 minutes from the
|
|
663
|
+
* same credential pause it (`credential_throttled`). Needs `authyon:otp:verify`.
|
|
664
|
+
*/
|
|
665
|
+
check: (userId, code) => this.request(`/env/users/${segment(userId)}/otp/verify`, {
|
|
666
|
+
method: "POST",
|
|
667
|
+
envBearer: true,
|
|
668
|
+
body: { code }
|
|
669
|
+
})
|
|
670
|
+
},
|
|
558
671
|
/**
|
|
559
|
-
*
|
|
560
|
-
*
|
|
672
|
+
* The customer approves a payload with their authenticator code or
|
|
673
|
+
* passkey, once.
|
|
561
674
|
*
|
|
562
|
-
* 1. `create()` the
|
|
563
|
-
* 2. The customer
|
|
564
|
-
*
|
|
565
|
-
* 3. `consume()` it with the same transaction right before executing it.
|
|
675
|
+
* 1. `create()` the approval with the payload and the customer.
|
|
676
|
+
* 2. The customer confirms it (`@authyon/auth` → `security.approvals.confirm`).
|
|
677
|
+
* 3. `consume()` it right before executing, and execute the returned payload.
|
|
566
678
|
*/
|
|
567
|
-
|
|
568
|
-
/** POST /env/authorizations — registers a
|
|
679
|
+
approvals: {
|
|
680
|
+
/** POST /env/authorizations — registers a payload awaiting the customer's approval. */
|
|
569
681
|
create: (input) => {
|
|
570
682
|
const { idempotencyKey, ...body } = input;
|
|
571
|
-
if (typeof idempotencyKey !== "string" || !idempotencyKey.trim())
|
|
572
|
-
throw new TypeError("Authyon: `idempotencyKey` is required.");
|
|
573
683
|
return this.request("/env/authorizations", {
|
|
574
684
|
method: "POST",
|
|
575
685
|
envBearer: true,
|
|
576
|
-
headers: { "Idempotency-Key": idempotencyKey },
|
|
686
|
+
headers: idempotencyKey ? { "Idempotency-Key": idempotencyKey } : void 0,
|
|
577
687
|
body
|
|
578
688
|
});
|
|
579
689
|
},
|
|
580
690
|
/** GET /env/authorizations/{id} — current status and, once approved, the assurance evidence. */
|
|
581
691
|
get: (id) => this.request(`/env/authorizations/${segment(id)}`, { envBearer: true }),
|
|
582
692
|
/**
|
|
583
|
-
* POST /env/authorizations/{id}/consume — redeems an approved
|
|
584
|
-
*
|
|
585
|
-
*
|
|
693
|
+
* POST /env/authorizations/{id}/consume — redeems an approved approval
|
|
694
|
+
* exactly once and returns the approved payload. Pass `payload` to have
|
|
695
|
+
* the API check it matches (`payload_mismatch` otherwise).
|
|
586
696
|
*/
|
|
587
|
-
consume: (id,
|
|
697
|
+
consume: (id, payload) => this.request(`/env/authorizations/${segment(id)}/consume`, {
|
|
588
698
|
method: "POST",
|
|
589
699
|
envBearer: true,
|
|
590
|
-
body:
|
|
700
|
+
body: payload === void 0 ? void 0 : { payload }
|
|
591
701
|
})
|
|
592
|
-
},
|
|
593
|
-
audit: {
|
|
594
|
-
/** GET /env/audit — paginated list of the environment's audit events. */
|
|
595
|
-
list: (params = {}) => this.request("/env/audit", { envBearer: true, query: params }),
|
|
596
|
-
/** GET /env/audit/login-activity — paginated login activity in the environment. */
|
|
597
|
-
loginActivity: (params = {}) => this.request("/env/audit/login-activity", { envBearer: true, query: params })
|
|
598
702
|
}
|
|
599
703
|
};
|
|
600
704
|
// ── Generic permission grants ─────────────────────────────────────────────
|
|
@@ -720,6 +824,28 @@ var AuthyonServerClient = class {
|
|
|
720
824
|
_clientSecret = new WeakMap();
|
|
721
825
|
var TenantScopedClient = class {
|
|
722
826
|
constructor(server, credentials) {
|
|
827
|
+
/** Invites to the token's tenant, by e-mail or by link. */
|
|
828
|
+
this.invites = {
|
|
829
|
+
/** GET /tenant/invites — every invite with its status, newest first. */
|
|
830
|
+
list: () => this.request("/tenant/invites"),
|
|
831
|
+
/** POST /tenant/invites — always returns `acceptUrl`; `sendEmail: false` skips the e-mail. */
|
|
832
|
+
create: (input) => this.request("/tenant/invites", {
|
|
833
|
+
method: "POST",
|
|
834
|
+
body: {
|
|
835
|
+
email: input.email,
|
|
836
|
+
roles: input.roles,
|
|
837
|
+
sendEmail: input.sendEmail ?? true,
|
|
838
|
+
redirectUri: input.redirectUri
|
|
839
|
+
}
|
|
840
|
+
}),
|
|
841
|
+
/** POST /tenant/invites/{inviteId}/resend — new link (the previous one stops working), mailed unless `sendEmail` is `false`. */
|
|
842
|
+
resend: (inviteId, input = {}) => this.request(`/tenant/invites/${encodeURIComponent(inviteId)}/resend`, {
|
|
843
|
+
method: "POST",
|
|
844
|
+
body: { sendEmail: input.sendEmail ?? true }
|
|
845
|
+
}),
|
|
846
|
+
/** DELETE /tenant/invites/{inviteId} — revoke a pending invite. */
|
|
847
|
+
revoke: (inviteId) => this.request(`/tenant/invites/${encodeURIComponent(inviteId)}`, { method: "DELETE" })
|
|
848
|
+
};
|
|
723
849
|
this.members = {
|
|
724
850
|
/**
|
|
725
851
|
* GET /tenant/members — members of the token's tenant.
|
package/dist/next.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { R as RequestAuthorizationOptions, A as AbilitySubject, a as AuthorizationError } from './authorization-
|
|
3
|
-
import { A as AuthyonServerClient } from './authyonServerClient-
|
|
2
|
+
import { R as RequestAuthorizationOptions, A as AbilitySubject, a as AuthorizationError } from './authorization-C0Mg5gUv.cjs';
|
|
3
|
+
import { A as AuthyonServerClient } from './authyonServerClient-1_1qNRDa.cjs';
|
|
4
4
|
import 'jose';
|
|
5
5
|
|
|
6
6
|
interface ServerPermissionGuardFallbackContext {
|
package/dist/next.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { R as RequestAuthorizationOptions, A as AbilitySubject, a as AuthorizationError } from './authorization-
|
|
3
|
-
import { A as AuthyonServerClient } from './authyonServerClient-
|
|
2
|
+
import { R as RequestAuthorizationOptions, A as AbilitySubject, a as AuthorizationError } from './authorization-BvjIWPcU.js';
|
|
3
|
+
import { A as AuthyonServerClient } from './authyonServerClient-1_1qNRDa.js';
|
|
4
4
|
import 'jose';
|
|
5
5
|
|
|
6
6
|
interface ServerPermissionGuardFallbackContext {
|
package/package.json
CHANGED