diff --git a/authentik/providers/scim/clients/users.py b/authentik/providers/scim/clients/users.py
index 90ffe76abb..f9bfe58b88 100644
--- a/authentik/providers/scim/clients/users.py
+++ b/authentik/providers/scim/clients/users.py
@@ -1,10 +1,12 @@
"""User client"""
+from django.db import transaction
+from django.utils.http import urlencode
from pydantic import ValidationError
from authentik.core.models import User
from authentik.lib.sync.mapper import PropertyMappingManager
-from authentik.lib.sync.outgoing.exceptions import StopSync
+from authentik.lib.sync.outgoing.exceptions import ObjectExistsSyncException, StopSync
from authentik.policies.utils import delete_none_values
from authentik.providers.scim.clients.base import SCIMClient
from authentik.providers.scim.clients.schema import SCIM_USER_SCHEMA
@@ -55,18 +57,35 @@ class SCIMUserClient(SCIMClient[User, SCIMProviderUser, SCIMUserSchema]):
def create(self, user: User):
"""Create user from scratch and create a connection object"""
scim_user = self.to_schema(user, None)
- response = self._request(
- "POST",
- "/Users",
- json=scim_user.model_dump(
- mode="json",
- exclude_unset=True,
- ),
- )
- scim_id = response.get("id")
- if not scim_id or scim_id == "":
- raise StopSync("SCIM Response with missing or invalid `id`")
- return SCIMProviderUser.objects.create(provider=self.provider, user=user, scim_id=scim_id)
+ with transaction.atomic():
+ try:
+ response = self._request(
+ "POST",
+ "/Users",
+ json=scim_user.model_dump(
+ mode="json",
+ exclude_unset=True,
+ ),
+ )
+ except ObjectExistsSyncException as exc:
+ if not self._config.filter.supported:
+ raise exc
+ users = self._request(
+ "GET", f"/Users?{urlencode({'filter': f'userName eq {scim_user.userName}'})}"
+ )
+ users_res = users.get("Resources", [])
+ if len(users_res) < 1:
+ raise exc
+ return SCIMProviderUser.objects.create(
+ provider=self.provider, user=user, scim_id=users_res[0]["id"]
+ )
+ else:
+ scim_id = response.get("id")
+ if not scim_id or scim_id == "":
+ raise StopSync("SCIM Response with missing or invalid `id`")
+ return SCIMProviderUser.objects.create(
+ provider=self.provider, user=user, scim_id=scim_id
+ )
def update(self, user: User, connection: SCIMProviderUser):
"""Update existing user"""
diff --git a/web/src/admin/providers/RelatedApplicationButton.ts b/web/src/admin/providers/RelatedApplicationButton.ts
index 3ada21bae9..c8ae28b5b8 100644
--- a/web/src/admin/providers/RelatedApplicationButton.ts
+++ b/web/src/admin/providers/RelatedApplicationButton.ts
@@ -21,12 +21,22 @@ export class RelatedApplicationButton extends AKElement {
@property({ attribute: false })
provider?: Provider;
+ @property()
+ mode: "primary" | "backchannel" = "primary";
+
render(): TemplateResult {
- if (this.provider?.assignedApplicationSlug) {
+ if (this.mode === "primary" && this.provider?.assignedApplicationSlug) {
return html`
${this.provider.assignedApplicationName}
`;
}
+ if (this.mode === "backchannel" && this.provider?.assignedBackchannelApplicationSlug) {
+ return html`
+ ${this.provider.assignedBackchannelApplicationName}
+ `;
+ }
return html`
${msg("Create")}
${msg("Create Application")}
diff --git a/web/src/admin/providers/scim/SCIMProviderViewPage.ts b/web/src/admin/providers/scim/SCIMProviderViewPage.ts
index 808d4d8534..d0b6f11210 100644
--- a/web/src/admin/providers/scim/SCIMProviderViewPage.ts
+++ b/web/src/admin/providers/scim/SCIMProviderViewPage.ts
@@ -173,6 +173,7 @@ export class SCIMProviderViewPage extends AKElement {