authhero 8.23.1 → 8.25.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.
Files changed (54) hide show
  1. package/dist/assets/u/widget/index.esm.js +1 -1
  2. package/dist/authhero.cjs +139 -142
  3. package/dist/authhero.d.ts +1073 -292
  4. package/dist/authhero.mjs +20321 -15480
  5. package/dist/tsconfig.types.tsbuildinfo +1 -1
  6. package/dist/types/adapters/control-plane-custom-domains.d.ts +35 -0
  7. package/dist/types/authentication-flows/passwordless.d.ts +4 -4
  8. package/dist/types/helpers/control-plane-client.d.ts +46 -0
  9. package/dist/types/helpers/control-plane-sync-events.d.ts +12 -28
  10. package/dist/types/index.d.ts +326 -246
  11. package/dist/types/routes/auth-api/index.d.ts +28 -28
  12. package/dist/types/routes/auth-api/passwordless.d.ts +12 -12
  13. package/dist/types/routes/auth-api/register/index.d.ts +2 -2
  14. package/dist/types/routes/auth-api/revoke.d.ts +2 -2
  15. package/dist/types/routes/auth-api/token.d.ts +12 -12
  16. package/dist/types/routes/management-api/authentication-methods.d.ts +1 -1
  17. package/dist/types/routes/management-api/clients.d.ts +14 -14
  18. package/dist/types/routes/management-api/connections.d.ts +16 -16
  19. package/dist/types/routes/management-api/custom-domains.d.ts +6 -6
  20. package/dist/types/routes/management-api/email-templates.d.ts +18 -18
  21. package/dist/types/routes/management-api/forms.d.ts +126 -126
  22. package/dist/types/routes/management-api/guardian.d.ts +5 -5
  23. package/dist/types/routes/management-api/helpers.d.ts +47 -0
  24. package/dist/types/routes/management-api/index.d.ts +280 -211
  25. package/dist/types/routes/management-api/logs.d.ts +4 -4
  26. package/dist/types/routes/management-api/migration-sources.d.ts +6 -6
  27. package/dist/types/routes/management-api/organizations.d.ts +8 -8
  28. package/dist/types/routes/management-api/prompts.d.ts +4 -4
  29. package/dist/types/routes/management-api/roles.d.ts +1 -1
  30. package/dist/types/routes/management-api/tenant-members.d.ts +304 -0
  31. package/dist/types/routes/management-api/tenant-members.test.d.ts +1 -0
  32. package/dist/types/routes/management-api/tenants.d.ts +8 -8
  33. package/dist/types/routes/management-api/users.d.ts +71 -2
  34. package/dist/types/routes/proxy-control-plane/custom-domains.d.ts +45 -0
  35. package/dist/types/routes/proxy-control-plane/index.d.ts +47 -6
  36. package/dist/types/routes/proxy-control-plane/scopes.d.ts +20 -0
  37. package/dist/types/routes/proxy-control-plane/tenant-members.d.ts +37 -0
  38. package/dist/types/routes/proxy-control-plane/verify.d.ts +29 -4
  39. package/dist/types/routes/proxy-control-plane/verify.test.d.ts +1 -0
  40. package/dist/types/routes/universal-login/common.d.ts +8 -8
  41. package/dist/types/routes/universal-login/flow-api.d.ts +12 -12
  42. package/dist/types/routes/universal-login/identifier.d.ts +2 -2
  43. package/dist/types/routes/universal-login/index.d.ts +2 -2
  44. package/dist/types/routes/universal-login/u2-index.d.ts +5 -5
  45. package/dist/types/routes/universal-login/u2-routes.d.ts +5 -5
  46. package/dist/types/tenant-members/control-plane-roundtrip.test.d.ts +1 -0
  47. package/dist/types/tenant-members/local-backend.d.ts +43 -0
  48. package/dist/types/tenant-members/local-backend.test.d.ts +1 -0
  49. package/dist/types/tenant-members/remote-backend.d.ts +17 -0
  50. package/dist/types/tenant-members/types.d.ts +112 -0
  51. package/dist/types/tenant-members/wire.d.ts +28 -0
  52. package/dist/types/types/AuthHeroConfig.d.ts +54 -7
  53. package/dist/types/types/IdToken.d.ts +4 -4
  54. package/package.json +6 -6
