@authyon/server 0.2.0-beta.15 → 0.2.0-beta.17

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 CHANGED
@@ -174,8 +174,22 @@ function path(id, suffix = "") {
174
174
  throw new TypeError("Authyon: an approval id is required.");
175
175
  return `/auth/authorizations/${encodeURIComponent(id)}${suffix}`;
176
176
  }
177
+ var NO_METHODS = {
178
+ password: false,
179
+ authenticator: false,
180
+ emailCode: false,
181
+ passkey: false,
182
+ passkeyCount: 0,
183
+ recoveryCodes: 0,
184
+ sso: [],
185
+ twoFactor: false
186
+ };
177
187
  function subjectSecurity(request) {
178
188
  return {
189
+ methods: async () => {
190
+ const me = await request("/auth/me");
191
+ return me.security ?? NO_METHODS;
192
+ },
179
193
  approvals: {
180
194
  get: (id) => request(path(id)),
181
195
  webauthnOptions: (id) => request(path(id, "/webauthn/options"), { method: "POST" }),
@@ -213,6 +227,31 @@ var UserScopedClient = class {
213
227
  remove: (tenantId, userId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members/${segment(userId)}`, {
214
228
  method: "DELETE"
215
229
  })
230
+ },
231
+ /**
232
+ * Invites by e-mail or by link, acting as the user. Requires the
233
+ * `tenants:members:invite` permission on the tenant.
234
+ */
235
+ invites: {
236
+ list: (tenantId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/invites`),
237
+ /** Always returns `acceptUrl`; `sendEmail: false` skips the e-mail. */
238
+ create: (tenantId, input) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/invites`, {
239
+ method: "POST",
240
+ body: {
241
+ email: input.email,
242
+ roles: input.roles,
243
+ sendEmail: input.sendEmail ?? true,
244
+ redirectUri: input.redirectUri
245
+ }
246
+ }),
247
+ /** New link (the previous one stops working), mailed unless `sendEmail` is `false`. */
248
+ resend: (tenantId, inviteId, input = {}) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/invites/${segment(inviteId)}/resend`, {
249
+ method: "POST",
250
+ body: { sendEmail: input.sendEmail ?? true }
251
+ }),
252
+ revoke: (tenantId, inviteId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/invites/${segment(inviteId)}`, {
253
+ method: "DELETE"
254
+ })
216
255
  }
217
256
  };
218
257
  __privateSet(this, _request, scopedRequest(request, token));
@@ -279,6 +318,7 @@ var ErrorCodes = {
279
318
  UserNotFound: "user_not_found",
280
319
  TemporarilyUnavailable: "temporarily_unavailable",
281
320
  InsufficientScope: "insufficient_scope",
321
+ CredentialThrottled: "credential_throttled",
282
322
  ApprovalNotFound: "authorization_not_found",
283
323
  SessionRevoked: "session_revoked",
284
324
  TwoFactorTooManyFailures: "user.2fa.too_many_failures"
@@ -1006,6 +1046,61 @@ var AuthyonServerClient = class {
1006
1046
  { method: "DELETE", envBearer: true }
1007
1047
  )
1008
1048
  },
1049
+ /**
1050
+ * Invites by e-mail or by link — for addresses that may not have an
1051
+ * account yet; accepting creates it. Managing them needs the
1052
+ * credential's `authyon:users:write` scope (listing, `authyon:tenants:read`).
1053
+ */
1054
+ invites: {
1055
+ /** GET /env/tenants/{tenantId}/invites — every invite with its status, newest first. */
1056
+ list: (tenantId) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}/invites`, { envBearer: true }),
1057
+ /**
1058
+ * POST /env/tenants/{tenantId}/invites — invite an address. Always
1059
+ * returns `acceptUrl`; with `sendEmail: false` Authyon does not mail
1060
+ * it and you deliver the link yourself. Valid 7 days, single use, and
1061
+ * not readable again later.
1062
+ */
1063
+ create: (tenantId, input) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}/invites`, {
1064
+ method: "POST",
1065
+ envBearer: true,
1066
+ body: {
1067
+ email: input.email,
1068
+ roles: input.roles,
1069
+ sendEmail: input.sendEmail ?? true,
1070
+ redirectUri: input.redirectUri
1071
+ }
1072
+ }),
1073
+ /** POST .../invites/{inviteId}/resend — new link (the previous one stops working), mailed unless `sendEmail` is `false`. */
1074
+ resend: (tenantId, inviteId, input = {}) => this.request(
1075
+ `/env/tenants/${encodeURIComponent(tenantId)}/invites/${encodeURIComponent(inviteId)}/resend`,
1076
+ { method: "POST", envBearer: true, body: { sendEmail: input.sendEmail ?? true } }
1077
+ ),
1078
+ /** DELETE /env/tenants/{tenantId}/invites/{inviteId} — revoke a pending invite. */
1079
+ revoke: (tenantId, inviteId) => this.request(
1080
+ `/env/tenants/${encodeURIComponent(tenantId)}/invites/${encodeURIComponent(inviteId)}`,
1081
+ { method: "DELETE", envBearer: true }
1082
+ ),
1083
+ /**
1084
+ * POST /auth/tenant-invites/preview — for a backend hosting the accept
1085
+ * page. Public: needs only `envKey`, the token is the credential.
1086
+ */
1087
+ preview: (token) => this.request("/auth/tenant-invites/preview", { method: "POST", body: { token } }),
1088
+ /**
1089
+ * Joins the tenant; for an address with no account, also creates it
1090
+ * (password required) with the e-mail already confirmed. Does not
1091
+ * sign the user in.
1092
+ *
1093
+ * Without metadata: POST /auth/tenant-invites/accept — public, needs
1094
+ * only `envKey`. With `publicMetadata`/`privateMetadata`: POST
1095
+ * /env/tenant-invites/accept with the environment credential
1096
+ * (`authyon:users:write`), since only your backend may set them.
1097
+ */
1098
+ accept: (input) => input.publicMetadata !== void 0 || input.privateMetadata !== void 0 ? this.request("/env/tenant-invites/accept", {
1099
+ method: "POST",
1100
+ envBearer: true,
1101
+ body: input
1102
+ }) : this.request("/auth/tenant-invites/accept", { method: "POST", body: input })
1103
+ },
1009
1104
  roles: {
1010
1105
  /** GET /env/tenants/{tenantId}/roles — list a tenant's roles. */
1011
1106
  list: (tenantId) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}/roles`, { envBearer: true }),
@@ -1077,8 +1172,9 @@ var AuthyonServerClient = class {
1077
1172
  };
1078
1173
  // ── Security: one-time codes and approvals ───────────────────────────────
1079
1174
  //
1080
- // Everything here runs with the environment credential, which needs the
1081
- // `authyon:financial:authorize` scope. Keep that credential on the server.
1175
+ // Everything here runs with the environment credential: `otp` needs the
1176
+ // `authyon:otp:verify` scope, `approvals` needs `authyon:financial:authorize`.
1177
+ // Keep those credentials on the server.
1082
1178
  this.security = {
1083
1179
  otp: {
1084
1180
  /**
@@ -1086,7 +1182,8 @@ var AuthyonServerClient = class {
1086
1182
  * app (TOTP) code. A wrong code returns `{ valid: false }` instead of
1087
1183
  * throwing. Each code is accepted once; 3 wrong codes in a row sign the
1088
1184
  * user out everywhere (`sessionsRevoked: true`); 5 lock the check for 15
1089
- * minutes (`rate_limited`).
1185
+ * minutes (`rate_limited`). More than 50 wrong codes in 10 minutes from the
1186
+ * same credential pause it (`credential_throttled`). Needs `authyon:otp:verify`.
1090
1187
  */
1091
1188
  check: (userId, code) => this.request(`/env/users/${segment(userId)}/otp/verify`, {
1092
1189
  method: "POST",
@@ -1250,6 +1347,28 @@ var AuthyonServerClient = class {
1250
1347
  _clientSecret = new WeakMap();
1251
1348
  var TenantScopedClient = class {
1252
1349
  constructor(server, credentials) {
1350
+ /** Invites to the token's tenant, by e-mail or by link. */
1351
+ this.invites = {
1352
+ /** GET /tenant/invites — every invite with its status, newest first. */
1353
+ list: () => this.request("/tenant/invites"),
1354
+ /** POST /tenant/invites — always returns `acceptUrl`; `sendEmail: false` skips the e-mail. */
1355
+ create: (input) => this.request("/tenant/invites", {
1356
+ method: "POST",
1357
+ body: {
1358
+ email: input.email,
1359
+ roles: input.roles,
1360
+ sendEmail: input.sendEmail ?? true,
1361
+ redirectUri: input.redirectUri
1362
+ }
1363
+ }),
1364
+ /** POST /tenant/invites/{inviteId}/resend — new link (the previous one stops working), mailed unless `sendEmail` is `false`. */
1365
+ resend: (inviteId, input = {}) => this.request(`/tenant/invites/${encodeURIComponent(inviteId)}/resend`, {
1366
+ method: "POST",
1367
+ body: { sendEmail: input.sendEmail ?? true }
1368
+ }),
1369
+ /** DELETE /tenant/invites/{inviteId} — revoke a pending invite. */
1370
+ revoke: (inviteId) => this.request(`/tenant/invites/${encodeURIComponent(inviteId)}`, { method: "DELETE" })
1371
+ };
1253
1372
  this.members = {
1254
1373
  /**
1255
1374
  * GET /tenant/members — members of the token's tenant.
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-DQzhfaja.cjs';
2
- export { b as AccessTokenSource, c as Approval, d as ApprovalAssurance, e as ApprovalPayload, f as ApprovalStatus, g as ApprovalWebAuthnOptions, h as AuditEvent, i as AuthyonJwksDiscoveryOptions, j as AuthyonJwtClaims, k as AuthyonServerClientOptions, C as ClientCredentials, l as ClientRequestContext, m as ConfirmApprovalInput, n as ConsumedApproval, o as CreateApprovalInput, p as CreateCredentialInput, q as CreateOrganizationInput, r as CreatePermissionInput, s as CreateTenantCredentialInput, t as CreateUserInput, u as CredentialCreator, v as CredentialDetail, w as CredentialListOptions, x as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, 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 OtpCheckResult, Q as Paged, R as PaginationOptions, S as Permission, T as PermissionsByRole, U as ReservedPermissions, V as Role, W as RoleGrant, X as RoleInput, Y as RoleList, Z as RolePermissions, _ as SafeJwtAlgorithm, $ as SubjectApprovals, a0 as SubjectSecurity, a1 as TenantClientValidationResult, a2 as TenantCredentialIssued, a3 as TenantCredentialSummary, a4 as TenantMember, a5 as TenantMemberPage, a6 as TenantMembership, a7 as TenantScopedClient, a8 as TokenResult, a9 as TokenVerificationError, aa as TokenVerificationErrorCode, ab as UpdateOrganizationInput, ac as User, ad as UserScopedClient, ae as ValidateResult, af as VerifiedAccessToken, ag as createClient, ah as normalizeClientIp } from './authyonServerClient-DQzhfaja.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-B82XXf3B.cjs';
1
+ import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-1_1qNRDa.cjs';
2
+ export { b as AcceptTenantInviteInput, c as AccessTokenSource, d as Approval, e as ApprovalAssurance, f as ApprovalPayload, g as ApprovalStatus, h as ApprovalWebAuthnOptions, i as AuditEvent, j as AuthyonJwksDiscoveryOptions, k as AuthyonJwtClaims, l as AuthyonServerClientOptions, C as ClientCredentials, m as ClientRequestContext, n as ConfirmApprovalInput, o as ConsumedApproval, p as CreateApprovalInput, q as CreateCredentialInput, r as CreateOrganizationInput, s as CreatePermissionInput, t as CreateTenantCredentialInput, u as CreateUserInput, v as CredentialCreator, w as CredentialDetail, x as CredentialListOptions, y as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, z as HttpAdapterRequest, B as HttpLogEvent, D as HttpLogger, I as IntrospectResult, G as InviteTenantMemberInput, J as JsonWebKeySet, K as JwksTokenVerifier, L as JwksTokenVerifierOptions, M as LoggingHttpAdapter, N as LoginActivity, O as OpenIdConfiguration, P as Organization, Q as OtpCheckResult, R as Paged, S as PaginationOptions, T as Permission, U as PermissionsByRole, V as ReservedPermissions, W as Role, X as RoleGrant, Y as RoleInput, Z as RoleList, _ as RolePermissions, $ as SafeJwtAlgorithm, a0 as SecurityMethods, a1 as SubjectApprovals, a2 as SubjectSecurity, a3 as TenantClientValidationResult, a4 as TenantCredentialIssued, a5 as TenantCredentialSummary, a6 as TenantInvite, a7 as TenantInviteAccepted, a8 as TenantInviteInput, a9 as TenantInviteIssued, aa as TenantInvitePreview, ab as TenantInviteStatus, ac as TenantMember, ad as TenantMemberPage, ae as TenantMembership, af as TenantScopedClient, ag as TokenResult, ah as TokenVerificationError, ai as TokenVerificationErrorCode, aj as UpdateOrganizationInput, ak as User, al as UserScopedClient, am as ValidateResult, an as VerifiedAccessToken, ao as createClient, ap as normalizeClientIp } from './authyonServerClient-1_1qNRDa.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-C0Mg5gUv.cjs';
4
4
  import 'jose';
5
5
 
6
6
  declare const ErrorCodes: {
@@ -27,6 +27,7 @@ declare const ErrorCodes: {
27
27
  readonly UserNotFound: "user_not_found";
28
28
  readonly TemporarilyUnavailable: "temporarily_unavailable";
29
29
  readonly InsufficientScope: "insufficient_scope";
30
+ readonly CredentialThrottled: "credential_throttled";
30
31
  readonly ApprovalNotFound: "authorization_not_found";
31
32
  readonly SessionRevoked: "session_revoked";
32
33
  readonly TwoFactorTooManyFailures: "user.2fa.too_many_failures";
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-DQzhfaja.js';
2
- export { b as AccessTokenSource, c as Approval, d as ApprovalAssurance, e as ApprovalPayload, f as ApprovalStatus, g as ApprovalWebAuthnOptions, h as AuditEvent, i as AuthyonJwksDiscoveryOptions, j as AuthyonJwtClaims, k as AuthyonServerClientOptions, C as ClientCredentials, l as ClientRequestContext, m as ConfirmApprovalInput, n as ConsumedApproval, o as CreateApprovalInput, p as CreateCredentialInput, q as CreateOrganizationInput, r as CreatePermissionInput, s as CreateTenantCredentialInput, t as CreateUserInput, u as CredentialCreator, v as CredentialDetail, w as CredentialListOptions, x as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, 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 OtpCheckResult, Q as Paged, R as PaginationOptions, S as Permission, T as PermissionsByRole, U as ReservedPermissions, V as Role, W as RoleGrant, X as RoleInput, Y as RoleList, Z as RolePermissions, _ as SafeJwtAlgorithm, $ as SubjectApprovals, a0 as SubjectSecurity, a1 as TenantClientValidationResult, a2 as TenantCredentialIssued, a3 as TenantCredentialSummary, a4 as TenantMember, a5 as TenantMemberPage, a6 as TenantMembership, a7 as TenantScopedClient, a8 as TokenResult, a9 as TokenVerificationError, aa as TokenVerificationErrorCode, ab as UpdateOrganizationInput, ac as User, ad as UserScopedClient, ae as ValidateResult, af as VerifiedAccessToken, ag as createClient, ah as normalizeClientIp } from './authyonServerClient-DQzhfaja.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-WlwcTBwG.js';
1
+ import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-1_1qNRDa.js';
2
+ export { b as AcceptTenantInviteInput, c as AccessTokenSource, d as Approval, e as ApprovalAssurance, f as ApprovalPayload, g as ApprovalStatus, h as ApprovalWebAuthnOptions, i as AuditEvent, j as AuthyonJwksDiscoveryOptions, k as AuthyonJwtClaims, l as AuthyonServerClientOptions, C as ClientCredentials, m as ClientRequestContext, n as ConfirmApprovalInput, o as ConsumedApproval, p as CreateApprovalInput, q as CreateCredentialInput, r as CreateOrganizationInput, s as CreatePermissionInput, t as CreateTenantCredentialInput, u as CreateUserInput, v as CredentialCreator, w as CredentialDetail, x as CredentialListOptions, y as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, z as HttpAdapterRequest, B as HttpLogEvent, D as HttpLogger, I as IntrospectResult, G as InviteTenantMemberInput, J as JsonWebKeySet, K as JwksTokenVerifier, L as JwksTokenVerifierOptions, M as LoggingHttpAdapter, N as LoginActivity, O as OpenIdConfiguration, P as Organization, Q as OtpCheckResult, R as Paged, S as PaginationOptions, T as Permission, U as PermissionsByRole, V as ReservedPermissions, W as Role, X as RoleGrant, Y as RoleInput, Z as RoleList, _ as RolePermissions, $ as SafeJwtAlgorithm, a0 as SecurityMethods, a1 as SubjectApprovals, a2 as SubjectSecurity, a3 as TenantClientValidationResult, a4 as TenantCredentialIssued, a5 as TenantCredentialSummary, a6 as TenantInvite, a7 as TenantInviteAccepted, a8 as TenantInviteInput, a9 as TenantInviteIssued, aa as TenantInvitePreview, ab as TenantInviteStatus, ac as TenantMember, ad as TenantMemberPage, ae as TenantMembership, af as TenantScopedClient, ag as TokenResult, ah as TokenVerificationError, ai as TokenVerificationErrorCode, aj as UpdateOrganizationInput, ak as User, al as UserScopedClient, am as ValidateResult, an as VerifiedAccessToken, ao as createClient, ap as normalizeClientIp } from './authyonServerClient-1_1qNRDa.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-BvjIWPcU.js';
4
4
  import 'jose';
5
5
 
6
6
  declare const ErrorCodes: {
@@ -27,6 +27,7 @@ declare const ErrorCodes: {
27
27
  readonly UserNotFound: "user_not_found";
28
28
  readonly TemporarilyUnavailable: "temporarily_unavailable";
29
29
  readonly InsufficientScope: "insufficient_scope";
30
+ readonly CredentialThrottled: "credential_throttled";
30
31
  readonly ApprovalNotFound: "authorization_not_found";
31
32
  readonly SessionRevoked: "session_revoked";
32
33
  readonly TwoFactorTooManyFailures: "user.2fa.too_many_failures";
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  JsonHttpClient,
8
8
  LoggingHttpAdapter,
9
9
  createSharedTransport
10
- } from "./chunk-WPPEV5BA.js";
10
+ } from "./chunk-TDJNBD3Z.js";
11
11
  import {
12
12
  AuthorizationError,
13
13
  AuthyonAbility,
@@ -152,8 +152,22 @@ function path(id, suffix = "") {
152
152
  throw new TypeError("Authyon: an approval id is required.");
153
153
  return `/auth/authorizations/${encodeURIComponent(id)}${suffix}`;
154
154
  }
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
+ };
155
165
  function subjectSecurity(request) {
156
166
  return {
167
+ methods: async () => {
168
+ const me = await request("/auth/me");
169
+ return me.security ?? NO_METHODS;
170
+ },
157
171
  approvals: {
158
172
  get: (id) => request(path(id)),
159
173
  webauthnOptions: (id) => request(path(id, "/webauthn/options"), { method: "POST" }),
@@ -191,6 +205,31 @@ var UserScopedClient = class {
191
205
  remove: (tenantId, userId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members/${segment(userId)}`, {
192
206
  method: "DELETE"
193
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
+ })
194
233
  }
195
234
  };
196
235
  __privateSet(this, _request, scopedRequest(request, token));
@@ -484,6 +523,61 @@ var AuthyonServerClient = class {
484
523
  { method: "DELETE", envBearer: true }
485
524
  )
486
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
+ },
487
581
  roles: {
488
582
  /** GET /env/tenants/{tenantId}/roles — list a tenant's roles. */
489
583
  list: (tenantId) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}/roles`, { envBearer: true }),
@@ -555,8 +649,9 @@ var AuthyonServerClient = class {
555
649
  };
556
650
  // ── Security: one-time codes and approvals ───────────────────────────────
557
651
  //
558
- // Everything here runs with the environment credential, which needs the
559
- // `authyon:financial:authorize` scope. Keep that credential on the server.
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.
560
655
  this.security = {
561
656
  otp: {
562
657
  /**
@@ -564,7 +659,8 @@ var AuthyonServerClient = class {
564
659
  * app (TOTP) code. A wrong code returns `{ valid: false }` instead of
565
660
  * throwing. Each code is accepted once; 3 wrong codes in a row sign the
566
661
  * user out everywhere (`sessionsRevoked: true`); 5 lock the check for 15
567
- * minutes (`rate_limited`).
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`.
568
664
  */
569
665
  check: (userId, code) => this.request(`/env/users/${segment(userId)}/otp/verify`, {
570
666
  method: "POST",
@@ -728,6 +824,28 @@ var AuthyonServerClient = class {
728
824
  _clientSecret = new WeakMap();
729
825
  var TenantScopedClient = class {
730
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
+ };
731
849
  this.members = {
732
850
  /**
733
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-B82XXf3B.cjs';
3
- import { A as AuthyonServerClient } from './authyonServerClient-DQzhfaja.cjs';
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-WlwcTBwG.js';
3
- import { A as AuthyonServerClient } from './authyonServerClient-DQzhfaja.js';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authyon/server",
3
- "version": "0.2.0-beta.15",
3
+ "version": "0.2.0-beta.17",
4
4
  "description": "Authyon SDK for backends — server-to-server organization/member management and access-token verification.",
5
5
  "license": "MIT",
6
6
  "type": "module",