authhero 8.24.0 → 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.
- package/dist/authhero.cjs +138 -138
- package/dist/authhero.d.ts +802 -225
- package/dist/authhero.mjs +12109 -11443
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/authentication-flows/passwordless.d.ts +3 -3
- package/dist/types/index.d.ts +228 -222
- package/dist/types/routes/auth-api/index.d.ts +44 -44
- package/dist/types/routes/auth-api/passwordless.d.ts +12 -12
- package/dist/types/routes/auth-api/register/index.d.ts +2 -2
- package/dist/types/routes/auth-api/revoke.d.ts +8 -8
- package/dist/types/routes/auth-api/token.d.ts +22 -22
- package/dist/types/routes/management-api/authentication-methods.d.ts +1 -1
- package/dist/types/routes/management-api/branding.d.ts +1 -1
- package/dist/types/routes/management-api/clients.d.ts +8 -8
- package/dist/types/routes/management-api/connections.d.ts +1 -1
- package/dist/types/routes/management-api/custom-domains.d.ts +6 -6
- package/dist/types/routes/management-api/failed-events.d.ts +1 -1
- package/dist/types/routes/management-api/forms.d.ts +126 -126
- package/dist/types/routes/management-api/guardian.d.ts +5 -5
- package/dist/types/routes/management-api/index.d.ts +172 -172
- package/dist/types/routes/management-api/logs.d.ts +4 -4
- package/dist/types/routes/management-api/organizations.d.ts +7 -7
- package/dist/types/routes/management-api/prompts.d.ts +4 -4
- package/dist/types/routes/management-api/roles.d.ts +1 -1
- package/dist/types/routes/management-api/tenant-export-import.d.ts +5 -5
- package/dist/types/routes/management-api/tenant-members.d.ts +304 -0
- package/dist/types/routes/management-api/tenant-members.test.d.ts +1 -0
- package/dist/types/routes/management-api/tenants.d.ts +9 -9
- package/dist/types/routes/management-api/users.d.ts +2 -2
- package/dist/types/routes/proxy-control-plane/index.d.ts +23 -0
- package/dist/types/routes/proxy-control-plane/scopes.d.ts +7 -0
- package/dist/types/routes/proxy-control-plane/tenant-members.d.ts +37 -0
- package/dist/types/routes/proxy-control-plane/verify.d.ts +14 -0
- package/dist/types/routes/proxy-control-plane/verify.test.d.ts +1 -0
- package/dist/types/routes/universal-login/common.d.ts +2 -2
- package/dist/types/routes/universal-login/flow-api.d.ts +12 -12
- package/dist/types/routes/universal-login/u2-index.d.ts +5 -5
- package/dist/types/routes/universal-login/u2-routes.d.ts +5 -5
- package/dist/types/tenant-members/control-plane-roundtrip.test.d.ts +1 -0
- package/dist/types/tenant-members/local-backend.d.ts +43 -0
- package/dist/types/tenant-members/local-backend.test.d.ts +1 -0
- package/dist/types/tenant-members/remote-backend.d.ts +17 -0
- package/dist/types/tenant-members/types.d.ts +112 -0
- package/dist/types/tenant-members/wire.d.ts +28 -0
- package/dist/types/types/AuthHeroConfig.d.ts +32 -0
- package/package.json +3 -3
|
@@ -3,6 +3,7 @@ import type { ResolvedHost } from "@authhero/proxy";
|
|
|
3
3
|
import { CustomDomain, CustomDomainsAdapter, ProxyRoute, ProxyRoutesAdapter } from "@authhero/adapter-interfaces";
|
|
4
4
|
import { SyncEvent } from "../../helpers/control-plane-sync-events";
|
|
5
5
|
import { Bindings } from "../../types";
|
|
6
|
+
import { type TenantMembersControlPlaneOptions } from "./tenant-members";
|
|
6
7
|
export interface ProxyControlPlaneOptions {
|
|
7
8
|
/**
|
|
8
9
|
* Cross-tenant host resolver. Typically delegated to a database adapter's
|
|
@@ -16,6 +17,16 @@ export interface ProxyControlPlaneOptions {
|
|
|
16
17
|
* service binding by inspecting the URL and dispatching accordingly.
|
|
17
18
|
*/
|
|
18
19
|
jwksFetch?: (url: string) => Promise<Response>;
|
|
20
|
+
/**
|
|
21
|
+
* Optional predicate that widens the set of accepted token issuers beyond
|
|
22
|
+
* `env.ISSUER` and the inbound host — specifically to a deployment's own
|
|
23
|
+
* Workers-for-Platforms tenant subdomains, whose per-tenant control-plane
|
|
24
|
+
* credential `jwksFetch` resolves locally (see #1139). Consulted before any
|
|
25
|
+
* JWKS fetch, so it still constrains where keys are fetched from; return
|
|
26
|
+
* `true` only for issuer hosts you serve. Applies to every mounted resource
|
|
27
|
+
* (custom-domains, tenant-members, sync).
|
|
28
|
+
*/
|
|
29
|
+
isTrustedIssuer?: (iss: string) => boolean;
|
|
19
30
|
/**
|
|
20
31
|
* Optional handler for `POST /sync` — receives `controlplane.sync.*` events
|
|
21
32
|
* emitted by tenant shards via `ControlPlaneSyncDestination` and replicates
|
|
@@ -43,6 +54,18 @@ export interface ProxyControlPlaneOptions {
|
|
|
43
54
|
* login.acme.com" needs a view across every tenant that only exists here.
|
|
44
55
|
*/
|
|
45
56
|
customDomains?: CustomDomainsAdapter;
|
|
57
|
+
/**
|
|
58
|
+
* The authoritative tenant-team resource. When set, mounts
|
|
59
|
+
* `/api/v2/proxy/control-plane/tenant-members` — the resource tenant shards
|
|
60
|
+
* call through `createControlPlaneTenantMembersAdapter` to let their admins
|
|
61
|
+
* manage who administers the tenant (control-plane organization membership +
|
|
62
|
+
* org-scoped roles + invitations), rows the shard itself cannot write.
|
|
63
|
+
*
|
|
64
|
+
* Wire the backend to the control-plane database (see
|
|
65
|
+
* `createLocalTenantMembersBackend`); the org is pinned from the verified
|
|
66
|
+
* token, never the request.
|
|
67
|
+
*/
|
|
68
|
+
tenantMembers?: TenantMembersControlPlaneOptions;
|
|
46
69
|
}
|
|
47
70
|
/**
|
|
48
71
|
* Returns a Hono app exposing the privileged proxy control-plane endpoint
|
|
@@ -10,4 +10,11 @@ export declare const CONTROL_PLANE_SYNC_SCOPE = "controlplane:sync";
|
|
|
10
10
|
* `createControlPlaneCustomDomainsAdapter`.
|
|
11
11
|
*/
|
|
12
12
|
export declare const CONTROL_PLANE_CUSTOM_DOMAINS_SCOPE = "controlplane:custom_domains";
|
|
13
|
+
/**
|
|
14
|
+
* Scope required by the authoritative `/tenant-members` resource on the control
|
|
15
|
+
* plane — a tenant's team (organization membership + org-scoped roles +
|
|
16
|
+
* invitations) that only the control plane can write. Tenant shards mint a
|
|
17
|
+
* token with this scope through `createControlPlaneTenantMembersAdapter`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CONTROL_PLANE_TENANT_MEMBERS_SCOPE = "controlplane:tenant_members";
|
|
13
20
|
export { PROXY_RESOLVE_HOST_SCOPE };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Hono, type Context } from "hono";
|
|
2
|
+
import { Bindings } from "../../types";
|
|
3
|
+
import { TenantMembersBackend } from "../../tenant-members/types";
|
|
4
|
+
import type { AuthenticateControlPlane } from "./custom-domains";
|
|
5
|
+
type TenantVars = {
|
|
6
|
+
tenantId: string;
|
|
7
|
+
};
|
|
8
|
+
/** Context seen by the control-plane resource: env + the pinned tenant id. */
|
|
9
|
+
type CpCtx = Context<{
|
|
10
|
+
Bindings: Bindings;
|
|
11
|
+
Variables: TenantVars;
|
|
12
|
+
}>;
|
|
13
|
+
export interface TenantMembersControlPlaneOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Build the backend for a request. Bound to the control-plane database
|
|
16
|
+
* (`c.env.data`) and, optionally, an email sender at wire-up time. The tenant
|
|
17
|
+
* is pinned separately from the verified token, so the factory does not need
|
|
18
|
+
* it.
|
|
19
|
+
*/
|
|
20
|
+
getBackend: (c: CpCtx) => TenantMembersBackend | Promise<TenantMembersBackend>;
|
|
21
|
+
authenticate: AuthenticateControlPlane;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The authoritative `tenant-members` resource. Tenant shards reach it through
|
|
25
|
+
* `createControlPlaneTenantMembersAdapter`; it manages the control-plane
|
|
26
|
+
* organization that models a tenant's team — rows the shard cannot write.
|
|
27
|
+
*
|
|
28
|
+
* Every operation is bound to the `tenant_id` claim of the verified token. The
|
|
29
|
+
* scope alone is not authorization: each shard holds it, so a request-supplied
|
|
30
|
+
* tenant id would let any shard read or edit any other tenant's team. Mount
|
|
31
|
+
* under `/api/v2/proxy/control-plane/tenant-members`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createTenantMembersControlPlaneApp(options: TenantMembersControlPlaneOptions): Hono<{
|
|
34
|
+
Bindings: Bindings;
|
|
35
|
+
Variables: TenantVars;
|
|
36
|
+
}>;
|
|
37
|
+
export {};
|
|
@@ -38,6 +38,20 @@ export interface VerifyControlPlaneTokenOptions {
|
|
|
38
38
|
* `proxy:resolve_host`.
|
|
39
39
|
*/
|
|
40
40
|
requiredScope?: string | string[];
|
|
41
|
+
/**
|
|
42
|
+
* Optional predicate consulted IN ADDITION to `expectedIssuers`, for issuers
|
|
43
|
+
* that can't be enumerated ahead of time — specifically a deployment's own
|
|
44
|
+
* Workers-for-Platforms tenant subdomains (`https://{tenant}.{host}/`), whose
|
|
45
|
+
* per-tenant control-plane credential the accompanying `jwksFetch` resolves
|
|
46
|
+
* locally (see #1139).
|
|
47
|
+
*
|
|
48
|
+
* Like `expectedIssuers`, it runs BEFORE the JWKS fetch, so it still gates
|
|
49
|
+
* where the verifier will fetch keys from: return `true` only for issuer
|
|
50
|
+
* hosts you actually serve. The signature must still verify against the
|
|
51
|
+
* resolved key, so this does not broaden trust beyond "a caller holding that
|
|
52
|
+
* tenant's registered private key."
|
|
53
|
+
*/
|
|
54
|
+
isTrustedIssuer?: (iss: string) => boolean;
|
|
41
55
|
}
|
|
42
56
|
/**
|
|
43
57
|
* Verify a bearer token for the proxy control plane. Returns `{ ok: true }`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -456,7 +456,7 @@ export declare function initJSXRoute(ctx: Context<{
|
|
|
456
456
|
custom_login_page_preview?: string | undefined;
|
|
457
457
|
form_template?: string | undefined;
|
|
458
458
|
addons?: Record<string, any> | undefined;
|
|
459
|
-
token_endpoint_auth_method?: "
|
|
459
|
+
token_endpoint_auth_method?: "client_secret_post" | "client_secret_basic" | "none" | "client_secret_jwt" | "private_key_jwt" | undefined;
|
|
460
460
|
client_metadata?: Record<string, string> | undefined;
|
|
461
461
|
hide_sign_up_disabled_error?: boolean | undefined;
|
|
462
462
|
mobile?: Record<string, any> | undefined;
|
|
@@ -1185,7 +1185,7 @@ export declare function initJSXRouteWithSession(ctx: Context<{
|
|
|
1185
1185
|
custom_login_page_preview?: string | undefined;
|
|
1186
1186
|
form_template?: string | undefined;
|
|
1187
1187
|
addons?: Record<string, any> | undefined;
|
|
1188
|
-
token_endpoint_auth_method?: "
|
|
1188
|
+
token_endpoint_auth_method?: "client_secret_post" | "client_secret_basic" | "none" | "client_secret_jwt" | "private_key_jwt" | undefined;
|
|
1189
1189
|
client_metadata?: Record<string, string> | undefined;
|
|
1190
1190
|
hide_sign_up_disabled_error?: boolean | undefined;
|
|
1191
1191
|
mobile?: Record<string, any> | undefined;
|
|
@@ -27,7 +27,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
27
27
|
output: {
|
|
28
28
|
screen: {
|
|
29
29
|
action: string;
|
|
30
|
-
method: "
|
|
30
|
+
method: "GET" | "POST";
|
|
31
31
|
components: {
|
|
32
32
|
id: string;
|
|
33
33
|
type: string;
|
|
@@ -43,7 +43,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
43
43
|
hint?: string | undefined;
|
|
44
44
|
messages?: {
|
|
45
45
|
text: string;
|
|
46
|
-
type: "
|
|
46
|
+
type: "success" | "error" | "info" | "warning";
|
|
47
47
|
id?: number | undefined;
|
|
48
48
|
}[] | undefined;
|
|
49
49
|
}[];
|
|
@@ -51,7 +51,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
51
51
|
description?: string | undefined;
|
|
52
52
|
messages?: {
|
|
53
53
|
text: string;
|
|
54
|
-
type: "
|
|
54
|
+
type: "success" | "error" | "info" | "warning";
|
|
55
55
|
id?: number | undefined;
|
|
56
56
|
}[] | undefined;
|
|
57
57
|
links?: {
|
|
@@ -107,7 +107,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
107
107
|
output: {
|
|
108
108
|
screen: {
|
|
109
109
|
action: string;
|
|
110
|
-
method: "
|
|
110
|
+
method: "GET" | "POST";
|
|
111
111
|
components: {
|
|
112
112
|
id: string;
|
|
113
113
|
type: string;
|
|
@@ -123,7 +123,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
123
123
|
hint?: string | undefined;
|
|
124
124
|
messages?: {
|
|
125
125
|
text: string;
|
|
126
|
-
type: "
|
|
126
|
+
type: "success" | "error" | "info" | "warning";
|
|
127
127
|
id?: number | undefined;
|
|
128
128
|
}[] | undefined;
|
|
129
129
|
}[];
|
|
@@ -131,7 +131,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
131
131
|
description?: string | undefined;
|
|
132
132
|
messages?: {
|
|
133
133
|
text: string;
|
|
134
|
-
type: "
|
|
134
|
+
type: "success" | "error" | "info" | "warning";
|
|
135
135
|
id?: number | undefined;
|
|
136
136
|
}[] | undefined;
|
|
137
137
|
links?: {
|
|
@@ -204,7 +204,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
204
204
|
output: {
|
|
205
205
|
screen: {
|
|
206
206
|
action: string;
|
|
207
|
-
method: "
|
|
207
|
+
method: "GET" | "POST";
|
|
208
208
|
components: {
|
|
209
209
|
id: string;
|
|
210
210
|
type: string;
|
|
@@ -220,7 +220,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
220
220
|
hint?: string | undefined;
|
|
221
221
|
messages?: {
|
|
222
222
|
text: string;
|
|
223
|
-
type: "
|
|
223
|
+
type: "success" | "error" | "info" | "warning";
|
|
224
224
|
id?: number | undefined;
|
|
225
225
|
}[] | undefined;
|
|
226
226
|
}[];
|
|
@@ -228,7 +228,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
228
228
|
description?: string | undefined;
|
|
229
229
|
messages?: {
|
|
230
230
|
text: string;
|
|
231
|
-
type: "
|
|
231
|
+
type: "success" | "error" | "info" | "warning";
|
|
232
232
|
id?: number | undefined;
|
|
233
233
|
}[] | undefined;
|
|
234
234
|
links?: {
|
|
@@ -319,7 +319,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
319
319
|
output: {
|
|
320
320
|
screen: {
|
|
321
321
|
action: string;
|
|
322
|
-
method: "
|
|
322
|
+
method: "GET" | "POST";
|
|
323
323
|
components: {
|
|
324
324
|
id: string;
|
|
325
325
|
type: string;
|
|
@@ -335,7 +335,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
335
335
|
hint?: string | undefined;
|
|
336
336
|
messages?: {
|
|
337
337
|
text: string;
|
|
338
|
-
type: "
|
|
338
|
+
type: "success" | "error" | "info" | "warning";
|
|
339
339
|
id?: number | undefined;
|
|
340
340
|
}[] | undefined;
|
|
341
341
|
}[];
|
|
@@ -343,7 +343,7 @@ export declare const flowApiRoutes: OpenAPIHono<{
|
|
|
343
343
|
description?: string | undefined;
|
|
344
344
|
messages?: {
|
|
345
345
|
text: string;
|
|
346
|
-
type: "
|
|
346
|
+
type: "success" | "error" | "info" | "warning";
|
|
347
347
|
id?: number | undefined;
|
|
348
348
|
}[] | undefined;
|
|
349
349
|
links?: {
|
|
@@ -165,7 +165,7 @@ export default function createU2App(config: AuthHeroConfig): OpenAPIHono<{
|
|
|
165
165
|
$get: {
|
|
166
166
|
input: {
|
|
167
167
|
param: {
|
|
168
|
-
screen: "signup" | "
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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,6 +315,14 @@ 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
|
|
@@ -335,6 +343,30 @@ export interface AuthHeroConfig {
|
|
|
335
343
|
* needs a view across every tenant that only exists here.
|
|
336
344
|
*/
|
|
337
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;
|
|
355
|
+
};
|
|
356
|
+
/**
|
|
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;
|
|
338
370
|
};
|
|
339
371
|
/**
|
|
340
372
|
* Optional outbox-driven replication of `proxy_routes` mutations to a global
|