@@ -165,7 +165,7 @@ export default function createU2App(config: AuthHeroConfig): OpenAPIHono<{
165
165
  $get: {
166
166
  input: {
167
167
  param: {
168
- screen: "signup" | "consent" | "login" | "reset-password" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
168
+ screen: "signup" | "login" | "reset-password" | "consent" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
169
169
  };
170
170
  } & {
171
171
  query: {
@@ -181,7 +181,7 @@ export default function createU2App(config: AuthHeroConfig): OpenAPIHono<{
181
181
  } | {
182
182
  input: {
183
183
  param: {
184
- screen: "signup" | "consent" | "login" | "reset-password" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
184
+ screen: "signup" | "login" | "reset-password" | "consent" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
185
185
  };
186
186
  } & {
187
187
  query: {
@@ -197,7 +197,7 @@ export default function createU2App(config: AuthHeroConfig): OpenAPIHono<{
197
197
  } | {
198
198
  input: {
199
199
  param: {
200
- screen: "signup" | "consent" | "login" | "reset-password" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
200
+ screen: "signup" | "login" | "reset-password" | "consent" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
201
201
  };
202
202
  } & {
203
203
  query: {
@@ -217,7 +217,7 @@ export default function createU2App(config: AuthHeroConfig): OpenAPIHono<{
217
217
  $post: {
218
218
  input: {
219
219
  param: {
220
- screen: "signup" | "consent" | "login" | "reset-password" | "enter-password" | "impersonate" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
220
+ screen: "signup" | "login" | "reset-password" | "consent" | "enter-password" | "impersonate" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
221
221
  };
222
222
  } & {
223
223
  query: {
@@ -235,7 +235,7 @@ export default function createU2App(config: AuthHeroConfig): OpenAPIHono<{
235
235
  } | {
236
236
  input: {
237
237
  param: {
238
- screen: "signup" | "consent" | "login" | "reset-password" | "enter-password" | "impersonate" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
238
+ screen: "signup" | "login" | "reset-password" | "consent" | "enter-password" | "impersonate" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
239
239
  };
240
240
  } & {
241
241
  query: {
@@ -170,7 +170,7 @@ export declare const u2Routes: OpenAPIHono<{
170
170
  $get: {
171
171
  input: {
172
172
  param: {
173
- screen: "signup" | "consent" | "login" | "reset-password" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
173
+ screen: "signup" | "login" | "reset-password" | "consent" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
174
174
  };
175
175
  } & {
176
176
  query: {
@@ -186,7 +186,7 @@ export declare const u2Routes: OpenAPIHono<{
186
186
  } | {
187
187
  input: {
188
188
  param: {
189
- screen: "signup" | "consent" | "login" | "reset-password" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
189
+ screen: "signup" | "login" | "reset-password" | "consent" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
190
190
  };
191
191
  } & {
192
192
  query: {
@@ -202,7 +202,7 @@ export declare const u2Routes: OpenAPIHono<{
202
202
  } | {
203
203
  input: {
204
204
  param: {
205
- screen: "signup" | "consent" | "login" | "reset-password" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
205
+ screen: "signup" | "login" | "reset-password" | "consent" | "account" | "enter-password" | "impersonate" | "try-connection-result" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
206
206
  };
207
207
  } & {
208
208
  query: {
@@ -222,7 +222,7 @@ export declare const u2Routes: OpenAPIHono<{
222
222
  $post: {
223
223
  input: {
224
224
  param: {
225
- screen: "signup" | "consent" | "login" | "reset-password" | "enter-password" | "impersonate" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
225
+ screen: "signup" | "login" | "reset-password" | "consent" | "enter-password" | "impersonate" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
226
226
  };
227
227
  } & {
228
228
  query: {
@@ -240,7 +240,7 @@ export declare const u2Routes: OpenAPIHono<{
240
240
  } | {
241
241
  input: {
242
242
  param: {
243
- screen: "signup" | "consent" | "login" | "reset-password" | "enter-password" | "impersonate" | "reset-password/request" | "reset-password/code" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
243
+ screen: "signup" | "login" | "reset-password" | "consent" | "enter-password" | "impersonate" | "login/identifier" | "login/email-otp-challenge" | "login/sms-otp-challenge" | "login/login-passwordless-identifier" | "reset-password/code" | "reset-password/request" | "mfa/login-options" | "mfa/totp-challenge" | "mfa/totp-enrollment" | "mfa/phone-challenge" | "mfa/phone-enrollment" | "passkey/challenge" | "passkey/enrollment" | "passkey/enrollment-nudge" | "account/profile" | "account/security" | "account/security/totp-enrollment" | "account/security/phone-enrollment" | "account/linked" | "account/delete" | "account/passkeys" | "connect/start" | "connect/select-tenant";
244
244
  };
245
245
  } & {
246
246
  query: {
@@ -0,0 +1,43 @@
1
+ import { DataAdapters } from "@authhero/adapter-interfaces";
2
+ import { TenantMembersBackend } from "./types";
3
+ /** The control-plane adapters the team lives in. */
4
+ type TeamAdapters = Pick<DataAdapters, "organizations" | "userOrganizations" | "userRoles" | "users" | "roles" | "invites">;
5
+ export interface LocalTenantMembersBackendOptions {
6
+ /**
7
+ * Adapters bound to the CONTROL-PLANE database — the team lives there, not on
8
+ * the tenant shard. On the control-plane instance this is just `ctx.env.data`.
9
+ */
10
+ data: TeamAdapters;
11
+ /** Tenant id under which the org rows are stored (the control-plane tenant). */
12
+ controlPlaneTenantId: string;
13
+ /** Issuer used to build invitation acceptance links and default avatars. */
14
+ issuer: string;
15
+ /**
16
+ * Client id embedded in invitation links. Resolved server-side so the caller
17
+ * never supplies it (the admin-UI bug this fixes). Without it, invitations
18
+ * cannot be created and `createInvitation` throws.
19
+ */
20
+ invitationClientId?: string;
21
+ /**
22
+ * Best-effort invitation email delivery. Bound to a request context at the
23
+ * call site (it needs branding/email infra). Failures must not fail the
24
+ * create — Auth0 returns the invite even when delivery fails.
25
+ */
26
+ sendInvitationEmail?: (params: {
27
+ to: string;
28
+ invitationUrl: string;
29
+ inviterName?: string;
30
+ organizationName: string;
31
+ ttlSec: number;
32
+ }) => Promise<void>;
33
+ }
34
+ /**
35
+ * A `TenantMembersBackend` that resolves the tenant's control-plane
36
+ * organization and manages membership/roles/invitations directly against the
37
+ * control-plane adapters. Used where the code already runs with the
38
+ * control-plane database in reach: single-instance deployments (via the
39
+ * management route) and the control-plane proxy resource (which fronts remote
40
+ * shards).
41
+ */
42
+ export declare function createLocalTenantMembersBackend(options: LocalTenantMembersBackendOptions): TenantMembersBackend;
43
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ import { ControlPlaneClient } from "../helpers/control-plane-client";
2
+ import { TenantMembersBackend } from "./types";
3
+ export interface ControlPlaneTenantMembersOptions {
4
+ /** Authed transport to the control plane (shared with other adapters). */
5
+ client: ControlPlaneClient;
6
+ /** Override the control-plane resource path (tests, custom mounts). */
7
+ basePath?: string;
8
+ }
9
+ /**
10
+ * A `TenantMembersBackend` for a tenant shard whose own database does not hold
11
+ * the control-plane organization that models its team. Every call is delegated
12
+ * up to the authoritative `tenant-members` resource
13
+ * (`createTenantMembersControlPlaneApp`) over the shared control-plane client,
14
+ * which mints a service token bound to this tenant. The control plane pins the
15
+ * org from that token, so the shard never has to (and cannot) name it.
16
+ */
17
+ export declare function createControlPlaneTenantMembersAdapter(options: ControlPlaneTenantMembersOptions): TenantMembersBackend;
@@ -0,0 +1,112 @@
1
+ import { z } from "@hono/zod-openapi";
2
+ import { inviteSchema, roleSchema } from "@authhero/adapter-interfaces";
3
+ /**
4
+ * A tenant's "team" is not the tenant's own users. It is an organization on the
5
+ * control-plane tenant whose `name` equals the tenant id (see
6
+ * `@authhero/multi-tenancy` provisioning). Its members are control-plane users
7
+ * holding org-scoped roles, and the tenant shard cannot write those rows.
8
+ *
9
+ * `TenantMembersBackend` is the seam that hides "where the team actually lives":
10
+ * - on a single-instance / control-plane deployment it resolves the org and
11
+ * acts on the local control-plane adapters (`createLocalTenantMembersBackend`);
12
+ * - on a Workers-for-Platforms shard it delegates every call up to the control
13
+ * plane over the shared control-plane client
14
+ * (`createControlPlaneTenantMembersAdapter`).
15
+ *
16
+ * Every method takes the CHILD `tenantId` (the tenant whose team is managed),
17
+ * never an organization id — the org is resolved from the tenant id internally.
18
+ * The management route that fronts this has already pinned `tenantId` to the
19
+ * caller's verified org claim, so the backend never has to re-authorize.
20
+ */
21
+ export declare const tenantMemberSchema: z.ZodObject<{
22
+ user_id: z.ZodString;
23
+ email: z.ZodOptional<z.ZodString>;
24
+ name: z.ZodOptional<z.ZodString>;
25
+ picture: z.ZodOptional<z.ZodString>;
26
+ roles: z.ZodDefault<z.ZodArray<z.ZodObject<{
27
+ name: z.ZodString;
28
+ description: z.ZodOptional<z.ZodString>;
29
+ is_system: z.ZodOptional<z.ZodBoolean>;
30
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
31
+ id: z.ZodString;
32
+ created_at: z.ZodOptional<z.ZodString>;
33
+ updated_at: z.ZodOptional<z.ZodString>;
34
+ }, z.core.$strip>>>;
35
+ }, z.core.$strip>;
36
+ export type TenantMember = z.infer<typeof tenantMemberSchema>;
37
+ export declare const tenantMembersListSchema: z.ZodObject<{
38
+ members: z.ZodArray<z.ZodObject<{
39
+ user_id: z.ZodString;
40
+ email: z.ZodOptional<z.ZodString>;
41
+ name: z.ZodOptional<z.ZodString>;
42
+ picture: z.ZodOptional<z.ZodString>;
43
+ roles: z.ZodDefault<z.ZodArray<z.ZodObject<{
44
+ name: z.ZodString;
45
+ description: z.ZodOptional<z.ZodString>;
46
+ is_system: z.ZodOptional<z.ZodBoolean>;
47
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
48
+ id: z.ZodString;
49
+ created_at: z.ZodOptional<z.ZodString>;
50
+ updated_at: z.ZodOptional<z.ZodString>;
51
+ }, z.core.$strip>>>;
52
+ }, z.core.$strip>>;
53
+ start: z.ZodNumber;
54
+ limit: z.ZodNumber;
55
+ total: z.ZodNumber;
56
+ }, z.core.$strip>;
57
+ export type TenantMembersListResult = z.infer<typeof tenantMembersListSchema>;
58
+ /**
59
+ * The invitee-facing fields of an invitation create. `organization_id`,
60
+ * `invitation_url` and `id` are resolved server-side (the org from the tenant
61
+ * id, the URL from the control-plane issuer), never trusted from the caller —
62
+ * that is the fix for the admin UI's "invite silently disappears when the
63
+ * client id isn't in local storage" foot-gun.
64
+ */
65
+ export declare const tenantInvitationInputSchema: z.ZodObject<{
66
+ invitee: z.ZodObject<{
67
+ email: z.ZodString;
68
+ }, z.core.$strip>;
69
+ inviter: z.ZodDefault<z.ZodObject<{
70
+ name: z.ZodOptional<z.ZodString>;
71
+ }, z.core.$strip>>;
72
+ roles: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString>>>;
73
+ send_invitation_email: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
74
+ ttl_sec: z.ZodOptional<z.ZodNumber>;
75
+ }, z.core.$strip>;
76
+ export type TenantInvitationInput = z.input<typeof tenantInvitationInputSchema>;
77
+ export interface TenantMembersPageParams {
78
+ page?: number;
79
+ per_page?: number;
80
+ q?: string;
81
+ }
82
+ export type TenantInvitation = z.infer<typeof inviteSchema>;
83
+ export type TenantRole = z.infer<typeof roleSchema>;
84
+ export interface TenantMembersBackend {
85
+ listMembers(tenantId: string, params?: TenantMembersPageParams): Promise<TenantMembersListResult>;
86
+ addMembers(tenantId: string, userIds: string[]): Promise<void>;
87
+ removeMembers(tenantId: string, userIds: string[]): Promise<void>;
88
+ listMemberRoles(tenantId: string, userId: string): Promise<TenantRole[]>;
89
+ assignMemberRoles(tenantId: string, userId: string, roleIds: string[]): Promise<void>;
90
+ removeMemberRoles(tenantId: string, userId: string, roleIds: string[]): Promise<void>;
91
+ /** Roles that can be granted to a member — the control-plane tenant's roles. */
92
+ listRoles(tenantId: string, params?: TenantMembersPageParams): Promise<TenantRole[]>;
93
+ listInvitations(tenantId: string, params?: TenantMembersPageParams): Promise<TenantInvitation[]>;
94
+ createInvitation(tenantId: string, input: TenantInvitationInput): Promise<TenantInvitation>;
95
+ revokeInvitation(tenantId: string, invitationId: string): Promise<void>;
96
+ }
97
+ /**
98
+ * Base for the "asked for something that isn't there" cases a backend can hit.
99
+ * The management route maps any of these to a 404. It is a distinct type (not a
100
+ * bare HTTPException) so the local and remote backends can agree on the
101
+ * semantics without depending on hono.
102
+ */
103
+ export declare class TenantMembersNotFoundError extends Error {
104
+ }
105
+ /** The tenant id names no control-plane organization — i.e. no team. */
106
+ export declare class TenantOrganizationNotFoundError extends TenantMembersNotFoundError {
107
+ constructor(tenantId: string);
108
+ }
109
+ /** The invitation does not exist, or belongs to a different tenant's team. */
110
+ export declare class TenantInvitationNotFoundError extends TenantMembersNotFoundError {
111
+ constructor(invitationId: string);
112
+ }
@@ -0,0 +1,28 @@
1
+ import { z } from "@hono/zod-openapi";
2
+ /**
3
+ * The HTTP contract shared by the control-plane `tenant-members` resource
4
+ * (`createTenantMembersControlPlaneApp`) and the remote client that calls it
5
+ * (`createControlPlaneTenantMembersAdapter`). Keeping the paths and body shapes
6
+ * in one place is what keeps the two ends from drifting.
7
+ */
8
+ export declare const CONTROL_PLANE_TENANT_MEMBERS_PATH = "/api/v2/proxy/control-plane/tenant-members";
9
+ export declare const membersMutationBodySchema: z.ZodObject<{
10
+ user_ids: z.ZodArray<z.ZodString>;
11
+ tenant_id: z.ZodOptional<z.ZodString>;
12
+ }, z.core.$strip>;
13
+ export declare const memberRolesBodySchema: z.ZodObject<{
14
+ roles: z.ZodArray<z.ZodString>;
15
+ tenant_id: z.ZodOptional<z.ZodString>;
16
+ }, z.core.$strip>;
17
+ export declare const createInvitationBodySchema: z.ZodObject<{
18
+ invitee: z.ZodObject<{
19
+ email: z.ZodString;
20
+ }, z.core.$strip>;
21
+ inviter: z.ZodDefault<z.ZodObject<{
22
+ name: z.ZodOptional<z.ZodString>;
23
+ }, z.core.$strip>>;
24
+ roles: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString>>>;
25
+ send_invitation_email: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
26
+ ttl_sec: z.ZodOptional<z.ZodNumber>;
27
+ tenant_id: z.ZodOptional<z.ZodString>;
28
+ }, z.core.$strip>;
@@ -315,24 +315,71 @@ export interface AuthHeroConfig {
315
315
  * hosts through a service binding by inspecting the URL.
316
316
  */
317
317
  jwksFetch?: (url: string) => Promise<Response>;
318
+ /**
319
+ * Optional predicate widening the accepted token issuers beyond
320
+ * `env.ISSUER` / the inbound host to a deployment's own WFP tenant
321
+ * subdomains, whose per-tenant control-plane credential `jwksFetch`
322
+ * resolves locally (see #1139). Consulted before any JWKS fetch; return
323
+ * `true` only for issuer hosts you serve.
324
+ */
325
+ isTrustedIssuer?: (iss: string) => boolean;
318
326
  /**
319
327
  * Optional receiver for `POST /sync` events emitted by tenant shards via
320
328
  * the `ControlPlaneSyncDestination`. Mount on the control-plane authhero
321
329
  * instance only. Implementations MUST be idempotent — the outbox retries
322
- * on transient failures. Use `createApplySyncEvents({ customDomains,
323
- * proxyRoutes })` (exported from `authhero`) for the default
324
- * adapter-backed implementation.
330
+ * on transient failures. Use `createApplySyncEvents({ proxyRoutes })`
331
+ * (exported from `authhero`) for the default adapter-backed
332
+ * implementation.
325
333
  */
326
334
  applySyncEvents?: (events: import("../helpers/control-plane-sync-events").SyncEvent[]) => Promise<void>;
335
+ /**
336
+ * The authoritative custom-domains adapter. When set, mounts
337
+ * `/api/v2/proxy/control-plane/custom-domains` — the resource tenant
338
+ * shards write through (`createControlPlaneCustomDomainsAdapter`).
339
+ *
340
+ * Pass the Cloudflare adapter wrapping the control-plane database: a
341
+ * CF-for-SaaS hostname is an account-global resource, so registering it
342
+ * needs credentials that only exist here, and claiming it exactly once
343
+ * needs a view across every tenant that only exists here.
344
+ */
345
+ customDomains?: import("@authhero/adapter-interfaces").CustomDomainsAdapter;
346
+ /**
347
+ * The authoritative tenant-team resource. When set, mounts
348
+ * `/api/v2/proxy/control-plane/tenant-members` — the resource tenant shards
349
+ * call through `createControlPlaneTenantMembersAdapter` so their admins can
350
+ * manage who administers the tenant (control-plane organization membership
351
+ * + org-scoped roles + invitations). Wire the backend to the control-plane
352
+ * database via `createLocalTenantMembersBackend`.
353
+ */
354
+ tenantMembers?: import("../routes/proxy-control-plane/tenant-members").TenantMembersControlPlaneOptions;
327
355
  };
328
356
  /**
329
- * Optional outbox-driven replication of `custom_domains` and `proxy_routes`
330
- * mutations to a global proxy control plane. When set, every successful
331
- * write on this tenant shard enqueues a `controlplane.sync.*` outbox event;
332
- * the `ControlPlaneSyncDestination` POSTs each event to
357
+ * Enables the tenant-scoped `/api/v2/tenant-members` management resource,
358
+ * which lets a tenant admin manage their own team from the per-tenant admin
359
+ * UI. Every request is pinned to the caller's `org_name` claim, then
360
+ * delegated to the backend this returns.
361
+ *
362
+ * Return `createLocalTenantMembersBackend(...)` on a single-instance /
363
+ * control-plane deployment (the team lives in the same database), or
364
+ * `createControlPlaneTenantMembersAdapter(...)` on a Workers-for-Platforms
365
+ * shard (the team lives on the control plane and is reached over the shared
366
+ * control-plane client). Leave unset to not mount the resource.
367
+ */
368
+ tenantMembers?: {
369
+ getBackend: import("../routes/management-api/tenant-members").GetTenantMembersBackend;
370
+ };
371
+ /**
372
+ * Optional outbox-driven replication of `proxy_routes` mutations to a global
373
+ * proxy control plane. When set, every successful write on this tenant shard
374
+ * enqueues a `controlplane.sync.*` outbox event; the
375
+ * `ControlPlaneSyncDestination` POSTs each event to
333
376
  * `${baseUrl}/api/v2/proxy/control-plane/sync`. Requires the outbox to be
334
377
  * enabled (`outbox: { enabled: true }`).
335
378
  *
379
+ * Custom domains are NOT replicated this way — the control plane is
380
+ * authoritative for them; wire `createControlPlaneCustomDomainsAdapter` into
381
+ * the shard's `dataAdapter` instead.
382
+ *
336
383
  * Leave unset for single-DB deployments — the proxy reads the same database
337
384
  * the management API writes to, so replication is unnecessary.
338
385
  */
@@ -20,11 +20,11 @@ export declare const idTokenSchema: z.ZodObject<{
20
20
  export declare const userInfoSchema: z.ZodObject<{
21
21
  name: z.ZodOptional<z.ZodString>;
22
22
  email: z.ZodOptional<z.ZodString>;
23
- given_name: z.ZodOptional<z.ZodString>;
24
- family_name: z.ZodOptional<z.ZodString>;
25
- sub: z.ZodString;
26
- exp: z.ZodNumber;
27
23
  iss: z.ZodString;
24
+ sub: z.ZodString;
28
25
  aud: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
26
+ exp: z.ZodNumber;
27
+ given_name: z.ZodOptional<z.ZodString>;
28
+ family_name: z.ZodOptional<z.ZodString>;
29
29
  }, z.core.$loose>;
30
30
  export type IdToken = z.infer<typeof idTokenSchema>;
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "type": "git",
12
12
  "url": "https://github.com/markusahlstrand/authhero"
13
13
  },
14
- "version": "8.23.1",
14
+ "version": "8.25.0",
15
15
  "files": [
16
16
  "dist"
17
17
  ],
@@ -63,8 +63,8 @@
63
63
  "vite": "^8.0.14",
64
64
  "vite-plugin-dts": "^4.5.4",
65
65
  "vitest": "^4.1.7",
66
- "@authhero/kysely-adapter": "11.18.1",
67
- "@authhero/widget": "0.34.13"
66
+ "@authhero/widget": "0.34.14",
67
+ "@authhero/kysely-adapter": "11.19.0"
68
68
  },
69
69
  "dependencies": {
70
70
  "@peculiar/x509": "^1.14.0",
@@ -81,9 +81,9 @@
81
81
  "qrcode": "^1.5.4",
82
82
  "sanitize-html": "^2.17.4",
83
83
  "xstate": "^5.31.1",
84
- "@authhero/adapter-interfaces": "4.0.0",
85
- "@authhero/proxy": "0.9.3",
86
- "@authhero/saml": "0.4.5"
84
+ "@authhero/adapter-interfaces": "4.1.0",
85
+ "@authhero/proxy": "0.9.4",
86
+ "@authhero/saml": "0.4.6"
87
87
  },
88
88
  "peerDependencies": {
89
89
  "@authhero/widget": "^0.1.0",