@estifanos-sh/convex-auth 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/_generated/component.d.ts +130 -61
- package/dist/_generated/component.d.ts.map +1 -1
- package/dist/_generated/dataModel.d.ts +28 -0
- package/dist/_generated/dataModel.d.ts.map +1 -0
- package/dist/bin.js +1 -2
- package/dist/browser/index.d.ts +2 -2
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/client/core/types.d.ts +40 -79
- package/dist/client/core/types.d.ts.map +1 -1
- package/dist/client/core/types.js.map +1 -1
- package/dist/client/errors.d.ts +15 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +8 -1
- package/dist/client/errors.js.map +1 -1
- package/dist/client/index.d.ts +6 -3
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -2
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/component.d.ts +130 -61
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/_generated/dataModel.d.ts +1 -1
- package/dist/component/_generated/server.d.ts +1 -1
- package/dist/component/account.d.ts +43 -37
- package/dist/component/account.d.ts.map +1 -1
- package/dist/component/account.js +14 -16
- package/dist/component/account.js.map +1 -1
- package/dist/component/connection/audit.d.ts +29 -29
- package/dist/component/connection/audit.d.ts.map +1 -1
- package/dist/component/connection/audit.js +2 -1
- package/dist/component/connection/audit.js.map +1 -1
- package/dist/component/connection/cache.d.ts +6 -6
- package/dist/component/connection/domain/verification.d.ts +19 -19
- package/dist/component/connection/domain.d.ts +20 -20
- package/dist/component/connection/saml/assertion.d.ts +4 -4
- package/dist/component/connection/saml/request.d.ts +9 -9
- package/dist/component/connection/saml/request.d.ts.map +1 -1
- package/dist/component/connection/scim/config.d.ts +13 -13
- package/dist/component/connection/scim/identity.d.ts +102 -59
- package/dist/component/connection/scim/identity.d.ts.map +1 -1
- package/dist/component/connection/scim/identity.js +357 -56
- package/dist/component/connection/scim/identity.js.map +1 -1
- package/dist/component/connection/secret.d.ts +15 -15
- package/dist/component/connection/secret.d.ts.map +1 -1
- package/dist/component/connection/webhook/delivery.d.ts +69 -53
- package/dist/component/connection/webhook/delivery.d.ts.map +1 -1
- package/dist/component/connection/webhook/delivery.js +127 -170
- package/dist/component/connection/webhook/delivery.js.map +1 -1
- package/dist/component/connection/webhook/endpoint.d.ts +21 -21
- package/dist/component/connection/webhook/events.d.ts +26 -0
- package/dist/component/connection/webhook/events.d.ts.map +1 -0
- package/dist/component/connection/webhook/events.js +39 -0
- package/dist/component/connection/webhook/events.js.map +1 -0
- package/dist/component/connection.d.ts +38 -38
- package/dist/component/connection.d.ts.map +1 -1
- package/dist/component/context.d.ts +115 -0
- package/dist/component/context.d.ts.map +1 -0
- package/dist/component/context.js +50 -0
- package/dist/component/context.js.map +1 -0
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/crons.d.ts +2 -2
- package/dist/component/event.d.ts +134 -138
- package/dist/component/event.d.ts.map +1 -1
- package/dist/component/event.js +88 -117
- package/dist/component/event.js.map +1 -1
- package/dist/component/eventstream.d.ts +30 -0
- package/dist/component/eventstream.d.ts.map +1 -0
- package/dist/component/eventstream.js +51 -0
- package/dist/component/eventstream.js.map +1 -0
- package/dist/component/factor/device.d.ts +25 -24
- package/dist/component/factor/device.d.ts.map +1 -1
- package/dist/component/factor/device.js +5 -2
- package/dist/component/factor/device.js.map +1 -1
- package/dist/component/factor/passkey.d.ts +84 -75
- package/dist/component/factor/passkey.d.ts.map +1 -1
- package/dist/component/factor/passkey.js +6 -6
- package/dist/component/factor/passkey.js.map +1 -1
- package/dist/component/factor/totp.d.ts +54 -49
- package/dist/component/factor/totp.d.ts.map +1 -1
- package/dist/component/factor/totp.js +3 -3
- package/dist/component/factor/totp.js.map +1 -1
- package/dist/component/group/active.d.ts +326 -22
- package/dist/component/group/active.d.ts.map +1 -1
- package/dist/component/group/active.js +21 -11
- package/dist/component/group/active.js.map +1 -1
- package/dist/component/group/invite.d.ts +28 -28
- package/dist/component/group/invite.d.ts.map +1 -1
- package/dist/component/group/member.d.ts +34 -34
- package/dist/component/group.d.ts +47 -62
- package/dist/component/group.d.ts.map +1 -1
- package/dist/component/http.d.ts +2 -2
- package/dist/component/limits.d.ts +4 -4
- package/dist/component/maintenance.d.ts +2 -2
- package/dist/component/model.d.ts +1362 -1027
- package/dist/component/model.d.ts.map +1 -1
- package/dist/component/model.js +23 -6
- package/dist/component/model.js.map +1 -1
- package/dist/component/modules.d.ts +8 -2
- package/dist/component/modules.d.ts.map +1 -1
- package/dist/component/modules.js +3 -0
- package/dist/component/modules.js.map +1 -1
- package/dist/component/oauth/client.d.ts +20 -20
- package/dist/component/oauth/code.d.ts +14 -14
- package/dist/component/oauth/refresh.d.ts +19 -19
- package/dist/component/schema.d.ts +1100 -611
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +17 -4
- package/dist/component/schema.js.map +1 -1
- package/dist/component/session.d.ts +72 -32
- package/dist/component/session.d.ts.map +1 -1
- package/dist/component/session.js +120 -32
- package/dist/component/session.js.map +1 -1
- package/dist/component/token/continuation.d.ts +40 -18
- package/dist/component/token/continuation.d.ts.map +1 -1
- package/dist/component/token/continuation.js +57 -11
- package/dist/component/token/continuation.js.map +1 -1
- package/dist/component/token/pkce.d.ts +22 -22
- package/dist/component/token/pkce.d.ts.map +1 -1
- package/dist/component/token/refresh.d.ts +39 -35
- package/dist/component/token/refresh.d.ts.map +1 -1
- package/dist/component/token/refresh.js +11 -6
- package/dist/component/token/refresh.js.map +1 -1
- package/dist/component/token/verification.d.ts +36 -32
- package/dist/component/token/verification.d.ts.map +1 -1
- package/dist/component/token/verification.js +3 -3
- package/dist/component/token/verification.js.map +1 -1
- package/dist/component/user/email.d.ts +21 -21
- package/dist/component/user/key.d.ts +35 -35
- package/dist/component/user/key.d.ts.map +1 -1
- package/dist/component/user.d.ts +51 -45
- package/dist/component/user.d.ts.map +1 -1
- package/dist/core/index.d.ts +54 -90
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -4
- package/dist/core/index.js.map +1 -1
- package/dist/expo/index.d.ts +3 -3
- package/dist/expo/index.d.ts.map +1 -1
- package/dist/expo/index.js.map +1 -1
- package/dist/model.js.map +1 -1
- package/dist/providers/anonymous.d.ts +11 -5
- package/dist/providers/anonymous.d.ts.map +1 -1
- package/dist/providers/anonymous.js +4 -1
- package/dist/providers/anonymous.js.map +1 -1
- package/dist/providers/apple.d.ts +1 -1
- package/dist/providers/credentials.d.ts +21 -13
- package/dist/providers/credentials.d.ts.map +1 -1
- package/dist/providers/credentials.js +2 -0
- package/dist/providers/credentials.js.map +1 -1
- package/dist/providers/custom.d.ts +3 -3
- package/dist/providers/custom.d.ts.map +1 -1
- package/dist/providers/custom.js.map +1 -1
- package/dist/providers/email.d.ts +3 -3
- package/dist/providers/email.d.ts.map +1 -1
- package/dist/providers/email.js.map +1 -1
- package/dist/providers/github.d.ts +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/microsoft.d.ts +1 -1
- package/dist/providers/password.d.ts +103 -8
- package/dist/providers/password.d.ts.map +1 -1
- package/dist/providers/password.js +71 -26
- package/dist/providers/password.js.map +1 -1
- package/dist/providers/phone.d.ts +4 -3
- package/dist/providers/phone.d.ts.map +1 -1
- package/dist/providers/phone.js.map +1 -1
- package/dist/react/index.d.ts +40 -41
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +27 -52
- package/dist/react/index.js.map +1 -1
- package/dist/server/auth.d.ts +157 -117
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +41 -22
- package/dist/server/auth.js.map +1 -1
- package/dist/server/component/factor/db.js +4 -4
- package/dist/server/component/factor/db.js.map +1 -1
- package/dist/server/config.d.ts +2 -1
- package/dist/server/connection/domain.d.ts +4 -66
- package/dist/server/connection/domain.d.ts.map +1 -1
- package/dist/server/connection/domain.js +22 -4
- package/dist/server/connection/domain.js.map +1 -1
- package/dist/server/connection/group/service.js +6 -4
- package/dist/server/connection/group/service.js.map +1 -1
- package/dist/server/connection/http.js +94 -261
- package/dist/server/connection/http.js.map +1 -1
- package/dist/server/connection/oidc.js +8 -17
- package/dist/server/connection/oidc.js.map +1 -1
- package/dist/server/connection/policy/domain.js +4 -1
- package/dist/server/connection/policy/domain.js.map +1 -1
- package/dist/server/connection/policy.js +14 -13
- package/dist/server/connection/policy.js.map +1 -1
- package/dist/server/connection/provision.js +5 -19
- package/dist/server/connection/provision.js.map +1 -1
- package/dist/server/connection/webhook.js +4 -36
- package/dist/server/connection/webhook.js.map +1 -1
- package/dist/server/context.d.ts +2 -2
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/context.js +35 -24
- package/dist/server/context.js.map +1 -1
- package/dist/server/contract.d.ts.map +1 -1
- package/dist/server/contract.js +6 -14
- package/dist/server/contract.js.map +1 -1
- package/dist/server/core.js +6 -0
- package/dist/server/core.js.map +1 -1
- package/dist/server/cors.d.ts +2 -2
- package/dist/server/cors.d.ts.map +1 -1
- package/dist/server/crypto.js.map +1 -1
- package/dist/server/db.js +2 -1
- package/dist/server/db.js.map +1 -1
- package/dist/server/domains/context.js +34 -0
- package/dist/server/domains/context.js.map +1 -0
- package/dist/server/domains/factor.d.ts +3 -2
- package/dist/server/domains/factor.d.ts.map +1 -1
- package/dist/server/domains/factor.js.map +1 -1
- package/dist/server/domains/group.js.map +1 -1
- package/dist/server/domains/invite.js.map +1 -1
- package/dist/server/domains/key.js.map +1 -1
- package/dist/server/domains/member.js.map +1 -1
- package/dist/server/domains/session.js.map +1 -1
- package/dist/server/domains/user.js.map +1 -1
- package/dist/server/env.js +2 -22
- package/dist/server/env.js.map +1 -1
- package/dist/server/events.d.ts +0 -1
- package/dist/server/events.d.ts.map +1 -1
- package/dist/server/events.js +6 -6
- package/dist/server/events.js.map +1 -1
- package/dist/server/http.d.ts +1 -0
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +4 -4
- package/dist/server/http.js.map +1 -1
- package/dist/server/identity/claims.js +1 -1
- package/dist/server/identity/convex.d.ts +2 -0
- package/dist/server/identity/convex.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -3
- package/dist/server/index.js +1 -2
- package/dist/server/limits.js +21 -1
- package/dist/server/limits.js.map +1 -1
- package/dist/server/mutations/credentials/signin.js +6 -3
- package/dist/server/mutations/credentials/signin.js.map +1 -1
- package/dist/server/mutations/invalidate.js +5 -10
- package/dist/server/mutations/invalidate.js.map +1 -1
- package/dist/server/mutations/oauth.js +1 -1
- package/dist/server/mutations/oauth.js.map +1 -1
- package/dist/server/mutations/retrieve.js +4 -1
- package/dist/server/mutations/retrieve.js.map +1 -1
- package/dist/server/mutations/signin.js +2 -2
- package/dist/server/mutations/signin.js.map +1 -1
- package/dist/server/mutations/verify.js +4 -3
- package/dist/server/mutations/verify.js.map +1 -1
- package/dist/server/oauth/factory.js.map +1 -1
- package/dist/server/runtime.d.ts +107 -127
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/server/runtime.js +43 -28
- package/dist/server/runtime.js.map +1 -1
- package/dist/server/session/lifecycle.d.ts.map +1 -1
- package/dist/server/session/lifecycle.js +18 -3
- package/dist/server/session/lifecycle.js.map +1 -1
- package/dist/server/signin/flow.js +1 -1
- package/dist/server/signin/flow.js.map +1 -1
- package/dist/server/tokens.js +1 -0
- package/dist/server/tokens.js.map +1 -1
- package/dist/server/totp.js +3 -3
- package/dist/server/totp.js.map +1 -1
- package/dist/server/types.d.ts +63 -43
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/user/account.js +0 -1
- package/dist/server/user/account.js.map +1 -1
- package/dist/server/validators.d.ts +874 -917
- package/dist/server/validators.d.ts.map +1 -1
- package/dist/server/validators.js +33 -32
- package/dist/server/validators.js.map +1 -1
- package/dist/server/webauthn.js +4 -4
- package/dist/server/webauthn.js.map +1 -1
- package/dist/shared/brand.d.ts +3 -7
- package/dist/shared/brand.d.ts.map +1 -1
- package/dist/shared/params.d.ts +78 -0
- package/dist/shared/params.d.ts.map +1 -0
- package/dist/shared/results.d.ts +7 -1
- package/dist/shared/results.d.ts.map +1 -1
- package/dist/svelte/context.svelte.d.ts +23 -12
- package/dist/svelte/context.svelte.d.ts.map +1 -1
- package/dist/svelte/context.svelte.js +20 -13
- package/dist/svelte/index.d.ts +1 -4
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +1 -4
- package/dist/test.d.ts +1105 -611
- package/dist/test.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/server/env.d.ts +0 -28
- package/dist/server/env.d.ts.map +0 -1
- package/dist/svelte/AuthLoading.svelte +0 -13
- package/dist/svelte/AuthLoading.svelte.d.ts +0 -8
- package/dist/svelte/AuthLoading.svelte.d.ts.map +0 -1
- package/dist/svelte/SignedIn.svelte +0 -14
- package/dist/svelte/SignedIn.svelte.d.ts +0 -8
- package/dist/svelte/SignedIn.svelte.d.ts.map +0 -1
- package/dist/svelte/SignedOut.svelte +0 -13
- package/dist/svelte/SignedOut.svelte.d.ts +0 -8
- package/dist/svelte/SignedOut.svelte.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","names":["serializeCookie","ctx","state","location"],"sources":["../../../src/server/connection/http.ts"],"sourcesContent":["import type { GenericActionCtx, GenericDataModel, HttpRouter } from \"convex/server\";\nimport { ConvexError } from \"convex/values\";\nimport { serialize as serializeCookie } from \"cookie\";\n\nimport { configDefaults } from \"../config\";\nimport {\n getScimIdentity,\n getScimIdentityByConnectionAndUser,\n getScimIdentityByMappedGroup,\n insertUser,\n listScimIdentitiesByConnection,\n provisionScimUser,\n removeScimIdentity,\n updateUser,\n upsertScimIdentity,\n type ScimIdentityRecord,\n} from \"../contract\";\nimport { redirectToParamCookie, useRedirectToParam } from \"../cookies\";\nimport { convexError } from \"../errors\";\nimport { ErrorCode } from \"../../shared/codes\";\nimport { addConnectionRoutes, convertErrorsToResponse, getCookies } from \"../http\";\nimport type { ConnectionRuntimeRoute } from \"../http\";\nimport { log } from \"../log\";\nimport { createOAuthAuthorizationURL, handleOAuthCallback } from \"../oauth/runtime\";\nimport type { AuthAccountExtend, AuthProfile } from \"../payloads\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"../redirects\";\nimport type { AuthEventKind, AuthEventObject, AuthEventSubject } from \"../events\";\nimport type { EmitGroupAuthEventInput } from \"./group/service\";\nimport type { GroupConnectionPolicy } from \"../types\";\nimport { createGroupConnectionOidcRuntime } from \"./oidc\";\nimport { resolveProvisionedRoleIds } from \"./policy\";\nimport { finalizeNormalizedProfile, normalizeStringArray } from \"./profile\";\nimport {\n createGroupConnectionSamlMetadataXml,\n createGroupConnectionSamlSignInRequest,\n createSamlPostBindingResponse,\n encodeGroupSamlRelayState,\n enforceGroupConnectionSamlSecurity,\n getSamlServiceProviderOptions,\n parseGroupConnectionSamlLoginResponse,\n parseGroupConnectionSamlLogoutMessage,\n profileFromSamlExtract,\n samlReplayIdentifiers,\n validateGroupConnectionSamlLoginRelayState,\n} from \"./saml\";\nimport {\n parseScimListRequest,\n scimError,\n scimJson,\n serializeScimGroup,\n serializeScimUser,\n} from \"./scim\";\nimport {\n decodeGroupOidcState,\n encodeGroupOidcState,\n groupOidcProviderId,\n groupSamlProviderId,\n SCIM_GROUP_SCHEMA_ID,\n SCIM_USER_SCHEMA_ID,\n} from \"./shared\";\n\ntype ComponentConfig = ReturnType<typeof configDefaults>;\n\ntype AuthRuntime = {\n user: {\n get(ctx: GenericActionCtx<GenericDataModel>, args: { id: string }): Promise<UserRecord | null>;\n };\n group: {\n get(ctx: GenericActionCtx<GenericDataModel>, args: { id: string }): Promise<GroupRecord | null>;\n list(\n ctx: GenericActionCtx<GenericDataModel>,\n opts: {\n where?: Record<string, unknown>;\n paginationOpts: { numItems: number; cursor: string | null };\n },\n ): Promise<{ page: Array<Record<string, unknown>>; isDone: boolean; continueCursor: string }>;\n create(\n ctx: GenericActionCtx<GenericDataModel>,\n args: { data: { name: string; parentGroupId: string; type: string } },\n ): Promise<string>;\n update(\n ctx: GenericActionCtx<GenericDataModel>,\n args: { id: string; patch: Record<string, unknown> },\n ): Promise<null>;\n remove(ctx: GenericActionCtx<GenericDataModel>, args: { id: string }): Promise<null>;\n };\n member: {\n list(\n ctx: GenericActionCtx<GenericDataModel>,\n opts: {\n where?: Record<string, unknown>;\n paginationOpts: { numItems: number; cursor: string | null };\n },\n ): Promise<{\n page: Array<{ _id: string; userId: string; status?: string }>;\n isDone: boolean;\n continueCursor: string;\n }>;\n create(\n ctx: GenericActionCtx<GenericDataModel>,\n args: {\n data: {\n groupId: string;\n userId: string;\n roleIds: string[];\n status: string;\n };\n },\n ): Promise<string>;\n update(\n ctx: GenericActionCtx<GenericDataModel>,\n args: { id: string; patch: Record<string, unknown> },\n ): Promise<null>;\n remove(ctx: GenericActionCtx<GenericDataModel>, args: { id: string }): Promise<null>;\n get(\n ctx: GenericActionCtx<GenericDataModel>,\n args: { groupId: string; userId: string },\n ): Promise<{ membership: { _id: string } | null }>;\n };\n};\n\ntype ActiveSamlConnection = {\n loaded: {\n source: { kind: \"connection\"; id: string };\n config: unknown;\n [key: string]: unknown;\n };\n connection: { _id: string; groupId: string };\n saml: Record<string, unknown>;\n};\n\ntype OidcConnection = {\n connection: { _id: string; groupId: string };\n oidc: Record<string, unknown>;\n};\n\ntype ScimContext = {\n parsedPath: {\n connectionId: string;\n resource: string;\n resourceId?: string;\n };\n connection: { _id: string; groupId: string; protocol: \"oidc\" | \"saml\" };\n scimConfig: {\n _id: string;\n connectionId: string;\n status: string;\n extend?: unknown;\n };\n};\n\ntype GroupPolicy = GroupConnectionPolicy;\n\ntype CookieToSerialize = {\n name: string;\n value: string;\n options: Parameters<typeof serializeCookie>[2];\n};\n\nfunction formDataEntries(formData: unknown): Iterable<[string, string | { name: string }]> {\n return formData as Iterable<[string, string | { name: string }]>;\n}\n\nasync function getOidcCallbackParams(request: Request) {\n const url = new URL(request.url);\n const params = new URLSearchParams(url.searchParams);\n if (request.headers.get(\"Content-Type\")?.includes(\"application/x-www-form-urlencoded\")) {\n const formData = await request.formData();\n for (const [key, value] of formDataEntries(formData)) {\n if (typeof value === \"string\") {\n params.append(key, value);\n }\n }\n }\n return params;\n}\n\ntype MemberRecord = { _id: string; userId: string; status?: string };\ntype UserRecord = { _id: string; email?: string } & Record<string, unknown>;\ntype GroupRecord = { _id: string; name?: string } & Record<string, unknown>;\n\ntype UserListItem = {\n user: UserRecord;\n member: MemberRecord;\n identity?: ScimIdentityRecord;\n};\n\ntype GroupListItem = {\n group: GroupRecord;\n identity?: ScimIdentityRecord;\n memberIds?: string[];\n};\n\ntype GroupHttpRuntimeDeps = {\n http: HttpRouter;\n hasConnection: boolean;\n auth: AuthRuntime;\n config: ComponentConfig;\n routeBase: string;\n requireEnv: (name: string) => string;\n loadActiveConnectionSamlOrThrow: (\n ctx: GenericActionCtx<GenericDataModel>,\n connectionId: string,\n ) => Promise<ActiveSamlConnection>;\n loadConnectionOidcOrThrow: (\n ctx: GenericActionCtx<GenericDataModel>,\n connectionId: string,\n ) => Promise<OidcConnection>;\n getGroupConnectionScimContext: (\n ctx: GenericActionCtx<GenericDataModel>,\n request: Request,\n ) => Promise<ScimContext>;\n loadGroupPolicyOrThrow: (\n ctx: GenericActionCtx<GenericDataModel>,\n groupId: string,\n ) => Promise<GroupPolicy>;\n normalizeGroupConnectionPolicy: (policy: unknown) => GroupPolicy;\n emitGroupAuthEvent: (\n ctx: GenericActionCtx<GenericDataModel>,\n args: EmitGroupAuthEventInput,\n ) => Promise<string>;\n generateRandomString: (length: number, alphabet: string) => string;\n inviteTokenAlphabet: string;\n callUserOAuth: (\n ctx: GenericActionCtx<GenericDataModel>,\n args: {\n provider: string;\n providerAccountId: string;\n signature: string;\n profile: AuthProfile;\n accountExtend?: AuthAccountExtend;\n },\n ) => Promise<string>;\n callVerifierSignature: (\n ctx: GenericActionCtx<GenericDataModel>,\n args: { verifier: string; signature: string },\n ) => Promise<void>;\n sharedOidcRedirectURI?: string;\n};\n\ntype ScimFilterOperator = NonNullable<\n ReturnType<typeof parseScimListRequest>[\"filter\"]\n>[\"operator\"];\n\n/**\n * Upper bound on rows a single SCIM list response will materialize. SCIM list\n * filtering and `totalResults` require the full member/group set, so the\n * handlers cursor-follow to this cap; past it the response is truncated and a\n * warning is logged rather than silently returning a partial first page.\n */\nconst SCIM_COLLECT_LIMIT = 5000;\n\n/**\n * Lifetime of a persisted pending SAML AuthnRequest. Bounds how long an ACS\n * response can accept the request; comfortably covers IdP round-trips and the\n * default 300s clock skew while keeping the pending-request table small.\n */\nconst SAML_LOGIN_REQUEST_TTL_MS = 10 * 60 * 1000;\n\n/**\n * Fallback TTL for the seen-assertion replay cache when an assertion carries no\n * `NotOnOrAfter` bound (only reachable when `requireTimestamps` is disabled).\n */\nconst SAML_SEEN_ASSERTION_FALLBACK_TTL_MS = 10 * 60 * 1000;\n\nconst SCIM_FILTER_OPERATORS = {\n pr: (values) => values.length > 0,\n eq: (values, filterValue) => values.includes(filterValue),\n co: (values, filterValue) => values.some((value) => value.includes(filterValue)),\n sw: (values, filterValue) => values.some((value) => value.startsWith(filterValue)),\n ew: (values, filterValue) => values.some((value) => value.endsWith(filterValue)),\n} satisfies Record<ScimFilterOperator, (values: string[], filterValue: string) => boolean>;\n\nexport function addGroupHttpRuntime(deps: GroupHttpRuntimeDeps) {\n if (!deps.hasConnection) {\n return;\n }\n\n const {\n http,\n auth,\n config,\n requireEnv,\n loadActiveConnectionSamlOrThrow,\n loadConnectionOidcOrThrow,\n getGroupConnectionScimContext,\n loadGroupPolicyOrThrow,\n emitGroupAuthEvent,\n generateRandomString,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n callUserOAuth,\n callVerifierSignature,\n sharedOidcRedirectURI,\n } = deps;\n const GROUP_CONNECTION_ROUTE_BASE = deps.routeBase;\n\n type ScimState = {\n ctx: GenericActionCtx<GenericDataModel>;\n request: Request;\n url: URL;\n parsedPath: ScimContext[\"parsedPath\"];\n connection: ScimContext[\"connection\"];\n scimConfig: ScimContext[\"scimConfig\"];\n policy: GroupPolicy;\n recordScimEvent: (\n kind: AuthEventKind,\n outcome: \"success\" | \"failure\",\n subject: AuthEventSubject,\n data?: Record<string, unknown>,\n ) => Promise<void>;\n };\n\n type ScimHandler = (state: ScimState) => Promise<Response>;\n\n const errorCodeForEvent = (error: unknown, fallback: string) => {\n if (\n error instanceof ConvexError &&\n typeof error.data === \"object\" &&\n error.data !== null &&\n \"code\" in error.data &&\n typeof (error.data as { code?: unknown }).code === \"string\"\n ) {\n return (error.data as { code: string }).code;\n }\n return fallback;\n };\n\n const recordConnectionLoginEvent = async (\n ctx: GenericActionCtx<GenericDataModel>,\n args: {\n connection: { _id: string; groupId: string };\n protocol: \"oidc\" | \"saml\";\n outcome: \"success\" | \"failure\";\n userId?: string;\n error?: unknown;\n },\n ) => {\n await emitGroupAuthEvent(ctx, {\n connectionId: args.connection._id,\n groupId: args.connection.groupId,\n kind: args.outcome === \"success\" ? \"connection.login.succeeded\" : \"connection.login.failed\",\n actor: { type: \"anonymous\" },\n subject: args.userId\n ? { type: \"user\", id: args.userId }\n : { type: \"connection\", id: args.connection._id },\n outcome: args.outcome,\n data:\n args.outcome === \"success\"\n ? {\n connectionId: args.connection._id,\n protocol: args.protocol,\n userId: args.userId,\n }\n : {\n connectionId: args.connection._id,\n protocol: args.protocol,\n errorCode: errorCodeForEvent(args.error, \"OAUTH_PROVIDER_ERROR\"),\n },\n });\n };\n\n /**\n * Enforce server-side SAML replay prevention at the ACS.\n *\n * The signature, audience/recipient/timestamp, and `InResponseTo` checks that\n * ran earlier all travel inside the same replayable POST, so none of them can\n * tell a captured `SAMLResponse` from a resubmitted one. This consumes the\n * single-use pending request (defeating SP-initiated replay) and records the\n * assertion ID in a bounded seen-cache (defeating IdP-initiated replay, which\n * carries no `InResponseTo`). Either check failing means the response was\n * already used: a connection-login failure is emitted and the login is\n * rejected with no session. Throws (never returns) on rejection.\n */\n const enforceSamlAcsReplayDefense = async (\n ctx: GenericActionCtx<GenericDataModel>,\n connection: { _id: string; groupId: string },\n parsed: {\n samlContent: string;\n extract?: Parameters<typeof samlReplayIdentifiers>[0][\"extract\"];\n },\n ): Promise<void> => {\n const nowMs = Date.now();\n const { assertionId, inResponseTo, notOnOrAfter } = samlReplayIdentifiers(parsed);\n const rejectReplay = async (message: string): Promise<never> => {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error: new Error(message),\n });\n throw convexError(ErrorCode.OAUTH_INVALID_STATE, message);\n };\n\n if (typeof inResponseTo === \"string\" && inResponseTo.length > 0) {\n const accepted = (await ctx.runMutation(config.component.connection.saml.request.accept, {\n requestId: inResponseTo,\n now: nowMs,\n connectionId: connection._id,\n })) as boolean;\n if (!accepted) {\n await rejectReplay(\"SAML response replays or references an unknown login request.\");\n }\n }\n\n if (typeof assertionId !== \"string\" || assertionId.length === 0) {\n await rejectReplay(\"SAML assertion is missing an ID required for replay detection.\");\n }\n const expiresAtMs =\n typeof notOnOrAfter === \"string\" && Number.isFinite(new Date(notOnOrAfter).getTime())\n ? new Date(notOnOrAfter).getTime()\n : nowMs + SAML_SEEN_ASSERTION_FALLBACK_TTL_MS;\n const firstSeen = (await ctx.runMutation(config.component.connection.saml.assertion.accept, {\n connectionId: connection._id,\n assertionId: assertionId as string,\n expiresAt: expiresAtMs,\n })) as boolean;\n if (!firstSeen) {\n await rejectReplay(\"SAML assertion has already been used.\");\n }\n };\n\n const SCIM_SCHEMAS = [\n {\n id: SCIM_USER_SCHEMA_ID,\n name: \"User\",\n description: \"User Account\",\n attributes: [\n { name: \"userName\", type: \"string\", required: true },\n { name: \"displayName\", type: \"string\" },\n { name: \"active\", type: \"boolean\" },\n { name: \"emails\", type: \"complex\", multiValued: true },\n ],\n },\n {\n id: SCIM_GROUP_SCHEMA_ID,\n name: \"Group\",\n description: \"Group\",\n attributes: [\n { name: \"displayName\", type: \"string\", required: true },\n { name: \"members\", type: \"complex\", multiValued: true },\n ],\n },\n ] as const;\n\n const SCIM_RESOURCE_TYPES = [\n {\n id: \"User\",\n name: \"User\",\n endpoint: \"/Users\",\n schema: SCIM_USER_SCHEMA_ID,\n },\n {\n id: \"Group\",\n name: \"Group\",\n endpoint: \"/Groups\",\n schema: SCIM_GROUP_SCHEMA_ID,\n },\n ] as const;\n\n const handleStaticScimCollection = <T extends { id?: string; name?: string }>(\n items: readonly T[],\n resourceId: string | undefined,\n opts: { by: \"id\" | \"name\"; notFound: string },\n ) => {\n if (resourceId !== undefined) {\n const item = items.find((entry) => entry[opts.by] === decodeURIComponent(resourceId));\n return item ? scimJson(item) : scimError(404, \"notFound\", opts.notFound);\n }\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: items,\n totalResults: items.length,\n startIndex: 1,\n itemsPerPage: items.length,\n });\n };\n\n const pickPrimaryEmail = (body: ScimBody) =>\n Array.isArray(body.emails)\n ? (body.emails.find((entry) => entry.primary === true)?.value ?? body.emails[0]?.value)\n : undefined;\n\n const pickDisplayName = (body: ScimBody) => {\n const name = typeof body.name === \"object\" && body.name !== null ? body.name : undefined;\n const derivedName = [name?.givenName, name?.familyName].filter(Boolean).join(\" \");\n if (body.displayName !== undefined) {\n return body.displayName;\n }\n if (name?.formatted !== undefined) {\n return name.formatted;\n }\n return derivedName !== \"\" ? derivedName : undefined;\n };\n\n const pickPhone = (body: ScimBody) =>\n Array.isArray(body.phoneNumbers) ? body.phoneNumbers[0]?.value : undefined;\n\n const getScimProfileConfig = (scimConfig: { extend?: unknown } | null | undefined) => {\n const extend =\n typeof scimConfig?.extend === \"object\" && scimConfig.extend !== null\n ? (scimConfig.extend as Record<string, unknown>)\n : {};\n const profile =\n typeof extend.profile === \"object\" && extend.profile !== null\n ? (extend.profile as Record<string, unknown>)\n : {};\n return {\n mapping:\n typeof profile.mapping === \"object\" && profile.mapping !== null\n ? (profile.mapping as Record<string, string>)\n : {},\n extraFields:\n typeof profile.extraFields === \"object\" && profile.extraFields !== null\n ? (profile.extraFields as Record<string, string>)\n : {},\n };\n };\n\n const scimFieldAccessors: Record<string, (body: ScimBody) => unknown> = {\n userName: (body) => body.userName,\n externalId: (body) => body.externalId,\n displayName: (body) => body.displayName,\n \"name.formatted\": (body) => body.name?.formatted,\n \"name.givenName\": (body) => body.name?.givenName,\n \"name.familyName\": (body) => body.name?.familyName,\n \"emails.primary\": (body) => pickPrimaryEmail(body),\n \"emails.value\": (body) =>\n Array.isArray(body.emails)\n ? body.emails\n .map((entry) => entry.value)\n .filter((value): value is string => typeof value === \"string\")\n : undefined,\n \"phoneNumbers.primary\": (body) => pickPhone(body),\n \"phoneNumbers.value\": (body) => pickPhone(body),\n active: (body) => body.active,\n groups: (body) => (body as Record<string, unknown>).groups,\n roles: (body) => (body as Record<string, unknown>).roles,\n };\n\n const resolveScimField = (body: ScimBody, key: string | undefined) => {\n if (!key) {\n return undefined;\n }\n const accessor = scimFieldAccessors[key];\n return accessor ? accessor(body) : (body as Record<string, unknown>)[key];\n };\n\n const extractScimProfile = (\n scimConfig: { extend?: unknown } | null | undefined,\n body: ScimBody,\n ) => {\n const { mapping, extraFields } = getScimProfileConfig(scimConfig);\n const extend = Object.fromEntries(\n Object.entries(extraFields)\n .map(([fieldName, source]) => [fieldName, resolveScimField(body, source)])\n .filter(([, value]) => value !== undefined),\n );\n\n return finalizeNormalizedProfile({\n externalId:\n (resolveScimField(body, mapping.externalId) as string | undefined) ??\n (typeof body.externalId === \"string\" ? body.externalId : undefined),\n name: (resolveScimField(body, mapping.name) as string | undefined) ?? pickDisplayName(body),\n firstName: resolveScimField(body, mapping.firstName) as string | undefined,\n lastName: resolveScimField(body, mapping.lastName) as string | undefined,\n email:\n (resolveScimField(body, mapping.email) as string | undefined) ??\n pickPrimaryEmail(body) ??\n body.userName,\n phone: (resolveScimField(body, mapping.phone) as string | undefined) ?? pickPhone(body),\n active: (resolveScimField(body, mapping.active) as boolean | undefined) ?? body.active,\n groups: pickStringArray(resolveScimField(body, mapping.groups)),\n roles: pickStringArray(resolveScimField(body, mapping.roles)),\n extend: Object.keys(extend).length > 0 ? extend : undefined,\n });\n };\n\n const pickStringArray = (value: unknown) => {\n return normalizeStringArray(\n Array.isArray(value)\n ? value.map((entry) => {\n if (typeof entry === \"string\") {\n return entry;\n }\n if (\n typeof entry === \"object\" &&\n entry !== null &&\n typeof (entry as { value?: unknown }).value === \"string\"\n ) {\n return (entry as { value: string }).value;\n }\n return undefined;\n })\n : value,\n );\n };\n\n const normalizeScimValues = (value: unknown): string[] => {\n if (Array.isArray(value)) {\n return value.flatMap((entry) => normalizeScimValues(entry));\n }\n if (typeof value === \"string\") {\n return [value];\n }\n if (typeof value === \"boolean\") {\n return [String(value)];\n }\n return [];\n };\n\n const applyUserProvisioningPatch = (args: {\n currentUser: Record<string, unknown>;\n nextUser: Record<string, unknown>;\n policy: {\n authority?: \"app\" | \"connection\" | \"scim\";\n updateProfileOnLogin?: \"never\" | \"missing\" | \"always\";\n updateProfileFromScim?: \"never\" | \"missing\" | \"always\";\n };\n source: \"scim\";\n }) => {\n const mode = args.policy.updateProfileFromScim ?? \"always\";\n if (mode === \"never\") {\n return {};\n }\n if (mode === \"always\") {\n return args.nextUser;\n }\n return Object.fromEntries(\n Object.entries(args.nextUser).filter(([key, value]) => {\n if (value === undefined) {\n return false;\n }\n const current = args.currentUser[key];\n return current === undefined || current === null || current === \"\";\n }),\n );\n };\n\n const filterScimCollection = <T>(\n items: T[],\n filter: ReturnType<typeof parseScimListRequest>[\"filter\"],\n filters: Record<string, (item: T) => unknown>,\n ) => {\n if (!filter) {\n return items;\n }\n const accessor = filters[filter.attribute];\n if (!accessor) {\n throw new Error(\"Unsupported SCIM filter.\");\n }\n const matchesOperator = SCIM_FILTER_OPERATORS[filter.operator];\n return items.filter((item) =>\n matchesOperator(normalizeScimValues(accessor(item)), filter.value ?? \"\"),\n );\n };\n\n const paginateScimCollection = <T>(\n items: T[],\n listRequest: ReturnType<typeof parseScimListRequest>,\n ) => {\n const start = listRequest.startIndex - 1;\n return items.slice(start, start + listRequest.count);\n };\n\n const requireScimResourceId = (resourceId: string | undefined, label: string) => {\n if (!resourceId) {\n return scimError(400, \"invalidPath\", `${label} resource ID is required.`);\n }\n return null;\n };\n\n const readScimJson = async (request: Request) => {\n const contentType = request.headers.get(\"Content-Type\") ?? \"\";\n if (\n contentType &&\n !contentType.includes(\"application/scim+json\") &&\n !contentType.includes(\"application/json\")\n ) {\n throw new Error(\"Unsupported SCIM content type.\");\n }\n try {\n const body: unknown = await request.json();\n if (typeof body !== \"object\" || body === null || Array.isArray(body)) {\n throw new Error(\"Invalid SCIM JSON.\");\n }\n return body as Record<string, unknown>;\n } catch {\n throw new Error(\"Invalid SCIM JSON.\");\n }\n };\n\n const unsupportedScimPatch = (): never => {\n throw new Error(\"Unsupported SCIM PATCH operation.\");\n };\n\n const scimCollectOverflow = () => new Error(\"SCIM member set too large to reconcile.\");\n\n type ScimBody = Record<string, unknown> & {\n displayName?: string;\n userName?: string;\n active?: boolean;\n externalId?: string;\n emails?: Array<{ value?: string; primary?: boolean }>;\n phoneNumbers?: Array<{ value?: string }>;\n name?: { formatted?: string; givenName?: string; familyName?: string };\n Operations?: Array<{ op?: string; path?: string; value?: unknown }>;\n members?: Array<{ value?: string }>;\n };\n\n const handleSamlAcs = async (\n ctx: GenericActionCtx<GenericDataModel>,\n request: Request,\n runtimeRoute: ConnectionRuntimeRoute,\n ) => {\n if (\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"acs\"\n ) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Invalid connection runtime path.\");\n }\n\n const connectionId = runtimeRoute.connectionId;\n const loadedConnection = await loadActiveConnectionSamlOrThrow(ctx, connectionId);\n const { loaded, connection, saml } = loadedConnection;\n const rootUrl = requireEnv(\"CONVEX_SITE_URL\");\n const serviceProvider = getSamlServiceProviderOptions({\n rootUrl,\n source: { kind: \"connection\", id: connection._id },\n config: loaded.config,\n });\n\n let parsedResponse;\n try {\n parsedResponse = await parseGroupConnectionSamlLoginResponse({\n request,\n rootUrl,\n source: { kind: \"connection\", id: connection._id },\n config: loaded.config,\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error,\n });\n throw convexError(\n \"OAUTH_PROVIDER_ERROR\",\n `SAML response parse failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n try {\n enforceGroupConnectionSamlSecurity({\n extract: parsedResponse.parsed.extract,\n config: loaded.config,\n expectedAudience: serviceProvider.entityId,\n expectedAcsUrl: serviceProvider.acsUrl,\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error,\n });\n throw convexError(\n \"OAUTH_PROVIDER_ERROR\",\n error instanceof Error ? error.message : \"SAML assertion failed security validation.\",\n );\n }\n\n try {\n validateGroupConnectionSamlLoginRelayState({\n relayState: parsedResponse.relayState,\n source: { kind: \"connection\", id: connection._id },\n inResponseTo: parsedResponse.parsed.extract?.subjectConfirmation?.inResponseTo,\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error,\n });\n throw convexError(\n \"OAUTH_INVALID_STATE\",\n \"SAML RelayState did not match the pending login request.\",\n );\n }\n\n await enforceSamlAcsReplayDefense(ctx, connection, parsedResponse.parsed);\n\n const { samlAttributes, samlSessionIndex, ...userProfile } = profileFromSamlExtract(\n parsedResponse.parsed.extract,\n ((saml.profile as Record<string, unknown> | undefined)?.mapping ?? {}) as\n | Record<string, string>\n | undefined,\n );\n const profile = userProfile as Record<string, unknown> & {\n id: string;\n };\n const extraFields =\n typeof saml.profile === \"object\" && saml.profile !== null\n ? ((saml.profile as Record<string, unknown>).extraFields as\n | Record<string, string>\n | undefined)\n : undefined;\n if (extraFields) {\n const extend: Record<string, unknown> = {};\n for (const [fieldName, attributeName] of Object.entries(extraFields)) {\n const value = samlAttributes[attributeName];\n if (value !== undefined) {\n extend[fieldName] = value;\n }\n }\n if (Object.keys(extend).length > 0) {\n profile.extend = extend;\n }\n }\n\n const maybeRedirectTo = useRedirectToParam(\n groupSamlProviderId(connection._id),\n getCookies(request),\n );\n\n let verificationCode: string;\n try {\n verificationCode = await callUserOAuth(ctx, {\n provider: groupSamlProviderId(connection._id),\n providerAccountId: profile.id,\n profile: profile as AuthProfile,\n signature: parsedResponse.relayState.signature,\n accountExtend: {\n identity: {\n protocol: \"saml\",\n connectionId: connection._id,\n subject: profile.id,\n entityId: typeof saml.entityId === \"string\" ? saml.entityId : undefined,\n },\n saml: {\n attributes: samlAttributes as Record<string, string | string[]>,\n sessionIndex: samlSessionIndex,\n },\n },\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error,\n });\n throw error;\n }\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"success\",\n });\n\n const destinationUrl = await redirectAbsoluteUrl(ctx, config, {\n redirectTo:\n maybeRedirectTo?.redirectTo ??\n (typeof parsedResponse.relayState.redirectTo === \"string\"\n ? parsedResponse.relayState.redirectTo\n : undefined),\n });\n\n const vurl = setURLSearchParam(destinationUrl, \"code\", verificationCode);\n const vheaders = new Headers({ Location: vurl });\n vheaders.set(\"Cache-Control\", \"must-revalidate\");\n for (const { name, value, options } of maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []) {\n vheaders.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers: vheaders });\n };\n\n const handleSamlSlo = async (\n ctx: GenericActionCtx<GenericDataModel>,\n request: Request,\n runtimeRoute: ConnectionRuntimeRoute,\n ) => {\n if (\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"slo\"\n ) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Invalid connection runtime path.\");\n }\n const { loaded, connection } = await loadActiveConnectionSamlOrThrow(\n ctx,\n runtimeRoute.connectionId,\n );\n const parsedMessage = await parseGroupConnectionSamlLogoutMessage({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"connection\", id: connection._id },\n config: loaded.config,\n });\n if (parsedMessage.hasSamlRequest) {\n if (!parsedMessage.parsedRequest) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Missing SAML logout payload.\");\n }\n const responseContext = await parsedMessage.runtime.sp.createLogoutResponse(\n parsedMessage.runtime.idp,\n parsedMessage.parsedRequest.extract,\n parsedMessage.binding,\n parsedMessage.relayState ?? \"\",\n );\n if (parsedMessage.binding === \"redirect\") {\n return new Response(null, {\n status: 302,\n headers: { Location: responseContext.context },\n });\n }\n if (!(\"entityEndpoint\" in responseContext)) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Invalid SAML logout response binding.\");\n }\n return createSamlPostBindingResponse({\n endpoint: responseContext.entityEndpoint,\n parameter: \"SAMLResponse\",\n value: responseContext.context,\n relayState: parsedMessage.relayState,\n });\n } else if (parsedMessage.hasSamlResponse) {\n if (!parsedMessage.parsedResponse) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Missing SAML logout response payload.\");\n }\n return new Response(null, { status: 204 });\n } else {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Missing SAML logout payload.\");\n }\n };\n\n const handleScimRequest = async (ctx: GenericActionCtx<GenericDataModel>, request: Request) => {\n try {\n const { scimConfig, connection, parsedPath } = await getGroupConnectionScimContext(\n ctx,\n request,\n );\n const url = new URL(request.url);\n const state: ScimState = {\n ctx,\n request,\n url,\n parsedPath,\n connection,\n scimConfig,\n policy: await loadGroupPolicyOrThrow(ctx, connection.groupId),\n recordScimEvent: async (kind, outcome, subject, data) => {\n try {\n await emitGroupAuthEvent(ctx, {\n connectionId: connection._id,\n groupId: connection.groupId,\n kind,\n actor: { type: \"scim\" },\n subject,\n outcome,\n data,\n webhook: {\n payload: {\n connectionId: connection._id,\n ...(subject.id ? { subjectId: subject.id } : {}),\n ...(data ? { data: data as AuthEventObject } : {}),\n },\n },\n });\n } catch (error) {\n log(\"WARN\", \"[connection.scim] audit event emit failed (best-effort)\", { kind, error });\n }\n },\n };\n\n const collectMembers = async (\n ctx: GenericActionCtx<GenericDataModel>,\n where: { groupId: string; status?: \"active\" },\n ) => {\n const first = await auth.member.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor: null },\n });\n const out = [...first.page];\n let cursor = first.continueCursor;\n let done = first.isDone;\n while (!done && out.length < SCIM_COLLECT_LIMIT) {\n const next = await auth.member.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor },\n });\n out.push(...next.page);\n done = next.isDone;\n cursor = next.continueCursor;\n }\n if (!done) {\n log(\"WARN\", \"[connection.scim] member list truncated at collect limit\", {\n groupId: where.groupId,\n limit: SCIM_COLLECT_LIMIT,\n });\n }\n return out;\n };\n\n /**\n * Fully enumerate a group's active members for an authoritative\n * (destructive) membership replace. Unlike {@link collectMembers}, this\n * refuses to truncate: a `replace` diffs the incoming set against the\n * current set and removes the difference, so a partial read would\n * silently drop overflow members. Throws {@link scimCollectOverflow} past\n * the collect limit so the caller fails the reconcile (413) rather than\n * completing a partial authoritative replace.\n */\n const collectMembersForReplace = async (\n ctx: GenericActionCtx<GenericDataModel>,\n where: { groupId: string; status?: \"active\" },\n ) => {\n const first = await auth.member.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor: null },\n });\n const out = [...first.page];\n let cursor = first.continueCursor;\n let done = first.isDone;\n while (!done) {\n if (out.length > SCIM_COLLECT_LIMIT) {\n throw scimCollectOverflow();\n }\n const next = await auth.member.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor },\n });\n out.push(...next.page);\n done = next.isDone;\n cursor = next.continueCursor;\n }\n return out;\n };\n\n const collectGroups = async (\n ctx: GenericActionCtx<GenericDataModel>,\n where: { parentGroupId: string },\n ) => {\n const first = await auth.group.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor: null },\n });\n const out = [...first.page];\n let cursor = first.continueCursor;\n let done = first.isDone;\n while (!done && out.length < SCIM_COLLECT_LIMIT) {\n const next = await auth.group.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor },\n });\n out.push(...next.page);\n done = next.isDone;\n cursor = next.continueCursor;\n }\n if (!done) {\n log(\"WARN\", \"[connection.scim] group list truncated at collect limit\", {\n parentGroupId: where.parentGroupId,\n limit: SCIM_COLLECT_LIMIT,\n });\n }\n return out;\n };\n\n const userInConnectionScope = async (state: ScimState, userId: string) => {\n const identity = await getScimIdentityByConnectionAndUser(\n state.ctx,\n config.component.connection,\n { connectionId: state.connection._id, userId },\n );\n if (identity) {\n return true;\n }\n const existing = (\n await auth.member.list(state.ctx, {\n where: { groupId: state.connection.groupId, userId },\n paginationOpts: { numItems: 1, cursor: null },\n })\n ).page[0];\n return existing !== undefined;\n };\n\n const firstInvalidScimMember = async (state: ScimState, userIds: Iterable<string>) => {\n for (const userId of userIds) {\n const user = await auth.user.get(state.ctx, { id: userId });\n if (!user || !(await userInConnectionScope(state, userId))) {\n return userId;\n }\n }\n return null;\n };\n\n const handleUsersGet: ScimHandler = async (state) => {\n if (state.parsedPath.resourceId) {\n const userId = state.parsedPath.resourceId;\n const user = await auth.user.get(state.ctx, { id: userId });\n const identity = await getScimIdentityByConnectionAndUser(\n state.ctx,\n config.component.connection,\n { connectionId: state.connection._id, userId },\n );\n const membership = (\n await auth.member.list(state.ctx, {\n where: { groupId: state.connection.groupId, userId },\n paginationOpts: { numItems: 1, cursor: null },\n })\n ).page[0];\n if (!user || !membership) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const typedUser = user as UserRecord;\n await state.recordScimEvent(\n \"connection.scim.read\",\n \"success\",\n { type: \"user\", id: typedUser._id },\n { resourceType: \"user\", resourceId: typedUser._id, operation: \"get\" },\n );\n const location = `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${typedUser._id}`;\n return scimJson(\n serializeScimUser({\n id: typedUser._id,\n user: typedUser,\n externalId: identity?.externalId,\n location,\n active: identity?.active ?? membership?.status === \"active\",\n }),\n 200,\n { Location: location },\n );\n }\n const members = {\n page: await collectMembers(state.ctx, { groupId: state.connection.groupId }),\n };\n const identities = await listScimIdentitiesByConnection(\n state.ctx,\n config.component.connection,\n state.connection._id,\n );\n const identityByUserId = new Map(\n identities\n .filter(\n (identity: ScimIdentityRecord): identity is ScimIdentityRecord & { userId: string } =>\n typeof identity.userId === \"string\",\n )\n .map((identity: ScimIdentityRecord & { userId: string }) => [\n identity.userId,\n identity,\n ]),\n );\n const users = (\n await Promise.all(\n members.page.map(async (member) => {\n const user = await auth.user.get(state.ctx, { id: member.userId });\n const typedUser = user as UserRecord | null;\n return user\n ? {\n user: typedUser,\n member,\n identity: identityByUserId.get(typedUser!._id),\n }\n : null;\n }),\n )\n ).filter(Boolean) as UserListItem[];\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection<UserListItem>(users, listRequest.filter, {\n id: (item) => item.user._id,\n externalId: (item) => item.identity?.externalId,\n userName: (item) => item.user.email ?? item.user.phone ?? item.user.name ?? item.user._id,\n displayName: (item) => item.user.name,\n name: (item) => item.user.name,\n \"name.formatted\": (item) => item.user.name,\n \"name.givenName\": (item) => item.user.firstName,\n \"name.familyName\": (item) => item.user.lastName,\n \"emails.value\": (item) => item.user.email,\n \"phoneNumbers.value\": (item) => item.user.phone,\n active: (item) => item.identity?.active ?? item.member.status === \"active\",\n });\n const paged = paginateScimCollection(filtered, listRequest);\n await state.recordScimEvent(\n \"connection.scim.read\",\n \"success\",\n {\n type: \"connection\",\n id: state.connection._id,\n },\n {\n resourceType: \"user\",\n operation: \"list\",\n },\n );\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ user, identity, member }) =>\n serializeScimUser({\n id: user._id,\n user,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${user._id}`,\n active: identity?.active ?? member.status === \"active\",\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleUsersPost: ScimHandler = async (state) => {\n const body = (await readScimJson(state.request)) as ScimBody;\n const extractedBase = extractScimProfile(state.scimConfig, body);\n const extracted =\n ((await config.connection?.hooks?.profileResolved?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: extractedBase as Record<string, unknown>,\n })) as typeof extractedBase | undefined) ?? extractedBase;\n const provisionProfile =\n ((await config.connection?.hooks?.beforeProvision?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: extracted as Record<string, unknown>,\n })) as typeof extracted | undefined) ?? extracted;\n const externalId = provisionProfile.externalId;\n // Provider under which this connection links SSO accounts. The SCIM\n // externalId is the providerAccountId, so (providerId, externalId) is\n // the Account's natural key — used both to resolve an already-\n // provisioned user below and to dedup the Account insert.\n const providerId =\n state.connection.protocol === \"oidc\"\n ? groupOidcProviderId(state.connection._id)\n : groupSamlProviderId(state.connection._id);\n const provisionedRoleIds = resolveProvisionedRoleIds({\n policy: state.policy,\n groups: provisionProfile.groups,\n roles: provisionProfile.roles,\n });\n const userData = {\n name: provisionProfile.name,\n ...(typeof provisionProfile.firstName === \"string\"\n ? { firstName: provisionProfile.firstName }\n : {}),\n ...(typeof provisionProfile.lastName === \"string\"\n ? { lastName: provisionProfile.lastName }\n : {}),\n email: provisionProfile.email,\n ...(typeof provisionProfile.email === \"string\"\n ? { emailVerificationTime: Date.now() }\n : {}),\n phone: provisionProfile.phone,\n ...(typeof provisionProfile.phone === \"string\"\n ? { phoneVerificationTime: Date.now() }\n : {}),\n ...(provisionProfile.extend ? { extend: provisionProfile.extend } : {}),\n };\n const provisioned = externalId\n ? await provisionScimUser(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n groupId: state.connection.groupId,\n externalId,\n provider: providerId,\n userData,\n active: provisionProfile.active !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n })\n : {\n userId: await insertUser(state.ctx, config.component.user, userData),\n created: true,\n };\n const { userId, created } = provisioned;\n const existingUser = created ? null : await auth.user.get(state.ctx, { id: userId });\n if (!created && existingUser === null) {\n throw new ConvexError({\n code: ErrorCode.ACCOUNT_NOT_FOUND,\n message: \"The SCIM identity references a user that no longer exists.\",\n });\n }\n if (existingUser) {\n const nextUserData: Record<string, unknown> = {\n name: provisionProfile.name,\n firstName: provisionProfile.firstName,\n lastName: provisionProfile.lastName,\n email: provisionProfile.email,\n phone: provisionProfile.phone,\n ...(provisionProfile.extend ? { extend: provisionProfile.extend } : {}),\n };\n if (typeof provisionProfile.email === \"string\") {\n nextUserData.emailVerificationTime = Date.now();\n }\n if (typeof provisionProfile.phone === \"string\") {\n nextUserData.phoneVerificationTime = Date.now();\n }\n const patchData = applyUserProvisioningPatch({\n currentUser: existingUser as Record<string, unknown>,\n nextUser: nextUserData,\n policy: state.policy.provisioning.user,\n source: \"scim\",\n });\n if (Object.keys(patchData).length > 0) {\n await updateUser(state.ctx, config.component.user, {\n userId,\n patch: patchData,\n });\n }\n }\n const resolution = await auth.member.get(state.ctx, {\n groupId: state.connection.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.update(state.ctx, {\n id: resolution.membership._id,\n patch: { status: body.active === false ? \"inactive\" : \"active\" },\n });\n } else {\n await auth.member.create(state.ctx, {\n data: {\n groupId: state.connection.groupId,\n userId,\n roleIds: provisionedRoleIds,\n status: provisionProfile.active === false ? \"inactive\" : \"active\",\n },\n });\n }\n await state.recordScimEvent(\n created ? \"connection.scim.user.provisioned\" : \"connection.scim.user.updated\",\n \"success\",\n { type: \"user\", id: userId },\n );\n const createdUser = await auth.user.get(state.ctx, { id: userId });\n await config.connection?.hooks?.afterProvision?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: provisionProfile as Record<string, unknown>,\n userId,\n });\n const location = `${state.url.origin}${state.url.pathname}/${userId}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: createdUser ?? {},\n externalId,\n location,\n active: provisionProfile.active !== false,\n }),\n created ? 201 : 200,\n { Location: location },\n );\n };\n\n const handleUsersUpsert: ScimHandler = async (state) => {\n const missing = requireScimResourceId(state.parsedPath.resourceId, \"User\");\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const existingUser = await auth.user.get(state.ctx, { id: userId });\n if (!existingUser) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const existingIdentity = await getScimIdentityByConnectionAndUser(\n state.ctx,\n config.component.connection,\n {\n connectionId: state.connection._id,\n userId,\n },\n );\n const existingMembership = await auth.member.get(state.ctx, {\n groupId: state.connection.groupId,\n userId,\n });\n if (!existingIdentity && !existingMembership.membership) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const body = (await readScimJson(state.request)) as ScimBody;\n const extractedBase = extractScimProfile(state.scimConfig, body);\n const extracted =\n ((await config.connection?.hooks?.profileResolved?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: extractedBase as Record<string, unknown>,\n })) as typeof extractedBase | undefined) ?? extractedBase;\n const provisionProfile =\n ((await config.connection?.hooks?.beforeProvision?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: extracted as Record<string, unknown>,\n })) as typeof extracted | undefined) ?? extracted;\n const externalId = provisionProfile.externalId;\n const patchData: Record<string, unknown> = {};\n let nextActive: boolean | undefined;\n if (state.request.method === \"PUT\") {\n patchData.name = provisionProfile.name;\n patchData.firstName = provisionProfile.firstName;\n patchData.lastName = provisionProfile.lastName;\n patchData.email = provisionProfile.email;\n patchData.phone = provisionProfile.phone;\n if (provisionProfile.extend) {\n patchData.extend = provisionProfile.extend;\n }\n if (typeof patchData.email === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n if (typeof patchData.phone === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n } else {\n const operations = Array.isArray(body.Operations)\n ? body.Operations\n : unsupportedScimPatch();\n for (const operation of operations) {\n const op = typeof operation.op === \"string\" ? operation.op.toLowerCase() : \"replace\";\n if (op !== \"replace\" && op !== \"add\") {\n unsupportedScimPatch();\n }\n if (\n operation.path === undefined &&\n typeof operation.value === \"object\" &&\n operation.value !== null\n ) {\n const value = operation.value as Record<string, unknown>;\n if (typeof value.active === \"boolean\") nextActive = value.active;\n if (typeof value.displayName === \"string\") patchData.name = value.displayName;\n if (typeof value.userName === \"string\") {\n patchData.email = value.userName;\n patchData.emailVerificationTime = Date.now();\n }\n continue;\n }\n if (operation.path === \"active\") {\n nextActive = typeof operation.value === \"boolean\" ? operation.value : undefined;\n continue;\n }\n if (operation.path === \"displayName\" || operation.path === \"name.formatted\") {\n patchData.name = operation.value;\n continue;\n }\n if (operation.path === \"name.givenName\") {\n patchData.firstName = operation.value;\n continue;\n }\n if (operation.path === \"name.familyName\") {\n patchData.lastName = operation.value;\n continue;\n }\n if (operation.path === \"userName\" || operation.path === \"emails.value\") {\n patchData.email = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n continue;\n }\n if (operation.path === \"phoneNumbers.value\") {\n patchData.phone = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n continue;\n }\n unsupportedScimPatch();\n }\n }\n const nextPatchData = applyUserProvisioningPatch({\n currentUser: existingUser as Record<string, unknown>,\n nextUser: patchData,\n policy: state.policy.provisioning.user,\n source: \"scim\",\n });\n if (Object.keys(nextPatchData).length > 0) {\n await updateUser(state.ctx, config.component.user, {\n userId,\n patch: nextPatchData,\n });\n }\n const resolution = existingMembership;\n if (resolution.membership) {\n await auth.member.update(state.ctx, {\n id: resolution.membership._id,\n patch: {\n roleIds: resolveProvisionedRoleIds({\n policy: state.policy,\n groups: provisionProfile.groups,\n roles: provisionProfile.roles,\n }),\n status:\n provisionProfile.active === false || nextActive === false ? \"inactive\" : \"active\",\n },\n });\n }\n await upsertScimIdentity(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n groupId: state.connection.groupId,\n resourceType: \"user\",\n externalId: externalId ?? existingIdentity?.externalId ?? userId,\n userId,\n active: provisionProfile.active !== false && nextActive !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n });\n await state.recordScimEvent(\"connection.scim.user.updated\", \"success\", {\n type: \"user\",\n id: userId,\n });\n const updatedUser = await auth.user.get(state.ctx, { id: userId });\n await config.connection?.hooks?.afterProvision?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: provisionProfile as Record<string, unknown>,\n userId,\n });\n const location = `${state.url.origin}${state.url.pathname}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: updatedUser ?? existingUser,\n externalId,\n location,\n active: provisionProfile.active !== false && nextActive !== false,\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleUsersDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(state.parsedPath.resourceId, \"User\");\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const identity = await getScimIdentityByConnectionAndUser(\n state.ctx,\n config.component.connection,\n {\n connectionId: state.connection._id,\n userId,\n },\n );\n if (!identity) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const resolution = await auth.member.get(state.ctx, {\n groupId: state.connection.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.remove(state.ctx, { id: resolution.membership._id });\n }\n const { revoked } = (await state.ctx.runMutation(config.component.session.revokeForUser, {\n userId,\n })) as { revoked: number };\n if (revoked > 0) {\n await state.recordScimEvent(\n \"session.invalidated\",\n \"success\",\n { type: \"user\", id: userId },\n { userId, reason: \"connection_deprovision\" },\n );\n }\n if (state.policy.provisioning.deprovision.mode === \"hard\") {\n await removeScimIdentity(state.ctx, config.component.connection, identity._id);\n } else {\n await upsertScimIdentity(state.ctx, config.component.connection, {\n connectionId: identity.connectionId,\n groupId: identity.groupId,\n resourceType: identity.resourceType,\n externalId: identity.externalId,\n userId: identity.userId,\n mappedGroupId: identity.mappedGroupId,\n active: false,\n raw: identity.raw,\n lastProvisionedAt: Date.now(),\n });\n }\n await state.recordScimEvent(\"connection.scim.user.deactivated\", \"success\", {\n type: \"user\",\n id: userId,\n });\n return new Response(null, { status: 204 });\n };\n\n const handleGroupsGet: ScimHandler = async (state) => {\n if (state.parsedPath.resourceId) {\n const groupId = state.parsedPath.resourceId;\n const group = (await auth.group.get(state.ctx, { id: groupId })) as GroupRecord | null;\n if (!group || group.parentGroupId !== state.connection.groupId) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n const identity = await getScimIdentityByMappedGroup(\n state.ctx,\n config.component.connection,\n groupId,\n );\n const scopedIdentity =\n identity && identity.connectionId === state.connection._id ? identity : undefined;\n const members = (\n await collectMembers(state.ctx, { groupId: group._id, status: \"active\" })\n ).map((member) => ({ value: member.userId }));\n const location = `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${group._id}`;\n await state.recordScimEvent(\n \"connection.scim.read\",\n \"success\",\n { type: \"group\", id: group._id },\n { resourceType: \"group\", resourceId: group._id, operation: \"get\" },\n );\n return scimJson(\n serializeScimGroup({\n id: group._id,\n group,\n externalId: scopedIdentity?.externalId,\n location,\n members,\n }),\n 200,\n { Location: location },\n );\n }\n const groupsList = {\n page: await collectGroups(state.ctx, { parentGroupId: state.connection.groupId }),\n };\n const identities = await listScimIdentitiesByConnection(\n state.ctx,\n config.component.connection,\n state.connection._id,\n );\n const identityByGroupId = new Map(\n identities\n .filter(\n (\n identity: ScimIdentityRecord,\n ): identity is ScimIdentityRecord & { mappedGroupId: string } =>\n typeof identity.mappedGroupId === \"string\",\n )\n .map((identity: ScimIdentityRecord & { mappedGroupId: string }) => [\n identity.mappedGroupId,\n identity,\n ]),\n );\n const groups: GroupListItem[] = await Promise.all(\n groupsList.page.map(async (group) => {\n const typedGroup = group as GroupRecord;\n const members = await collectMembers(state.ctx, {\n groupId: typedGroup._id,\n status: \"active\",\n });\n return {\n group: typedGroup,\n identity: identityByGroupId.get(typedGroup._id),\n memberIds: members.map((member) => member.userId),\n };\n }),\n );\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection<GroupListItem>(groups, listRequest.filter, {\n id: (item) => item.group._id,\n externalId: (item) => item.identity?.externalId,\n displayName: (item) => item.group.name,\n \"members.value\": (item) => item.memberIds,\n });\n const paged = paginateScimCollection(filtered, listRequest);\n await state.recordScimEvent(\n \"connection.scim.read\",\n \"success\",\n { type: \"connection\", id: state.connection._id },\n {\n resourceType: \"group\",\n operation: \"list\",\n },\n );\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ group, identity }) =>\n serializeScimGroup({\n id: group._id,\n group,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${group._id}`,\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleGroupsPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const externalId = typeof body.externalId === \"string\" ? body.externalId : undefined;\n const existingIdentity = externalId\n ? await getScimIdentity(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n resourceType: \"group\",\n externalId,\n })\n : null;\n const existingGroup = existingIdentity?.mappedGroupId\n ? await auth.group.get(state.ctx, { id: existingIdentity.mappedGroupId })\n : null;\n const created = existingGroup === null;\n const provisionedRoleIds = resolveProvisionedRoleIds({\n policy: state.policy,\n groups: typeof body.displayName === \"string\" ? [body.displayName] : undefined,\n roles: pickStringArray((body as Record<string, unknown>).roles),\n });\n const groupId = existingGroup?._id\n ? existingGroup._id\n : await auth.group.create(state.ctx, {\n data: {\n name: typeof body.displayName === \"string\" ? body.displayName : \"Group\",\n parentGroupId: state.connection.groupId,\n type: \"organization\",\n },\n });\n if (!created && existingGroup) {\n const location = `${state.url.origin}${state.url.pathname}/${groupId}`;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: existingGroup,\n externalId,\n location,\n members: (await collectMembers(state.ctx, { groupId, status: \"active\" })).map(\n (member) => ({ value: member.userId }),\n ),\n }),\n 200,\n { Location: location },\n );\n }\n await upsertScimIdentity(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n groupId: state.connection.groupId,\n resourceType: \"group\",\n externalId: externalId ?? groupId,\n mappedGroupId: groupId,\n active: true,\n raw: body,\n lastProvisionedAt: Date.now(),\n });\n const currentMembers = await collectMembersForReplace(state.ctx, {\n groupId,\n status: \"active\",\n });\n const currentByUserId = new Map(currentMembers.map((member) => [member.userId, member]));\n const nextUserIds = new Set(\n (Array.isArray(body.members) ? body.members : []).map((member) => String(member.value)),\n );\n const toAddUserIds = [...nextUserIds].filter((userId) => !currentByUserId.has(userId));\n const invalidMember = await firstInvalidScimMember(state, toAddUserIds);\n if (invalidMember !== null) {\n return scimError(400, \"invalidValue\", `Group member user not found: ${invalidMember}`);\n }\n for (const member of currentMembers) {\n if (!nextUserIds.has(member.userId)) {\n await auth.member.remove(state.ctx, { id: member._id });\n }\n }\n for (const userId of toAddUserIds) {\n await auth.member.create(state.ctx, {\n data: {\n groupId,\n userId,\n roleIds: provisionedRoleIds,\n status: \"active\",\n },\n });\n }\n await state.recordScimEvent(\n created ? \"connection.scim.group.provisioned\" : \"connection.scim.group.updated\",\n \"success\",\n { type: \"group\", id: groupId },\n );\n const group = await auth.group.get(state.ctx, { id: groupId });\n const location = `${state.url.origin}${state.url.pathname}/${groupId}`;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n externalId,\n location,\n members: (await collectMembers(state.ctx, { groupId, status: \"active\" })).map(\n (member) => ({ value: member.userId }),\n ),\n }),\n created ? 201 : 200,\n { Location: location },\n );\n };\n\n const handleGroupsPatch: ScimHandler = async (state) => {\n const missing = requireScimResourceId(state.parsedPath.resourceId, \"Group\");\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n const identity = await getScimIdentityByMappedGroup(\n state.ctx,\n config.component.connection,\n groupId,\n );\n if (!identity || identity.connectionId !== state.connection._id) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n const body = (await readScimJson(state.request)) as ScimBody;\n const operations = Array.isArray(body.Operations)\n ? body.Operations\n : unsupportedScimPatch();\n for (const operation of operations) {\n const op = typeof operation.op === \"string\" ? operation.op.toLowerCase() : \"replace\";\n if (\n operation.path === undefined &&\n op === \"replace\" &&\n typeof operation.value === \"object\" &&\n operation.value !== null\n ) {\n const value = operation.value as Record<string, unknown>;\n if (typeof value.displayName === \"string\") {\n await auth.group.update(state.ctx, {\n id: groupId,\n patch: { name: value.displayName },\n });\n }\n continue;\n }\n if (operation.path === \"displayName\") {\n if (op !== \"replace\" && op !== \"add\") unsupportedScimPatch();\n await auth.group.update(state.ctx, {\n id: groupId,\n patch: { name: operation.value },\n });\n continue;\n }\n if (operation.path === \"members\" && op === \"add\") {\n const addUserIds = (Array.isArray(operation.value) ? operation.value : []).map(\n (member) => String(member.value),\n );\n const invalidMember = await firstInvalidScimMember(state, addUserIds);\n if (invalidMember !== null) {\n return scimError(\n 400,\n \"invalidValue\",\n `Group member user not found: ${invalidMember}`,\n );\n }\n for (const userId of addUserIds) {\n const existing = await auth.member.get(state.ctx, { groupId, userId });\n if (!existing.membership) {\n await auth.member.create(state.ctx, {\n data: {\n groupId,\n userId,\n roleIds: resolveProvisionedRoleIds({\n policy: state.policy,\n groups: typeof body.displayName === \"string\" ? [body.displayName] : undefined,\n roles: pickStringArray((body as Record<string, unknown>).roles),\n }),\n status: \"active\",\n },\n });\n }\n }\n continue;\n }\n if (operation.path === \"members\" && op === \"replace\") {\n const currentMembers = await collectMembersForReplace(state.ctx, {\n groupId,\n status: \"active\",\n });\n const currentUserIds = new Set<string>(currentMembers.map((member) => member.userId));\n const nextUserIds = new Set<string>(\n (Array.isArray(operation.value) ? operation.value : []).map((member: unknown) =>\n String((member as { value?: unknown }).value),\n ),\n );\n const toAddUserIds = [...nextUserIds].filter((userId) => !currentUserIds.has(userId));\n const invalidMember = await firstInvalidScimMember(state, toAddUserIds);\n if (invalidMember !== null) {\n return scimError(\n 400,\n \"invalidValue\",\n `Group member user not found: ${invalidMember}`,\n );\n }\n for (const member of currentMembers) {\n if (!nextUserIds.has(member.userId)) {\n await auth.member.remove(state.ctx, { id: member._id });\n }\n }\n for (const userId of toAddUserIds) {\n await auth.member.create(state.ctx, {\n data: {\n groupId,\n userId,\n roleIds: resolveProvisionedRoleIds({\n policy: state.policy,\n groups: typeof body.displayName === \"string\" ? [body.displayName] : undefined,\n roles: pickStringArray((body as Record<string, unknown>).roles),\n }),\n status: \"active\",\n },\n });\n }\n continue;\n }\n if (\n typeof operation.path === \"string\" &&\n op === \"remove\" &&\n operation.path.startsWith(\"members[\")\n ) {\n const match = operation.path.match(/^members\\[value eq \"([^\"]+)\"\\]$/);\n const userId = match?.[1];\n if (userId) {\n const resolution = await auth.member.get(state.ctx, {\n groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.remove(state.ctx, { id: resolution.membership._id });\n }\n }\n continue;\n }\n unsupportedScimPatch();\n }\n await state.recordScimEvent(\"connection.scim.group.updated\", \"success\", {\n type: \"group\",\n id: groupId,\n });\n const group = await auth.group.get(state.ctx, { id: groupId });\n const location = `${state.url.origin}${state.url.pathname}`;\n const members = await collectMembers(state.ctx, { groupId, status: \"active\" });\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n location,\n members: members.map((member) => ({\n value: member.userId,\n })),\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleGroupsDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(state.parsedPath.resourceId, \"Group\");\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n const identity = await getScimIdentityByMappedGroup(\n state.ctx,\n config.component.connection,\n groupId,\n );\n if (!identity || identity.connectionId !== state.connection._id) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n await auth.group.remove(state.ctx, { id: groupId });\n await removeScimIdentity(state.ctx, config.component.connection, identity._id);\n await state.recordScimEvent(\"connection.scim.group.deactivated\", \"success\", {\n type: \"group\",\n id: groupId,\n });\n return new Response(null, { status: 204 });\n };\n\n const scimHandlers: Record<string, Partial<Record<string, ScimHandler>>> = {\n ServiceProviderConfig: {\n GET: async () =>\n scimJson({\n schemas: [\"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\"],\n patch: { supported: true },\n bulk: {\n supported: false,\n maxOperations: 0,\n maxPayloadSize: 0,\n },\n filter: { supported: true, maxResults: 100 },\n changePassword: { supported: false },\n sort: { supported: false },\n etag: { supported: false },\n authenticationSchemes: [\n {\n type: \"oauthbearertoken\",\n name: \"Bearer Token\",\n description: \"Use the SCIM token generated by Convex Auth connection.\",\n },\n ],\n }),\n },\n Schemas: {\n GET: async (state) =>\n handleStaticScimCollection(SCIM_SCHEMAS, state.parsedPath.resourceId, {\n by: \"id\",\n notFound: \"Schema not found.\",\n }),\n },\n ResourceTypes: {\n GET: async (state) =>\n handleStaticScimCollection(SCIM_RESOURCE_TYPES, state.parsedPath.resourceId, {\n by: \"name\",\n notFound: \"Resource type not found.\",\n }),\n },\n Users: {\n GET: handleUsersGet,\n POST: handleUsersPost,\n PATCH: handleUsersUpsert,\n PUT: handleUsersUpsert,\n DELETE: handleUsersDelete,\n },\n Groups: {\n GET: handleGroupsGet,\n POST: handleGroupsPost,\n PATCH: handleGroupsPatch,\n DELETE: handleGroupsDelete,\n },\n };\n\n const handler = scimHandlers[state.parsedPath.resource]?.[state.request.method];\n return handler\n ? await handler(state)\n : scimError(404, \"notFound\", \"SCIM resource not found.\");\n } catch (error) {\n if (error instanceof Error && error.message === \"Unsupported SCIM filter.\") {\n return scimError(400, \"invalidFilter\", error.message);\n }\n if (error instanceof Error && error.message === \"Invalid SCIM pagination.\") {\n return scimError(400, \"invalidValue\", error.message);\n }\n if (error instanceof Error && error.message === \"Invalid SCIM JSON.\") {\n return scimError(400, \"invalidSyntax\", error.message);\n }\n if (error instanceof Error && error.message === \"Unsupported SCIM content type.\") {\n return scimError(415, \"invalidSyntax\", error.message);\n }\n if (error instanceof Error && error.message === \"Unsupported SCIM PATCH operation.\") {\n return scimError(400, \"invalidSyntax\", error.message);\n }\n if (error instanceof Error && error.message === \"SCIM member set too large to reconcile.\") {\n return scimError(413, \"tooLarge\", error.message);\n }\n if (\n error instanceof ConvexError &&\n typeof error.data === \"object\" &&\n error.data !== null &&\n \"code\" in error.data &&\n \"message\" in error.data\n ) {\n const code = error.data.code as string;\n const status = code === \"MISSING_BEARER_TOKEN\" || code === \"INVALID_API_KEY\" ? 401 : 400;\n const response = scimError(\n status,\n status === 401 ? \"invalidValue\" : code,\n error.data.message,\n );\n if (status === 401) {\n response.headers.set(\"WWW-Authenticate\", \"Bearer\");\n }\n return response;\n }\n log(\"WARN\", \"[connection.scim] unhandled error surfaced as SCIM 500\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return scimError(500, \"internalError\", \"SCIM request failed.\");\n }\n };\n\n const handleOidcCallbackForConnection = async (\n ctx: GenericActionCtx<GenericDataModel>,\n request: Request,\n connectionId: string,\n ) => {\n const params = await getOidcCallbackParams(request);\n const { connection, oidc } = await loadConnectionOidcOrThrow(ctx, connectionId);\n const { providerId, provider, oauthConfig } = await createGroupConnectionOidcRuntime({\n ctx,\n componentConnection: config.component.connection,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n connectionId: connection._id,\n oidc,\n sharedRedirectURI: sharedOidcRedirectURI,\n });\n const cookies = getCookies(request);\n const maybeRedirectTo = useRedirectToParam(providerId, cookies);\n const destinationUrl = await redirectAbsoluteUrl(ctx, config, {\n redirectTo: maybeRedirectTo?.redirectTo,\n });\n let result: Awaited<ReturnType<typeof handleOAuthCallback>>;\n try {\n result = await handleOAuthCallback(\n providerId,\n { ...oauthConfig, provider },\n Object.fromEntries(params.entries()),\n cookies,\n );\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"oidc\",\n outcome: \"failure\",\n error,\n });\n throw error;\n }\n const extraFields =\n typeof oidc.profile === \"object\" && oidc.profile !== null\n ? ((oidc.profile as Record<string, unknown>).extraFields as\n | Record<string, string>\n | undefined)\n : undefined;\n let profile = result.profile as Record<string, unknown>;\n if (extraFields && typeof profile === \"object\" && profile) {\n const extend: Record<string, unknown> = {};\n for (const [claimName, fieldName] of Object.entries(extraFields)) {\n if (claimName in profile) {\n extend[fieldName] = profile[claimName];\n }\n }\n if (Object.keys(extend).length > 0) {\n profile = { ...profile, extend };\n }\n }\n\n let verificationCode: string;\n try {\n verificationCode = await callUserOAuth(ctx, {\n provider: providerId,\n providerAccountId: result.providerAccountId,\n profile: profile as AuthProfile,\n signature: result.signature,\n accountExtend: {\n identity: {\n protocol: \"oidc\",\n connectionId: connection._id,\n subject: result.providerAccountId,\n issuer:\n typeof (oidc.discovery as Record<string, unknown> | undefined)?.issuer === \"string\"\n ? ((oidc.discovery as Record<string, unknown>).issuer as string)\n : undefined,\n discoveryUrl:\n typeof (oidc.discovery as Record<string, unknown> | undefined)?.discoveryUrl ===\n \"string\"\n ? ((oidc.discovery as Record<string, unknown>).discoveryUrl as string)\n : undefined,\n },\n },\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"oidc\",\n outcome: \"failure\",\n error,\n });\n throw error;\n }\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"oidc\",\n outcome: \"success\",\n });\n const headers = new Headers({\n Location: setURLSearchParam(destinationUrl, \"code\", verificationCode),\n });\n for (const { name, value, options } of result.cookies) {\n headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n if (maybeRedirectTo) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(\n maybeRedirectTo.updatedCookie.name,\n maybeRedirectTo.updatedCookie.value,\n maybeRedirectTo.updatedCookie.options,\n ),\n );\n }\n return new Response(null, { status: 302, headers });\n };\n\n addConnectionRoutes(http, {\n routeBase: GROUP_CONNECTION_ROUTE_BASE,\n convertErrorsToResponse,\n handleSamlMetadata: async (ctx, _request, runtimeRoute) => {\n const { loaded } = await loadActiveConnectionSamlOrThrow(ctx, runtimeRoute.connectionId);\n return new Response(\n createGroupConnectionSamlMetadataXml({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: loaded.source,\n config: loaded.config,\n }),\n {\n status: 200,\n headers: { \"Content-Type\": \"application/xml\" },\n },\n );\n },\n handleSamlSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw convexError(ErrorCode.OAUTH_MISSING_VERIFIER, \"Missing sign-in verifier.\");\n }\n const { loaded, connection } = await loadActiveConnectionSamlOrThrow(\n ctx,\n runtimeRoute.connectionId,\n );\n const state = generateRandomString(24, INVITE_TOKEN_ALPHABET);\n const signInRequest = await createGroupConnectionSamlSignInRequest({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"connection\", id: connection._id },\n config: loaded.config,\n state,\n signature: `saml ${connection._id} pending ${state}`,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n const signature = `saml ${connection._id} ${signInRequest.requestId} ${state}`;\n await callVerifierSignature(ctx, { verifier, signature });\n const nowMs = Date.now();\n await ctx.runMutation(config.component.connection.saml.request.create, {\n connectionId: connection._id,\n requestId: signInRequest.requestId,\n createdAt: nowMs,\n expiresAt: nowMs + SAML_LOGIN_REQUEST_TTL_MS,\n });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const redirectCookies =\n redirectTo !== null\n ? [redirectToParamCookie(groupSamlProviderId(connection._id), redirectTo)]\n : [];\n const relayState = encodeGroupSamlRelayState({\n source: { kind: \"connection\", id: connection._id },\n signature,\n requestId: signInRequest.requestId,\n state,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n if (signInRequest.binding === \"redirect\" && signInRequest.redirectUrl) {\n const redirectUrl = new URL(signInRequest.redirectUrl);\n redirectUrl.searchParams.set(\"RelayState\", relayState);\n const headers = new Headers({\n Location: redirectUrl.toString(),\n });\n for (const { name, value, options } of redirectCookies as CookieToSerialize[]) {\n headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers });\n }\n const response = createSamlPostBindingResponse({\n endpoint: signInRequest.post!.endpoint,\n parameter: \"SAMLRequest\",\n value: signInRequest.post!.value,\n relayState,\n });\n for (const { name, value, options } of redirectCookies as CookieToSerialize[]) {\n response.headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return response;\n },\n handleOidcSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw convexError(ErrorCode.OAUTH_MISSING_VERIFIER, \"Missing sign-in verifier.\");\n }\n const { connection, oidc } = await loadConnectionOidcOrThrow(ctx, runtimeRoute.connectionId);\n const { providerId, provider, oauthConfig } = await createGroupConnectionOidcRuntime({\n ctx,\n componentConnection: config.component.connection,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n connectionId: connection._id,\n oidc,\n sharedRedirectURI: sharedOidcRedirectURI,\n });\n const { redirect, cookies, signature } = await createOAuthAuthorizationURL(\n providerId,\n {\n ...oauthConfig,\n provider,\n },\n {\n loginHint:\n url.searchParams.get(\"loginHint\") ??\n (typeof (oidc.request as Record<string, unknown> | undefined)?.loginHint === \"string\"\n ? ((oidc.request as Record<string, unknown>).loginHint as string)\n : undefined),\n stateTransform:\n typeof sharedOidcRedirectURI === \"string\"\n ? (state) =>\n encodeGroupOidcState({\n connectionId: connection._id,\n state,\n })\n : undefined,\n },\n );\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const headers_ = new Headers({ Location: redirect });\n for (const { name, value, options } of [\n ...cookies,\n ...(redirectTo !== null ? [redirectToParamCookie(providerId, redirectTo)] : []),\n ] as CookieToSerialize[]) {\n headers_.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, {\n status: 302,\n headers: headers_,\n });\n },\n handleOidcCallback: async (ctx, request, runtimeRoute) => {\n return await handleOidcCallbackForConnection(ctx, request, runtimeRoute.connectionId);\n },\n handleSamlAcs,\n handleSamlSlo,\n handleScimRequest,\n sharedOidcCallbackPath: sharedOidcRedirectURI,\n handleOidcSharedCallback: async (ctx, request) => {\n const url = new URL(request.url);\n const params = await getOidcCallbackParams(request);\n const { connectionId } = decodeGroupOidcState(params.get(\"state\"));\n url.search = params.toString();\n const normalizedRequest = new Request(url, request);\n return await handleOidcCallbackForConnection(ctx, normalizedRequest, connectionId);\n },\n scimError,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"http.js","names":["serializeCookie","ctx","state"],"sources":["../../../src/server/connection/http.ts"],"sourcesContent":["import type { GenericActionCtx, GenericDataModel, HttpRouter } from \"convex/server\";\nimport { ConvexError, type GenericId } from \"convex/values\";\nimport { serialize as serializeCookie } from \"cookie\";\n\nimport { configDefaults } from \"../config\";\nimport {\n getScimIdentityByConnectionAndUser,\n getScimIdentityByMappedGroup,\n listScimIdentitiesByConnection,\n provisionScimUser,\n provisionScimGroup,\n revokeScimGroup,\n revokeScimUser,\n updateScimGroup,\n updateScimUser,\n type ScimIdentityRecord,\n} from \"../contract\";\nimport { redirectToParamCookie, useRedirectToParam } from \"../cookies\";\nimport { convexError } from \"../errors\";\nimport { ErrorCode } from \"../../shared/codes\";\nimport { addConnectionRoutes, convertErrorsToResponse, getCookies } from \"../http\";\nimport type { ConnectionRuntimeRoute } from \"../http\";\nimport { log } from \"../log\";\nimport { createOAuthAuthorizationURL, handleOAuthCallback } from \"../oauth/runtime\";\nimport type { AuthAccountExtend, AuthProfile } from \"../payloads\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"../redirects\";\nimport type { AuthEventKind, AuthEventObject, AuthEventSubject } from \"../events\";\nimport type { EmitGroupAuthEventInput } from \"./group/service\";\nimport type { GroupConnectionPolicy } from \"../types\";\nimport { createGroupConnectionOidcRuntime } from \"./oidc\";\nimport { resolveProvisionedRoleIds } from \"./policy\";\nimport { finalizeNormalizedProfile, normalizeStringArray } from \"./profile\";\nimport {\n createGroupConnectionSamlMetadataXml,\n createGroupConnectionSamlSignInRequest,\n createSamlPostBindingResponse,\n encodeGroupSamlRelayState,\n enforceGroupConnectionSamlSecurity,\n getSamlServiceProviderOptions,\n parseGroupConnectionSamlLoginResponse,\n parseGroupConnectionSamlLogoutMessage,\n profileFromSamlExtract,\n samlReplayIdentifiers,\n validateGroupConnectionSamlLoginRelayState,\n} from \"./saml\";\nimport {\n parseScimListRequest,\n scimError,\n scimJson,\n serializeScimGroup,\n serializeScimUser,\n} from \"./scim\";\nimport {\n decodeGroupOidcState,\n encodeGroupOidcState,\n groupSamlProviderId,\n SCIM_GROUP_SCHEMA_ID,\n SCIM_USER_SCHEMA_ID,\n} from \"./shared\";\n\ntype ComponentConfig = ReturnType<typeof configDefaults>;\n\ntype AuthRuntime = {\n user: {\n get(ctx: GenericActionCtx<GenericDataModel>, args: { id: string }): Promise<UserRecord | null>;\n };\n group: {\n get(ctx: GenericActionCtx<GenericDataModel>, args: { id: string }): Promise<GroupRecord | null>;\n list(\n ctx: GenericActionCtx<GenericDataModel>,\n opts: {\n where?: Record<string, unknown>;\n paginationOpts: { numItems: number; cursor: string | null };\n },\n ): Promise<{ page: Array<Record<string, unknown>>; isDone: boolean; continueCursor: string }>;\n };\n member: {\n list(\n ctx: GenericActionCtx<GenericDataModel>,\n opts: {\n where?: Record<string, unknown>;\n paginationOpts: { numItems: number; cursor: string | null };\n },\n ): Promise<{\n page: Array<{ _id: string; userId: string; status?: string }>;\n isDone: boolean;\n continueCursor: string;\n }>;\n };\n};\n\ntype ActiveSamlConnection = {\n loaded: {\n source: { kind: \"connection\"; id: string };\n config: unknown;\n [key: string]: unknown;\n };\n connection: { _id: string; groupId: string };\n saml: Record<string, unknown>;\n};\n\ntype OidcConnection = {\n connection: { _id: string; groupId: string };\n oidc: Record<string, unknown>;\n};\n\ntype ScimContext = {\n parsedPath: {\n connectionId: string;\n resource: string;\n resourceId?: string;\n };\n connection: { _id: string; groupId: string; protocol: \"oidc\" | \"saml\" };\n scimConfig: {\n _id: string;\n connectionId: string;\n status: string;\n extend?: unknown;\n };\n};\n\ntype GroupPolicy = GroupConnectionPolicy;\n\ntype CookieToSerialize = {\n name: string;\n value: string;\n options: Parameters<typeof serializeCookie>[2];\n};\n\nfunction formDataEntries(formData: unknown): Iterable<[string, string | { name: string }]> {\n return formData as Iterable<[string, string | { name: string }]>;\n}\n\nasync function getOidcCallbackParams(request: Request) {\n const url = new URL(request.url);\n const params = new URLSearchParams(url.searchParams);\n if (request.headers.get(\"Content-Type\")?.includes(\"application/x-www-form-urlencoded\")) {\n const formData = await request.formData();\n for (const [key, value] of formDataEntries(formData)) {\n if (typeof value === \"string\") {\n params.append(key, value);\n }\n }\n }\n return params;\n}\n\ntype MemberRecord = { _id: string; userId: string; status?: string };\ntype UserRecord = { _id: string; email?: string } & Record<string, unknown>;\ntype GroupRecord = { _id: string; name?: string } & Record<string, unknown>;\n\ntype UserListItem = {\n user: UserRecord;\n member: MemberRecord;\n identity?: ScimIdentityRecord;\n};\n\ntype GroupListItem = {\n group: GroupRecord;\n identity?: ScimIdentityRecord;\n memberIds?: string[];\n};\n\ntype GroupHttpRuntimeDeps = {\n http: HttpRouter;\n hasConnection: boolean;\n auth: AuthRuntime;\n config: ComponentConfig;\n routeBase: string;\n requireEnv: (name: string) => string;\n loadActiveConnectionSamlOrThrow: (\n ctx: GenericActionCtx<GenericDataModel>,\n connectionId: string,\n ) => Promise<ActiveSamlConnection>;\n loadConnectionOidcOrThrow: (\n ctx: GenericActionCtx<GenericDataModel>,\n connectionId: string,\n ) => Promise<OidcConnection>;\n getGroupConnectionScimContext: (\n ctx: GenericActionCtx<GenericDataModel>,\n request: Request,\n ) => Promise<ScimContext>;\n loadGroupPolicyOrThrow: (\n ctx: GenericActionCtx<GenericDataModel>,\n groupId: string,\n ) => Promise<GroupPolicy>;\n normalizeGroupConnectionPolicy: (policy: unknown) => GroupPolicy;\n emitGroupAuthEvent: (\n ctx: GenericActionCtx<GenericDataModel>,\n args: EmitGroupAuthEventInput,\n ) => Promise<string>;\n generateRandomString: (length: number, alphabet: string) => string;\n inviteTokenAlphabet: string;\n callUserOAuth: (\n ctx: GenericActionCtx<GenericDataModel>,\n args: {\n provider: string;\n providerAccountId: string;\n signature: string;\n profile: AuthProfile;\n accountExtend?: AuthAccountExtend;\n },\n ) => Promise<string>;\n callVerifierSignature: (\n ctx: GenericActionCtx<GenericDataModel>,\n args: { verifier: string; signature: string },\n ) => Promise<void>;\n sharedOidcRedirectURI?: string;\n};\n\ntype ScimFilterOperator = NonNullable<\n ReturnType<typeof parseScimListRequest>[\"filter\"]\n>[\"operator\"];\n\n/**\n * Upper bound on rows a single SCIM list response will materialize. SCIM list\n * filtering and `totalResults` require the full member/group set, so the\n * handlers cursor-follow to this cap; past it the response is truncated and a\n * warning is logged rather than silently returning a partial first page.\n */\nconst SCIM_COLLECT_LIMIT = 5000;\n\n/**\n * Lifetime of a persisted pending SAML AuthnRequest. Bounds how long an ACS\n * response can accept the request; comfortably covers IdP round-trips and the\n * default 300s clock skew while keeping the pending-request table small.\n */\nconst SAML_LOGIN_REQUEST_TTL_MS = 10 * 60 * 1000;\n\n/**\n * Fallback TTL for the seen-assertion replay cache when an assertion carries no\n * `NotOnOrAfter` bound (only reachable when `requireTimestamps` is disabled).\n */\nconst SAML_SEEN_ASSERTION_FALLBACK_TTL_MS = 10 * 60 * 1000;\n\nconst SCIM_FILTER_OPERATORS = {\n pr: (values) => values.length > 0,\n eq: (values, filterValue) => values.includes(filterValue),\n co: (values, filterValue) => values.some((value) => value.includes(filterValue)),\n sw: (values, filterValue) => values.some((value) => value.startsWith(filterValue)),\n ew: (values, filterValue) => values.some((value) => value.endsWith(filterValue)),\n} satisfies Record<ScimFilterOperator, (values: string[], filterValue: string) => boolean>;\n\n/** @internal Post-commit SCIM notifications must never make a committed write retryable. */\nexport async function notifyScimAfterProvision(notify: (() => Promise<unknown>) | undefined) {\n try {\n await notify?.();\n } catch (error) {\n console.error(\"[auth] SCIM afterProvision hook failed after commit\", error);\n }\n}\n\nexport function addGroupHttpRuntime(deps: GroupHttpRuntimeDeps) {\n if (!deps.hasConnection) {\n return;\n }\n\n const {\n http,\n auth,\n config,\n requireEnv,\n loadActiveConnectionSamlOrThrow,\n loadConnectionOidcOrThrow,\n getGroupConnectionScimContext,\n loadGroupPolicyOrThrow,\n emitGroupAuthEvent,\n generateRandomString,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n callUserOAuth,\n callVerifierSignature,\n sharedOidcRedirectURI,\n } = deps;\n const GROUP_CONNECTION_ROUTE_BASE = deps.routeBase;\n\n type ScimState = {\n ctx: GenericActionCtx<GenericDataModel>;\n request: Request;\n url: URL;\n parsedPath: ScimContext[\"parsedPath\"];\n connection: ScimContext[\"connection\"];\n scimConfig: ScimContext[\"scimConfig\"];\n policy: GroupPolicy;\n recordScimEvent: (\n kind: AuthEventKind,\n outcome: \"success\" | \"failure\",\n subject: AuthEventSubject,\n data?: Record<string, unknown>,\n ) => Promise<void>;\n };\n\n type ScimHandler = (state: ScimState) => Promise<Response>;\n\n const errorCodeForEvent = (error: unknown, fallback: string) => {\n if (\n error instanceof ConvexError &&\n typeof error.data === \"object\" &&\n error.data !== null &&\n \"code\" in error.data &&\n typeof (error.data as { code?: unknown }).code === \"string\"\n ) {\n return (error.data as { code: string }).code;\n }\n return fallback;\n };\n\n const recordConnectionLoginEvent = async (\n ctx: GenericActionCtx<GenericDataModel>,\n args: {\n connection: { _id: string; groupId: string };\n protocol: \"oidc\" | \"saml\";\n outcome: \"success\" | \"failure\";\n userId?: string;\n error?: unknown;\n },\n ) => {\n await emitGroupAuthEvent(ctx, {\n connectionId: args.connection._id,\n groupId: args.connection.groupId,\n kind: args.outcome === \"success\" ? \"connection.login.succeeded\" : \"connection.login.failed\",\n actor: { type: \"anonymous\" },\n subject: args.userId\n ? { type: \"user\", id: args.userId }\n : { type: \"connection\", id: args.connection._id },\n outcome: args.outcome,\n data:\n args.outcome === \"success\"\n ? {\n connectionId: args.connection._id,\n protocol: args.protocol,\n userId: args.userId,\n }\n : {\n connectionId: args.connection._id,\n protocol: args.protocol,\n errorCode: errorCodeForEvent(args.error, \"OAUTH_PROVIDER_ERROR\"),\n },\n });\n };\n\n /**\n * Enforce server-side SAML replay prevention at the ACS.\n *\n * The signature, audience/recipient/timestamp, and `InResponseTo` checks that\n * ran earlier all travel inside the same replayable POST, so none of them can\n * tell a captured `SAMLResponse` from a resubmitted one. This consumes the\n * single-use pending request (defeating SP-initiated replay) and records the\n * assertion ID in a bounded seen-cache (defeating IdP-initiated replay, which\n * carries no `InResponseTo`). Either check failing means the response was\n * already used: a connection-login failure is emitted and the login is\n * rejected with no session. Throws (never returns) on rejection.\n */\n const enforceSamlAcsReplayDefense = async (\n ctx: GenericActionCtx<GenericDataModel>,\n connection: { _id: string; groupId: string },\n parsed: {\n samlContent: string;\n extract?: Parameters<typeof samlReplayIdentifiers>[0][\"extract\"];\n },\n ): Promise<void> => {\n const nowMs = Date.now();\n const { assertionId, inResponseTo, notOnOrAfter } = samlReplayIdentifiers(parsed);\n const rejectReplay = async (message: string): Promise<never> => {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error: new Error(message),\n });\n throw convexError(ErrorCode.OAUTH_INVALID_STATE, message);\n };\n\n if (typeof inResponseTo === \"string\" && inResponseTo.length > 0) {\n const accepted = (await ctx.runMutation(config.component.connection.saml.request.accept, {\n requestId: inResponseTo,\n now: nowMs,\n connectionId: connection._id,\n })) as boolean;\n if (!accepted) {\n await rejectReplay(\"SAML response replays or references an unknown login request.\");\n }\n }\n\n if (typeof assertionId !== \"string\" || assertionId.length === 0) {\n await rejectReplay(\"SAML assertion is missing an ID required for replay detection.\");\n }\n const expiresAtMs =\n typeof notOnOrAfter === \"string\" && Number.isFinite(new Date(notOnOrAfter).getTime())\n ? new Date(notOnOrAfter).getTime()\n : nowMs + SAML_SEEN_ASSERTION_FALLBACK_TTL_MS;\n const firstSeen = (await ctx.runMutation(config.component.connection.saml.assertion.accept, {\n connectionId: connection._id,\n assertionId: assertionId as string,\n expiresAt: expiresAtMs,\n })) as boolean;\n if (!firstSeen) {\n await rejectReplay(\"SAML assertion has already been used.\");\n }\n };\n\n const SCIM_SCHEMAS = [\n {\n id: SCIM_USER_SCHEMA_ID,\n name: \"User\",\n description: \"User Account\",\n attributes: [\n { name: \"userName\", type: \"string\", required: true },\n { name: \"displayName\", type: \"string\" },\n { name: \"active\", type: \"boolean\" },\n { name: \"emails\", type: \"complex\", multiValued: true },\n ],\n },\n {\n id: SCIM_GROUP_SCHEMA_ID,\n name: \"Group\",\n description: \"Group\",\n attributes: [\n { name: \"displayName\", type: \"string\", required: true },\n { name: \"members\", type: \"complex\", multiValued: true },\n ],\n },\n ] as const;\n\n const SCIM_RESOURCE_TYPES = [\n {\n id: \"User\",\n name: \"User\",\n endpoint: \"/Users\",\n schema: SCIM_USER_SCHEMA_ID,\n },\n {\n id: \"Group\",\n name: \"Group\",\n endpoint: \"/Groups\",\n schema: SCIM_GROUP_SCHEMA_ID,\n },\n ] as const;\n\n const handleStaticScimCollection = <T extends { id?: string; name?: string }>(\n items: readonly T[],\n resourceId: string | undefined,\n opts: { by: \"id\" | \"name\"; notFound: string },\n ) => {\n if (resourceId !== undefined) {\n const item = items.find((entry) => entry[opts.by] === decodeURIComponent(resourceId));\n return item ? scimJson(item) : scimError(404, \"notFound\", opts.notFound);\n }\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: items,\n totalResults: items.length,\n startIndex: 1,\n itemsPerPage: items.length,\n });\n };\n\n const pickPrimaryEmail = (body: ScimBody) =>\n Array.isArray(body.emails)\n ? (body.emails.find((entry) => entry.primary === true)?.value ?? body.emails[0]?.value)\n : undefined;\n\n const pickDisplayName = (body: ScimBody) => {\n const name = typeof body.name === \"object\" && body.name !== null ? body.name : undefined;\n const derivedName = [name?.givenName, name?.familyName].filter(Boolean).join(\" \");\n if (body.displayName !== undefined) {\n return body.displayName;\n }\n if (name?.formatted !== undefined) {\n return name.formatted;\n }\n return derivedName !== \"\" ? derivedName : undefined;\n };\n\n const pickPhone = (body: ScimBody) =>\n Array.isArray(body.phoneNumbers) ? body.phoneNumbers[0]?.value : undefined;\n\n const getScimProfileConfig = (scimConfig: { extend?: unknown } | null | undefined) => {\n const extend =\n typeof scimConfig?.extend === \"object\" && scimConfig.extend !== null\n ? (scimConfig.extend as Record<string, unknown>)\n : {};\n const profile =\n typeof extend.profile === \"object\" && extend.profile !== null\n ? (extend.profile as Record<string, unknown>)\n : {};\n return {\n mapping:\n typeof profile.mapping === \"object\" && profile.mapping !== null\n ? (profile.mapping as Record<string, string>)\n : {},\n extraFields:\n typeof profile.extraFields === \"object\" && profile.extraFields !== null\n ? (profile.extraFields as Record<string, string>)\n : {},\n };\n };\n\n const scimFieldAccessors: Record<string, (body: ScimBody) => unknown> = {\n userName: (body) => body.userName,\n externalId: (body) => body.externalId,\n displayName: (body) => body.displayName,\n \"name.formatted\": (body) => body.name?.formatted,\n \"name.givenName\": (body) => body.name?.givenName,\n \"name.familyName\": (body) => body.name?.familyName,\n \"emails.primary\": (body) => pickPrimaryEmail(body),\n \"emails.value\": (body) =>\n Array.isArray(body.emails)\n ? body.emails\n .map((entry) => entry.value)\n .filter((value): value is string => typeof value === \"string\")\n : undefined,\n \"phoneNumbers.primary\": (body) => pickPhone(body),\n \"phoneNumbers.value\": (body) => pickPhone(body),\n active: (body) => body.active,\n groups: (body) => (body as Record<string, unknown>).groups,\n roles: (body) => (body as Record<string, unknown>).roles,\n };\n\n const resolveScimField = (body: ScimBody, key: string | undefined) => {\n if (!key) {\n return undefined;\n }\n const accessor = scimFieldAccessors[key];\n return accessor ? accessor(body) : (body as Record<string, unknown>)[key];\n };\n\n const extractScimProfile = (\n scimConfig: { extend?: unknown } | null | undefined,\n body: ScimBody,\n ) => {\n const { mapping, extraFields } = getScimProfileConfig(scimConfig);\n const extend = Object.fromEntries(\n Object.entries(extraFields)\n .map(([fieldName, source]) => [fieldName, resolveScimField(body, source)])\n .filter(([, value]) => value !== undefined),\n );\n\n return finalizeNormalizedProfile({\n externalId:\n (resolveScimField(body, mapping.externalId) as string | undefined) ??\n (typeof body.externalId === \"string\" ? body.externalId : undefined),\n name: (resolveScimField(body, mapping.name) as string | undefined) ?? pickDisplayName(body),\n firstName: resolveScimField(body, mapping.firstName) as string | undefined,\n lastName: resolveScimField(body, mapping.lastName) as string | undefined,\n email:\n (resolveScimField(body, mapping.email) as string | undefined) ??\n pickPrimaryEmail(body) ??\n body.userName,\n phone: (resolveScimField(body, mapping.phone) as string | undefined) ?? pickPhone(body),\n active: (resolveScimField(body, mapping.active) as boolean | undefined) ?? body.active,\n groups: pickStringArray(resolveScimField(body, mapping.groups)),\n roles: pickStringArray(resolveScimField(body, mapping.roles)),\n extend: Object.keys(extend).length > 0 ? extend : undefined,\n });\n };\n\n const pickStringArray = (value: unknown) => {\n return normalizeStringArray(\n Array.isArray(value)\n ? value.map((entry) => {\n if (typeof entry === \"string\") {\n return entry;\n }\n if (\n typeof entry === \"object\" &&\n entry !== null &&\n typeof (entry as { value?: unknown }).value === \"string\"\n ) {\n return (entry as { value: string }).value;\n }\n return undefined;\n })\n : value,\n );\n };\n\n const normalizeScimValues = (value: unknown): string[] => {\n if (Array.isArray(value)) {\n return value.flatMap((entry) => normalizeScimValues(entry));\n }\n if (typeof value === \"string\") {\n return [value];\n }\n if (typeof value === \"boolean\") {\n return [String(value)];\n }\n return [];\n };\n\n const filterScimCollection = <T>(\n items: T[],\n filter: ReturnType<typeof parseScimListRequest>[\"filter\"],\n filters: Record<string, (item: T) => unknown>,\n ) => {\n if (!filter) {\n return items;\n }\n const accessor = filters[filter.attribute];\n if (!accessor) {\n throw new Error(\"Unsupported SCIM filter.\");\n }\n const matchesOperator = SCIM_FILTER_OPERATORS[filter.operator];\n return items.filter((item) =>\n matchesOperator(normalizeScimValues(accessor(item)), filter.value ?? \"\"),\n );\n };\n\n const paginateScimCollection = <T>(\n items: T[],\n listRequest: ReturnType<typeof parseScimListRequest>,\n ) => {\n const start = listRequest.startIndex - 1;\n return items.slice(start, start + listRequest.count);\n };\n\n const requireScimResourceId = (resourceId: string | undefined, label: string) => {\n if (!resourceId) {\n return scimError(400, \"invalidPath\", `${label} resource ID is required.`);\n }\n return null;\n };\n\n const readScimJson = async (request: Request) => {\n const contentType = request.headers.get(\"Content-Type\") ?? \"\";\n if (\n contentType &&\n !contentType.includes(\"application/scim+json\") &&\n !contentType.includes(\"application/json\")\n ) {\n throw new Error(\"Unsupported SCIM content type.\");\n }\n try {\n const body: unknown = await request.json();\n if (typeof body !== \"object\" || body === null || Array.isArray(body)) {\n throw new Error(\"Invalid SCIM JSON.\");\n }\n return body as Record<string, unknown>;\n } catch {\n throw new Error(\"Invalid SCIM JSON.\");\n }\n };\n\n const unsupportedScimPatch = (): never => {\n throw new Error(\"Unsupported SCIM PATCH operation.\");\n };\n\n const scimCollectOverflow = () => new Error(\"SCIM member set too large to reconcile.\");\n\n type ScimBody = Record<string, unknown> & {\n displayName?: string;\n userName?: string;\n active?: boolean;\n externalId?: string;\n emails?: Array<{ value?: string; primary?: boolean }>;\n phoneNumbers?: Array<{ value?: string }>;\n name?: { formatted?: string; givenName?: string; familyName?: string };\n Operations?: Array<{ op?: string; path?: string; value?: unknown }>;\n members?: Array<{ value?: string }>;\n };\n\n const handleSamlAcs = async (\n ctx: GenericActionCtx<GenericDataModel>,\n request: Request,\n runtimeRoute: ConnectionRuntimeRoute,\n ) => {\n if (\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"acs\"\n ) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Invalid connection runtime path.\");\n }\n\n const connectionId = runtimeRoute.connectionId;\n const loadedConnection = await loadActiveConnectionSamlOrThrow(ctx, connectionId);\n const { loaded, connection, saml } = loadedConnection;\n const rootUrl = requireEnv(\"CONVEX_SITE_URL\");\n const serviceProvider = getSamlServiceProviderOptions({\n rootUrl,\n source: { kind: \"connection\", id: connection._id },\n config: loaded.config,\n });\n\n let parsedResponse;\n try {\n parsedResponse = await parseGroupConnectionSamlLoginResponse({\n request,\n rootUrl,\n source: { kind: \"connection\", id: connection._id },\n config: loaded.config,\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error,\n });\n throw convexError(\n \"OAUTH_PROVIDER_ERROR\",\n `SAML response parse failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n try {\n enforceGroupConnectionSamlSecurity({\n extract: parsedResponse.parsed.extract,\n config: loaded.config,\n expectedAudience: serviceProvider.entityId,\n expectedAcsUrl: serviceProvider.acsUrl,\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error,\n });\n throw convexError(\n \"OAUTH_PROVIDER_ERROR\",\n error instanceof Error ? error.message : \"SAML assertion failed security validation.\",\n );\n }\n\n try {\n validateGroupConnectionSamlLoginRelayState({\n relayState: parsedResponse.relayState,\n source: { kind: \"connection\", id: connection._id },\n inResponseTo: parsedResponse.parsed.extract?.subjectConfirmation?.inResponseTo,\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error,\n });\n throw convexError(\n \"OAUTH_INVALID_STATE\",\n \"SAML RelayState did not match the pending login request.\",\n );\n }\n\n await enforceSamlAcsReplayDefense(ctx, connection, parsedResponse.parsed);\n\n const { samlAttributes, samlSessionIndex, ...userProfile } = profileFromSamlExtract(\n parsedResponse.parsed.extract,\n ((saml.profile as Record<string, unknown> | undefined)?.mapping ?? {}) as\n | Record<string, string>\n | undefined,\n );\n const profile = userProfile as Record<string, unknown> & {\n id: string;\n };\n const extraFields =\n typeof saml.profile === \"object\" && saml.profile !== null\n ? ((saml.profile as Record<string, unknown>).extraFields as\n | Record<string, string>\n | undefined)\n : undefined;\n if (extraFields) {\n const extend: Record<string, unknown> = {};\n for (const [fieldName, attributeName] of Object.entries(extraFields)) {\n const value = samlAttributes[attributeName];\n if (value !== undefined) {\n extend[fieldName] = value;\n }\n }\n if (Object.keys(extend).length > 0) {\n profile.extend = extend;\n }\n }\n\n const maybeRedirectTo = useRedirectToParam(\n groupSamlProviderId(connection._id),\n getCookies(request),\n );\n\n let verificationCode: string;\n try {\n verificationCode = await callUserOAuth(ctx, {\n provider: groupSamlProviderId(connection._id),\n providerAccountId: profile.id,\n profile: profile as AuthProfile,\n signature: parsedResponse.relayState.signature,\n accountExtend: {\n identity: {\n protocol: \"saml\",\n connectionId: connection._id,\n subject: profile.id,\n entityId: typeof saml.entityId === \"string\" ? saml.entityId : undefined,\n },\n saml: {\n attributes: samlAttributes as Record<string, string | string[]>,\n sessionIndex: samlSessionIndex,\n },\n },\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"failure\",\n error,\n });\n throw error;\n }\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"saml\",\n outcome: \"success\",\n });\n\n const destinationUrl = await redirectAbsoluteUrl(ctx, config, {\n redirectTo:\n maybeRedirectTo?.redirectTo ??\n (typeof parsedResponse.relayState.redirectTo === \"string\"\n ? parsedResponse.relayState.redirectTo\n : undefined),\n });\n\n const vurl = setURLSearchParam(destinationUrl, \"code\", verificationCode);\n const vheaders = new Headers({ Location: vurl });\n vheaders.set(\"Cache-Control\", \"must-revalidate\");\n for (const { name, value, options } of maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []) {\n vheaders.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers: vheaders });\n };\n\n const handleSamlSlo = async (\n ctx: GenericActionCtx<GenericDataModel>,\n request: Request,\n runtimeRoute: ConnectionRuntimeRoute,\n ) => {\n if (\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"slo\"\n ) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Invalid connection runtime path.\");\n }\n const { loaded, connection } = await loadActiveConnectionSamlOrThrow(\n ctx,\n runtimeRoute.connectionId,\n );\n const parsedMessage = await parseGroupConnectionSamlLogoutMessage({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"connection\", id: connection._id },\n config: loaded.config,\n });\n if (parsedMessage.hasSamlRequest) {\n if (!parsedMessage.parsedRequest) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Missing SAML logout payload.\");\n }\n const responseContext = await parsedMessage.runtime.sp.createLogoutResponse(\n parsedMessage.runtime.idp,\n parsedMessage.parsedRequest.extract,\n parsedMessage.binding,\n parsedMessage.relayState ?? \"\",\n );\n if (parsedMessage.binding === \"redirect\") {\n return new Response(null, {\n status: 302,\n headers: { Location: responseContext.context },\n });\n }\n if (!(\"entityEndpoint\" in responseContext)) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Invalid SAML logout response binding.\");\n }\n return createSamlPostBindingResponse({\n endpoint: responseContext.entityEndpoint,\n parameter: \"SAMLResponse\",\n value: responseContext.context,\n relayState: parsedMessage.relayState,\n });\n } else if (parsedMessage.hasSamlResponse) {\n if (!parsedMessage.parsedResponse) {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Missing SAML logout response payload.\");\n }\n return new Response(null, { status: 204 });\n } else {\n throw convexError(ErrorCode.INVALID_PARAMETERS, \"Missing SAML logout payload.\");\n }\n };\n\n const handleScimRequest = async (ctx: GenericActionCtx<GenericDataModel>, request: Request) => {\n try {\n const { scimConfig, connection, parsedPath } = await getGroupConnectionScimContext(\n ctx,\n request,\n );\n const url = new URL(request.url);\n const state: ScimState = {\n ctx,\n request,\n url,\n parsedPath,\n connection,\n scimConfig,\n policy: await loadGroupPolicyOrThrow(ctx, connection.groupId),\n recordScimEvent: async (kind, outcome, subject, data) => {\n try {\n await emitGroupAuthEvent(ctx, {\n connectionId: connection._id,\n groupId: connection.groupId,\n kind,\n actor: { type: \"scim\" },\n subject,\n outcome,\n data,\n webhook: {\n payload: {\n connectionId: connection._id,\n ...(subject.id ? { subjectId: subject.id } : {}),\n ...(data ? { data: data as AuthEventObject } : {}),\n },\n },\n });\n } catch (error) {\n log(\"WARN\", \"[connection.scim] audit event emit failed (best-effort)\", { kind, error });\n }\n },\n };\n\n const collectMembers = async (\n ctx: GenericActionCtx<GenericDataModel>,\n where: { groupId: string; status?: \"active\" },\n ) => {\n const first = await auth.member.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor: null },\n });\n const out = [...first.page];\n let cursor = first.continueCursor;\n let done = first.isDone;\n while (!done && out.length < SCIM_COLLECT_LIMIT) {\n const next = await auth.member.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor },\n });\n out.push(...next.page);\n done = next.isDone;\n cursor = next.continueCursor;\n }\n if (!done) {\n log(\"WARN\", \"[connection.scim] member list truncated at collect limit\", {\n groupId: where.groupId,\n limit: SCIM_COLLECT_LIMIT,\n });\n }\n return out;\n };\n\n /**\n * Fully enumerate a group's active members for an authoritative\n * (destructive) membership replace. Unlike {@link collectMembers}, this\n * refuses to truncate: a `replace` diffs the incoming set against the\n * current set and removes the difference, so a partial read would\n * silently drop overflow members. Throws {@link scimCollectOverflow} past\n * the collect limit so the caller fails the reconcile (413) rather than\n * completing a partial authoritative replace.\n */\n const collectMembersForReplace = async (\n ctx: GenericActionCtx<GenericDataModel>,\n where: { groupId: string; status?: \"active\" },\n ) => {\n const first = await auth.member.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor: null },\n });\n const out = [...first.page];\n let cursor = first.continueCursor;\n let done = first.isDone;\n while (!done) {\n if (out.length > SCIM_COLLECT_LIMIT) {\n throw scimCollectOverflow();\n }\n const next = await auth.member.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor },\n });\n out.push(...next.page);\n done = next.isDone;\n cursor = next.continueCursor;\n }\n return out;\n };\n\n const collectGroups = async (\n ctx: GenericActionCtx<GenericDataModel>,\n where: { parentGroupId: string },\n ) => {\n const first = await auth.group.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor: null },\n });\n const out = [...first.page];\n let cursor = first.continueCursor;\n let done = first.isDone;\n while (!done && out.length < SCIM_COLLECT_LIMIT) {\n const next = await auth.group.list(ctx, {\n where,\n paginationOpts: { numItems: 200, cursor },\n });\n out.push(...next.page);\n done = next.isDone;\n cursor = next.continueCursor;\n }\n if (!done) {\n log(\"WARN\", \"[connection.scim] group list truncated at collect limit\", {\n parentGroupId: where.parentGroupId,\n limit: SCIM_COLLECT_LIMIT,\n });\n }\n return out;\n };\n\n const handleUsersGet: ScimHandler = async (state) => {\n if (state.parsedPath.resourceId) {\n const userId = state.parsedPath.resourceId;\n const user = await auth.user.get(state.ctx, { id: userId });\n const identity = await getScimIdentityByConnectionAndUser(\n state.ctx,\n config.component.connection,\n { connectionId: state.connection._id, userId },\n );\n const membership = (\n await auth.member.list(state.ctx, {\n where: { groupId: state.connection.groupId, userId },\n paginationOpts: { numItems: 1, cursor: null },\n })\n ).page[0];\n if (!user || !membership) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const typedUser = user as UserRecord;\n await state.recordScimEvent(\n \"connection.scim.read\",\n \"success\",\n { type: \"user\", id: typedUser._id },\n { resourceType: \"user\", resourceId: typedUser._id, operation: \"get\" },\n );\n const location = `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${typedUser._id}`;\n return scimJson(\n serializeScimUser({\n id: typedUser._id,\n user: typedUser,\n externalId: identity?.externalId,\n location,\n active: identity?.active ?? membership?.status === \"active\",\n }),\n 200,\n { Location: location },\n );\n }\n const members = {\n page: await collectMembers(state.ctx, { groupId: state.connection.groupId }),\n };\n const identities = await listScimIdentitiesByConnection(\n state.ctx,\n config.component.connection,\n state.connection._id,\n );\n const identityByUserId = new Map(\n identities\n .filter(\n (identity: ScimIdentityRecord): identity is ScimIdentityRecord & { userId: string } =>\n typeof identity.userId === \"string\",\n )\n .map((identity: ScimIdentityRecord & { userId: string }) => [\n identity.userId,\n identity,\n ]),\n );\n const users = (\n await Promise.all(\n members.page.map(async (member) => {\n const user = await auth.user.get(state.ctx, { id: member.userId });\n const typedUser = user as UserRecord | null;\n return user\n ? {\n user: typedUser,\n member,\n identity: identityByUserId.get(typedUser!._id),\n }\n : null;\n }),\n )\n ).filter(Boolean) as UserListItem[];\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection<UserListItem>(users, listRequest.filter, {\n id: (item) => item.user._id,\n externalId: (item) => item.identity?.externalId,\n userName: (item) => item.user.email ?? item.user.phone ?? item.user.name ?? item.user._id,\n displayName: (item) => item.user.name,\n name: (item) => item.user.name,\n \"name.formatted\": (item) => item.user.name,\n \"name.givenName\": (item) => item.user.firstName,\n \"name.familyName\": (item) => item.user.lastName,\n \"emails.value\": (item) => item.user.email,\n \"phoneNumbers.value\": (item) => item.user.phone,\n active: (item) => item.identity?.active ?? item.member.status === \"active\",\n });\n const paged = paginateScimCollection(filtered, listRequest);\n await state.recordScimEvent(\n \"connection.scim.read\",\n \"success\",\n {\n type: \"connection\",\n id: state.connection._id,\n },\n {\n resourceType: \"user\",\n operation: \"list\",\n },\n );\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ user, identity, member }) =>\n serializeScimUser({\n id: user._id,\n user,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${user._id}`,\n active: identity?.active ?? member.status === \"active\",\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleUsersPost: ScimHandler = async (state) => {\n const body = (await readScimJson(state.request)) as ScimBody;\n const extractedBase = extractScimProfile(state.scimConfig, body);\n const extracted =\n ((await config.connection?.hooks?.profileResolved?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: extractedBase as Record<string, unknown>,\n })) as typeof extractedBase | undefined) ?? extractedBase;\n const provisionProfile =\n ((await config.connection?.hooks?.beforeProvision?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: extracted as Record<string, unknown>,\n })) as typeof extracted | undefined) ?? extracted;\n const externalId = provisionProfile.externalId;\n const provisionedRoleIds = resolveProvisionedRoleIds({\n policy: state.policy,\n groups: provisionProfile.groups,\n roles: provisionProfile.roles,\n });\n const userData = {\n name: provisionProfile.name,\n ...(typeof provisionProfile.firstName === \"string\"\n ? { firstName: provisionProfile.firstName }\n : {}),\n ...(typeof provisionProfile.lastName === \"string\"\n ? { lastName: provisionProfile.lastName }\n : {}),\n email: provisionProfile.email,\n ...(typeof provisionProfile.email === \"string\"\n ? { emailVerificationTime: Date.now() }\n : {}),\n phone: provisionProfile.phone,\n ...(typeof provisionProfile.phone === \"string\"\n ? { phoneVerificationTime: Date.now() }\n : {}),\n ...(provisionProfile.extend ? { extend: provisionProfile.extend } : {}),\n };\n const provisioned = await provisionScimUser(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n externalId,\n userData,\n profileUpdate: state.policy.provisioning.user.updateProfileFromScim,\n roleIds: provisionedRoleIds,\n active: provisionProfile.active !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n });\n const { userId, created } = provisioned;\n await state.recordScimEvent(\n created ? \"connection.scim.user.provisioned\" : \"connection.scim.user.updated\",\n \"success\",\n { type: \"user\", id: userId },\n );\n const createdUser = await auth.user.get(state.ctx, { id: userId });\n await notifyScimAfterProvision(async () =>\n config.connection?.hooks?.afterProvision?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: provisionProfile as Record<string, unknown>,\n userId: userId as GenericId<\"User\">,\n }),\n );\n const location = `${state.url.origin}${state.url.pathname}/${userId}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: createdUser ?? {},\n externalId,\n location,\n active: provisionProfile.active !== false,\n }),\n created ? 201 : 200,\n { Location: location },\n );\n };\n\n const handleUsersUpsert: ScimHandler = async (state) => {\n const missing = requireScimResourceId(state.parsedPath.resourceId, \"User\");\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const existingUser = await auth.user.get(state.ctx, { id: userId });\n if (!existingUser) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const existingIdentity = await getScimIdentityByConnectionAndUser(\n state.ctx,\n config.component.connection,\n {\n connectionId: state.connection._id,\n userId: userId as GenericId<\"User\">,\n },\n );\n if (!existingIdentity) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const body = (await readScimJson(state.request)) as ScimBody;\n const extractedBase = extractScimProfile(state.scimConfig, body);\n const extracted =\n ((await config.connection?.hooks?.profileResolved?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: extractedBase as Record<string, unknown>,\n })) as typeof extractedBase | undefined) ?? extractedBase;\n const provisionProfile =\n ((await config.connection?.hooks?.beforeProvision?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: extracted as Record<string, unknown>,\n })) as typeof extracted | undefined) ?? extracted;\n const externalId = provisionProfile.externalId;\n const patchData: Record<string, unknown> = {};\n let nextActive: boolean | undefined;\n if (state.request.method === \"PUT\") {\n patchData.name = provisionProfile.name;\n patchData.firstName = provisionProfile.firstName;\n patchData.lastName = provisionProfile.lastName;\n patchData.email = provisionProfile.email;\n patchData.phone = provisionProfile.phone;\n if (provisionProfile.extend) {\n patchData.extend = provisionProfile.extend;\n }\n if (typeof patchData.email === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n if (typeof patchData.phone === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n } else {\n const operations = Array.isArray(body.Operations)\n ? body.Operations\n : unsupportedScimPatch();\n for (const operation of operations) {\n const op = typeof operation.op === \"string\" ? operation.op.toLowerCase() : \"replace\";\n if (op !== \"replace\" && op !== \"add\") {\n unsupportedScimPatch();\n }\n if (\n operation.path === undefined &&\n typeof operation.value === \"object\" &&\n operation.value !== null\n ) {\n const value = operation.value as Record<string, unknown>;\n if (typeof value.active === \"boolean\") nextActive = value.active;\n if (typeof value.displayName === \"string\") patchData.name = value.displayName;\n if (typeof value.userName === \"string\") {\n patchData.email = value.userName;\n patchData.emailVerificationTime = Date.now();\n }\n continue;\n }\n if (operation.path === \"active\") {\n nextActive = typeof operation.value === \"boolean\" ? operation.value : undefined;\n continue;\n }\n if (operation.path === \"displayName\" || operation.path === \"name.formatted\") {\n patchData.name = operation.value;\n continue;\n }\n if (operation.path === \"name.givenName\") {\n patchData.firstName = operation.value;\n continue;\n }\n if (operation.path === \"name.familyName\") {\n patchData.lastName = operation.value;\n continue;\n }\n if (operation.path === \"userName\" || operation.path === \"emails.value\") {\n patchData.email = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n continue;\n }\n if (operation.path === \"phoneNumbers.value\") {\n patchData.phone = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n continue;\n }\n unsupportedScimPatch();\n }\n }\n const resolvedExternalId = externalId ?? existingIdentity.externalId;\n await updateScimUser(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n userId,\n externalId: resolvedExternalId,\n userData: patchData,\n profileUpdate: state.policy.provisioning.user.updateProfileFromScim,\n roleIds: resolveProvisionedRoleIds({\n policy: state.policy,\n groups: provisionProfile.groups,\n roles: provisionProfile.roles,\n }),\n active: provisionProfile.active !== false && nextActive !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n });\n await state.recordScimEvent(\"connection.scim.user.updated\", \"success\", {\n type: \"user\",\n id: userId,\n });\n const updatedUser = await auth.user.get(state.ctx, { id: userId });\n await notifyScimAfterProvision(async () =>\n config.connection?.hooks?.afterProvision?.({\n protocol: \"scim\",\n connectionId: state.connection._id,\n profile: provisionProfile as Record<string, unknown>,\n userId: userId as GenericId<\"User\">,\n }),\n );\n const location = `${state.url.origin}${state.url.pathname}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: updatedUser ?? existingUser,\n externalId,\n location,\n active: provisionProfile.active !== false && nextActive !== false,\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleUsersDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(state.parsedPath.resourceId, \"User\");\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const identity = await getScimIdentityByConnectionAndUser(\n state.ctx,\n config.component.connection,\n {\n connectionId: state.connection._id,\n userId,\n },\n );\n if (!identity) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const { cleanupPending } = await revokeScimUser(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n userId,\n mode: state.policy.provisioning.deprovision.mode,\n });\n await state.recordScimEvent(\n \"session.invalidated\",\n \"success\",\n { type: \"user\", id: userId },\n { userId, reason: \"connection_deprovision\", cleanupPending },\n );\n await state.recordScimEvent(\"connection.scim.user.deactivated\", \"success\", {\n type: \"user\",\n id: userId,\n });\n return new Response(null, { status: 204 });\n };\n\n const handleGroupsGet: ScimHandler = async (state) => {\n if (state.parsedPath.resourceId) {\n const groupId = state.parsedPath.resourceId;\n const group = (await auth.group.get(state.ctx, { id: groupId })) as GroupRecord | null;\n if (!group || group.parentGroupId !== state.connection.groupId) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n const identity = await getScimIdentityByMappedGroup(\n state.ctx,\n config.component.connection,\n groupId,\n );\n const scopedIdentity =\n identity && identity.connectionId === state.connection._id ? identity : undefined;\n const members = (\n await collectMembers(state.ctx, { groupId: group._id, status: \"active\" })\n ).map((member) => ({ value: member.userId }));\n const location = `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${group._id}`;\n await state.recordScimEvent(\n \"connection.scim.read\",\n \"success\",\n { type: \"group\", id: group._id },\n { resourceType: \"group\", resourceId: group._id, operation: \"get\" },\n );\n return scimJson(\n serializeScimGroup({\n id: group._id,\n group,\n externalId: scopedIdentity?.externalId,\n location,\n members,\n }),\n 200,\n { Location: location },\n );\n }\n const groupsList = {\n page: await collectGroups(state.ctx, { parentGroupId: state.connection.groupId }),\n };\n const identities = await listScimIdentitiesByConnection(\n state.ctx,\n config.component.connection,\n state.connection._id,\n );\n const identityByGroupId = new Map(\n identities\n .filter(\n (\n identity: ScimIdentityRecord,\n ): identity is ScimIdentityRecord & { mappedGroupId: string } =>\n typeof identity.mappedGroupId === \"string\",\n )\n .map((identity: ScimIdentityRecord & { mappedGroupId: string }) => [\n identity.mappedGroupId,\n identity,\n ]),\n );\n const groups: GroupListItem[] = await Promise.all(\n groupsList.page.map(async (group) => {\n const typedGroup = group as GroupRecord;\n const members = await collectMembers(state.ctx, {\n groupId: typedGroup._id,\n status: \"active\",\n });\n return {\n group: typedGroup,\n identity: identityByGroupId.get(typedGroup._id),\n memberIds: members.map((member) => member.userId),\n };\n }),\n );\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection<GroupListItem>(groups, listRequest.filter, {\n id: (item) => item.group._id,\n externalId: (item) => item.identity?.externalId,\n displayName: (item) => item.group.name,\n \"members.value\": (item) => item.memberIds,\n });\n const paged = paginateScimCollection(filtered, listRequest);\n await state.recordScimEvent(\n \"connection.scim.read\",\n \"success\",\n { type: \"connection\", id: state.connection._id },\n {\n resourceType: \"group\",\n operation: \"list\",\n },\n );\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ group, identity }) =>\n serializeScimGroup({\n id: group._id,\n group,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${group._id}`,\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleGroupsPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const memberIds = (Array.isArray(body.members) ? body.members : []).map((member) =>\n String(member.value),\n );\n const externalIdForGroup =\n typeof body.externalId === \"string\" ? body.externalId : undefined;\n const provisioned = await provisionScimGroup(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n externalId: externalIdForGroup,\n name: typeof body.displayName === \"string\" ? body.displayName : \"Group\",\n memberIds,\n roleIds: resolveProvisionedRoleIds({\n policy: state.policy,\n groups: typeof body.displayName === \"string\" ? [body.displayName] : undefined,\n roles: pickStringArray((body as Record<string, unknown>).roles),\n }),\n raw: body,\n });\n await state.recordScimEvent(\n provisioned.created\n ? \"connection.scim.group.provisioned\"\n : \"connection.scim.group.updated\",\n \"success\",\n { type: \"group\", id: provisioned.groupId },\n );\n const group = await auth.group.get(state.ctx, { id: provisioned.groupId });\n const location = `${state.url.origin}${state.url.pathname}/${provisioned.groupId}`;\n return scimJson(\n serializeScimGroup({\n id: provisioned.groupId,\n group: group ?? {},\n externalId: externalIdForGroup,\n location,\n members: memberIds.map((value) => ({ value })),\n }),\n provisioned.created ? 201 : 200,\n { Location: location },\n );\n };\n\n const handleGroupsPatch: ScimHandler = async (state) => {\n const missing = requireScimResourceId(state.parsedPath.resourceId, \"Group\");\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n const identity = await getScimIdentityByMappedGroup(\n state.ctx,\n config.component.connection,\n groupId,\n );\n if (!identity || identity.connectionId !== state.connection._id) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n const group = await auth.group.get(state.ctx, { id: groupId });\n if (!group) return scimError(404, \"notFound\", \"Group not found.\");\n const currentMembers = await collectMembersForReplace(state.ctx, { groupId });\n const nextMemberIds = new Set(currentMembers.map((member) => member.userId));\n let name = typeof group.name === \"string\" ? group.name : \"Group\";\n const body = (await readScimJson(state.request)) as ScimBody;\n const operations = Array.isArray(body.Operations)\n ? body.Operations\n : unsupportedScimPatch();\n for (const operation of operations) {\n const op = typeof operation.op === \"string\" ? operation.op.toLowerCase() : \"replace\";\n if (\n operation.path === undefined &&\n op === \"replace\" &&\n typeof operation.value === \"object\" &&\n operation.value !== null\n ) {\n const value = operation.value as Record<string, unknown>;\n if (typeof value.displayName === \"string\") {\n name = value.displayName;\n }\n if (Array.isArray(value.members)) {\n nextMemberIds.clear();\n for (const member of value.members) {\n nextMemberIds.add(String((member as { value?: unknown }).value));\n }\n }\n continue;\n }\n if (operation.path === \"displayName\") {\n if (op !== \"replace\" && op !== \"add\") unsupportedScimPatch();\n if (typeof operation.value === \"string\") {\n name = operation.value;\n } else {\n unsupportedScimPatch();\n }\n continue;\n }\n if (operation.path === \"members\" && op === \"add\") {\n const addUserIds = (Array.isArray(operation.value) ? operation.value : []).map(\n (member) => String((member as { value?: unknown }).value),\n );\n for (const userId of addUserIds) nextMemberIds.add(userId);\n continue;\n }\n if (operation.path === \"members\" && op === \"replace\") {\n nextMemberIds.clear();\n for (const member of Array.isArray(operation.value) ? operation.value : []) {\n nextMemberIds.add(String((member as { value?: unknown }).value));\n }\n continue;\n }\n if (\n typeof operation.path === \"string\" &&\n op === \"remove\" &&\n operation.path.startsWith(\"members[\")\n ) {\n const match = operation.path.match(/^members\\[value eq \"([^\"]+)\"\\]$/);\n const userId = match?.[1];\n if (userId) nextMemberIds.delete(userId);\n continue;\n }\n unsupportedScimPatch();\n }\n await updateScimGroup(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n groupId,\n name,\n memberIds: [...nextMemberIds],\n roleIds: resolveProvisionedRoleIds({\n policy: state.policy,\n groups: [name],\n roles: pickStringArray((body as Record<string, unknown>).roles),\n }),\n raw: body,\n });\n await state.recordScimEvent(\"connection.scim.group.updated\", \"success\", {\n type: \"group\",\n id: groupId,\n });\n const location = `${state.url.origin}${state.url.pathname}`;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: { ...group, name },\n externalId: identity.externalId,\n location,\n members: [...nextMemberIds].map((value) => ({ value })),\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleGroupsDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(state.parsedPath.resourceId, \"Group\");\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n const identity = await getScimIdentityByMappedGroup(\n state.ctx,\n config.component.connection,\n groupId,\n );\n if (!identity || identity.connectionId !== state.connection._id) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n await revokeScimGroup(state.ctx, config.component.connection, {\n connectionId: state.connection._id,\n groupId,\n });\n await state.recordScimEvent(\"connection.scim.group.deactivated\", \"success\", {\n type: \"group\",\n id: groupId,\n });\n return new Response(null, { status: 204 });\n };\n\n const scimHandlers: Record<string, Partial<Record<string, ScimHandler>>> = {\n ServiceProviderConfig: {\n GET: async () =>\n scimJson({\n schemas: [\"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\"],\n patch: { supported: true },\n bulk: {\n supported: false,\n maxOperations: 0,\n maxPayloadSize: 0,\n },\n filter: { supported: true, maxResults: 100 },\n changePassword: { supported: false },\n sort: { supported: false },\n etag: { supported: false },\n authenticationSchemes: [\n {\n type: \"oauthbearertoken\",\n name: \"Bearer Token\",\n description: \"Use the SCIM token generated by Convex Auth connection.\",\n },\n ],\n }),\n },\n Schemas: {\n GET: async (state) =>\n handleStaticScimCollection(SCIM_SCHEMAS, state.parsedPath.resourceId, {\n by: \"id\",\n notFound: \"Schema not found.\",\n }),\n },\n ResourceTypes: {\n GET: async (state) =>\n handleStaticScimCollection(SCIM_RESOURCE_TYPES, state.parsedPath.resourceId, {\n by: \"name\",\n notFound: \"Resource type not found.\",\n }),\n },\n Users: {\n GET: handleUsersGet,\n POST: handleUsersPost,\n PATCH: handleUsersUpsert,\n PUT: handleUsersUpsert,\n DELETE: handleUsersDelete,\n },\n Groups: {\n GET: handleGroupsGet,\n POST: handleGroupsPost,\n PATCH: handleGroupsPatch,\n DELETE: handleGroupsDelete,\n },\n };\n\n const handler = scimHandlers[state.parsedPath.resource]?.[state.request.method];\n return handler\n ? await handler(state)\n : scimError(404, \"notFound\", \"SCIM resource not found.\");\n } catch (error) {\n if (error instanceof Error && error.message === \"Unsupported SCIM filter.\") {\n return scimError(400, \"invalidFilter\", error.message);\n }\n if (error instanceof Error && error.message === \"Invalid SCIM pagination.\") {\n return scimError(400, \"invalidValue\", error.message);\n }\n if (error instanceof Error && error.message === \"Invalid SCIM JSON.\") {\n return scimError(400, \"invalidSyntax\", error.message);\n }\n if (error instanceof Error && error.message === \"Unsupported SCIM content type.\") {\n return scimError(415, \"invalidSyntax\", error.message);\n }\n if (error instanceof Error && error.message === \"Unsupported SCIM PATCH operation.\") {\n return scimError(400, \"invalidSyntax\", error.message);\n }\n if (error instanceof Error && error.message === \"SCIM member set too large to reconcile.\") {\n return scimError(413, \"tooLarge\", error.message);\n }\n if (\n error instanceof ConvexError &&\n typeof error.data === \"object\" &&\n error.data !== null &&\n \"code\" in error.data &&\n \"message\" in error.data\n ) {\n const code = error.data.code as string;\n const status = code === \"MISSING_BEARER_TOKEN\" || code === \"INVALID_API_KEY\" ? 401 : 400;\n const response = scimError(\n status,\n status === 401 ? \"invalidValue\" : code,\n error.data.message,\n );\n if (status === 401) {\n response.headers.set(\"WWW-Authenticate\", \"Bearer\");\n }\n return response;\n }\n log(\"WARN\", \"[connection.scim] unhandled error surfaced as SCIM 500\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return scimError(500, \"internalError\", \"SCIM request failed.\");\n }\n };\n\n const handleOidcCallbackForConnection = async (\n ctx: GenericActionCtx<GenericDataModel>,\n request: Request,\n connectionId: string,\n ) => {\n const params = await getOidcCallbackParams(request);\n const { connection, oidc } = await loadConnectionOidcOrThrow(ctx, connectionId);\n const { providerId, provider, oauthConfig } = await createGroupConnectionOidcRuntime({\n ctx,\n componentConnection: config.component.connection,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n connectionId: connection._id,\n oidc,\n sharedRedirectURI: sharedOidcRedirectURI,\n });\n const cookies = getCookies(request);\n const maybeRedirectTo = useRedirectToParam(providerId, cookies);\n const destinationUrl = await redirectAbsoluteUrl(ctx, config, {\n redirectTo: maybeRedirectTo?.redirectTo,\n });\n let result: Awaited<ReturnType<typeof handleOAuthCallback>>;\n try {\n result = await handleOAuthCallback(\n providerId,\n { ...oauthConfig, provider },\n Object.fromEntries(params.entries()),\n cookies,\n );\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"oidc\",\n outcome: \"failure\",\n error,\n });\n throw error;\n }\n const extraFields =\n typeof oidc.profile === \"object\" && oidc.profile !== null\n ? ((oidc.profile as Record<string, unknown>).extraFields as\n | Record<string, string>\n | undefined)\n : undefined;\n let profile = result.profile as Record<string, unknown>;\n if (extraFields && typeof profile === \"object\" && profile) {\n const extend: Record<string, unknown> = {};\n for (const [claimName, fieldName] of Object.entries(extraFields)) {\n if (claimName in profile) {\n extend[fieldName] = profile[claimName];\n }\n }\n if (Object.keys(extend).length > 0) {\n profile = { ...profile, extend };\n }\n }\n\n let verificationCode: string;\n try {\n verificationCode = await callUserOAuth(ctx, {\n provider: providerId,\n providerAccountId: result.providerAccountId,\n profile: profile as AuthProfile,\n signature: result.signature,\n accountExtend: {\n identity: {\n protocol: \"oidc\",\n connectionId: connection._id,\n subject: result.providerAccountId,\n issuer:\n typeof (oidc.discovery as Record<string, unknown> | undefined)?.issuer === \"string\"\n ? ((oidc.discovery as Record<string, unknown>).issuer as string)\n : undefined,\n discoveryUrl:\n typeof (oidc.discovery as Record<string, unknown> | undefined)?.discoveryUrl ===\n \"string\"\n ? ((oidc.discovery as Record<string, unknown>).discoveryUrl as string)\n : undefined,\n },\n },\n });\n } catch (error) {\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"oidc\",\n outcome: \"failure\",\n error,\n });\n throw error;\n }\n await recordConnectionLoginEvent(ctx, {\n connection,\n protocol: \"oidc\",\n outcome: \"success\",\n });\n const headers = new Headers({\n Location: setURLSearchParam(destinationUrl, \"code\", verificationCode),\n });\n for (const { name, value, options } of result.cookies) {\n headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n if (maybeRedirectTo) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(\n maybeRedirectTo.updatedCookie.name,\n maybeRedirectTo.updatedCookie.value,\n maybeRedirectTo.updatedCookie.options,\n ),\n );\n }\n return new Response(null, { status: 302, headers });\n };\n\n addConnectionRoutes(http, {\n routeBase: GROUP_CONNECTION_ROUTE_BASE,\n convertErrorsToResponse,\n handleSamlMetadata: async (ctx, _request, runtimeRoute) => {\n const { loaded } = await loadActiveConnectionSamlOrThrow(ctx, runtimeRoute.connectionId);\n return new Response(\n createGroupConnectionSamlMetadataXml({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: loaded.source,\n config: loaded.config,\n }),\n {\n status: 200,\n headers: { \"Content-Type\": \"application/xml\" },\n },\n );\n },\n handleSamlSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw convexError(ErrorCode.OAUTH_MISSING_VERIFIER, \"Missing sign-in verifier.\");\n }\n const { loaded, connection } = await loadActiveConnectionSamlOrThrow(\n ctx,\n runtimeRoute.connectionId,\n );\n const state = generateRandomString(24, INVITE_TOKEN_ALPHABET);\n const signInRequest = await createGroupConnectionSamlSignInRequest({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"connection\", id: connection._id },\n config: loaded.config,\n state,\n signature: `saml ${connection._id} pending ${state}`,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n const signature = `saml ${connection._id} ${signInRequest.requestId} ${state}`;\n await callVerifierSignature(ctx, { verifier, signature });\n const nowMs = Date.now();\n await ctx.runMutation(config.component.connection.saml.request.create, {\n connectionId: connection._id,\n requestId: signInRequest.requestId,\n createdAt: nowMs,\n expiresAt: nowMs + SAML_LOGIN_REQUEST_TTL_MS,\n });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const redirectCookies =\n redirectTo !== null\n ? [redirectToParamCookie(groupSamlProviderId(connection._id), redirectTo)]\n : [];\n const relayState = encodeGroupSamlRelayState({\n source: { kind: \"connection\", id: connection._id },\n signature,\n requestId: signInRequest.requestId,\n state,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n if (signInRequest.binding === \"redirect\" && signInRequest.redirectUrl) {\n const redirectUrl = new URL(signInRequest.redirectUrl);\n redirectUrl.searchParams.set(\"RelayState\", relayState);\n const headers = new Headers({\n Location: redirectUrl.toString(),\n });\n for (const { name, value, options } of redirectCookies as CookieToSerialize[]) {\n headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers });\n }\n const response = createSamlPostBindingResponse({\n endpoint: signInRequest.post!.endpoint,\n parameter: \"SAMLRequest\",\n value: signInRequest.post!.value,\n relayState,\n });\n for (const { name, value, options } of redirectCookies as CookieToSerialize[]) {\n response.headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return response;\n },\n handleOidcSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw convexError(ErrorCode.OAUTH_MISSING_VERIFIER, \"Missing sign-in verifier.\");\n }\n const { connection, oidc } = await loadConnectionOidcOrThrow(ctx, runtimeRoute.connectionId);\n const { providerId, provider, oauthConfig } = await createGroupConnectionOidcRuntime({\n ctx,\n componentConnection: config.component.connection,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n connectionId: connection._id,\n oidc,\n sharedRedirectURI: sharedOidcRedirectURI,\n });\n const { redirect, cookies, signature } = await createOAuthAuthorizationURL(\n providerId,\n {\n ...oauthConfig,\n provider,\n },\n {\n loginHint:\n url.searchParams.get(\"loginHint\") ??\n (typeof (oidc.request as Record<string, unknown> | undefined)?.loginHint === \"string\"\n ? ((oidc.request as Record<string, unknown>).loginHint as string)\n : undefined),\n stateTransform:\n typeof sharedOidcRedirectURI === \"string\"\n ? (state) =>\n encodeGroupOidcState({\n connectionId: connection._id,\n state,\n })\n : undefined,\n },\n );\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const headers_ = new Headers({ Location: redirect });\n for (const { name, value, options } of [\n ...cookies,\n ...(redirectTo !== null ? [redirectToParamCookie(providerId, redirectTo)] : []),\n ] as CookieToSerialize[]) {\n headers_.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, {\n status: 302,\n headers: headers_,\n });\n },\n handleOidcCallback: async (ctx, request, runtimeRoute) => {\n return await handleOidcCallbackForConnection(ctx, request, runtimeRoute.connectionId);\n },\n handleSamlAcs,\n handleSamlSlo,\n handleScimRequest,\n sharedOidcCallbackPath: sharedOidcRedirectURI,\n handleOidcSharedCallback: async (ctx, request) => {\n const url = new URL(request.url);\n const params = await getOidcCallbackParams(request);\n const { connectionId } = decodeGroupOidcState(params.get(\"state\"));\n url.search = params.toString();\n const normalizedRequest = new Request(url, request);\n return await handleOidcCallbackForConnection(ctx, normalizedRequest, connectionId);\n },\n scimError,\n });\n}\n"],"mappings":"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"}
|