Files
better-auth/packages/scim/CHANGELOG.md
better-release[bot]GitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
f4260a95cd chore: release v1.7.12 (#11922)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-10-20 11:51:50 +00:00

59 KiB

@better-auth/scim

1.7.12

1.7.11

1.7.10

1.7.9

1.7.8

Patch Changes

  • #11512 4175b34 Thanks @bytaesu! - Align the installed @better-auth/utils version with better-call while accepting ^0.4.2 || ^0.5.0 across official package peers.

  • #11644 f556970 Thanks @gustavovalverde! - If your SCIM provider sends attribute names with different letter case than the SCIM schema, such as Active or Emails, Better Auth now applies them. Previously these keys were ignored while the request still succeeded, so a PUT with Active: false left the User active. A request that sends the same attribute twice with different letter case now returns 400 Bad Request. Providers that send the standard attribute names are unaffected.

  • #11638 39f0980 Thanks @gustavovalverde! - SCIM User and Group requests now accept JSON null attribute values, such as the unpopulated attributes Microsoft Entra ID sends, instead of returning 400 Bad Request. In POST and PUT bodies a null attribute is treated as omitted, and in PATCH a null value removes the attribute. active: null is still rejected, and null on a read-only attribute is ignored.

  • #11167 666e1de Thanks @jonathansamines! - Fix POST /scim/v2/Users rejecting a reprovisioned user with a uniqueness conflict when an inactive SCIM User already has the same externalId, such as when Okta reassigns a deactivated user. The inactive SCIM User is now reprovisioned in place and keeps its ID and linked Better Auth User.

  • #11669 8409fb2 Thanks @gustavovalverde! - SCIM directories that send concurrent updates now get a 409 uniqueness error when a User PATCH, Group PUT, or Group PATCH claims a userName, displayName, externalId, or managed email that another request saved first. Previously the losing request failed with a 500 server error. Requests that don't race are unaffected.

1.7.7

1.7.6

1.7.5

1.7.4

1.7.3

1.7.2

1.7.1

1.7.0

Minor Changes

  • #10474 dec763e Thanks @gustavovalverde! - Add acquireActiveSCIMUserLink for transaction-safe authentication of provisioned users. The helper maps an exact SCIM connection ID and externalId to an active Better Auth User while fencing concurrent subject changes, deactivation, deletion, and connection decommissioning.

    Compose the helper with SSO resolveUser to link the provisioned User without matching by email or userName.

  • #10390 0de88f5 Thanks @gustavovalverde! - SCIM connections can now provision Users, Groups, and direct memberships into application-defined provisioning domains without the organization or SSO plugins. Applications can map Group membership to validated custom roles through projections. The service also supports SCIM 2.0 discovery, filtering, pagination, response attribute selection, atomic PATCH operations, and common request patterns used by Microsoft Entra ID and Okta.

    This replaces the previous SCIM configuration, client APIs, database schema, and organization-backed Group model. Existing SCIM installations cannot migrate provisioning state in place. Follow the SCIM cutover in the 1.7 upgrade guide, including full directory reprovisioning, before resuming traffic.

    Deferred database side effects now run only after a successful transaction. A rolled-back User update no longer refreshes its cached profile, and a rolled-back bulk session revocation no longer invalidates sessions.

  • #10592 26b1949 Thanks @gustavovalverde! - Allow SCIM bearer verification to resolve application-owned connections at request time. Dynamic connections use the same scope enforcement, immutable provisioning-domain binding, decommissioning, and request fencing as code-defined connections, while an empty static connection list is supported when a verifier is configured.

  • #10620 b7683b8 Thanks @gustavovalverde! - Add the standard Enterprise User extension (employeeNumber, costCenter, organization, division, department, manager) and the classic title, userType, preferredLanguage, locale, timezone, phoneNumbers, addresses, roles, and entitlements User attributes, plus name.middleName, name.honorificPrefix, and name.honorificSuffix. All are readable, filterable by type or primary, and writable through PATCH, including the classic Microsoft Entra manager path aliases.

    Add compatibility.microsoftEntra.acceptLegacyGroupSchema to accept Microsoft Entra's legacy, attribute-less Group schema marker on POST /Groups without storing or returning it.

    Microsoft Entra interoperability fixes:

    • A bare attributes/excludedAttributes name for an Enterprise User sub-attribute (for example ?attributes=manager) no longer drops the whole extension from the response.
    • Multi-op PATCH paths filtered by [primary eq true] (or [primary eq "true"]) with a sub-attribute target now work on emails, phoneNumbers, addresses, roles, and entitlements.
    • A single-element array wrapping a scalar PATCH replace value is unwrapped instead of rejected, on User scalars, Enterprise User fields, and Group displayName and externalId.
    • Removing the last sub-attribute of a complex attribute (for example manager.value) clears the emptied Enterprise User extension instead of leaving it declared.
    • Replacing manager with an empty string clears it, matching how Microsoft Entra removes a manager.
    • A PATCH with an empty Operations array is a valid no-op instead of an error, for both Users and Groups.
    • PATCH /Users/:id and PATCH /Groups/:id return 200 OK with the updated resource instead of 204 No Content.
  • #10682 8b96573 Thanks @gustavovalverde! - SCIM PATCH operations that target filtered multi-valued attributes (phoneNumbers, addresses, roles, entitlements, emails) now create the value when the filter matches nothing instead of rejecting the request with a noTarget error. Microsoft Entra ID sends these operations for attributes that are not populated yet, and the rejection also discarded every other operation bundled in the same PATCH request.

  • #10018 445b034 Thanks @gustavovalverde! - Add durable SCIM Group resources with connection-scoped membership, projection callbacks, metadata, and Group lifecycle endpoints. Groups belong to SCIM connections rather than Better Auth Organizations.

  • #10592 26b1949 Thanks @gustavovalverde! - Add an optional SCIM-owned connection and credential catalog. Configure managedConnections to let trusted server code create runtime tenant connections and issue, rotate, and revoke their bearer credentials through server-only auth.api methods, without a code-defined connection or an application-owned verifier.

Patch Changes

  • #10620 b7683b8 Thanks @gustavovalverde! - Accept exact case-insensitive string Boolean values for SCIM User active and the primary sub-attribute of emails, phoneNumbers, addresses, roles, and entitlements at the HTTP ingress for Microsoft Entra interoperability.

  • #10592 26b1949 Thanks @gustavovalverde! - Allow trusted server code to retain a terminal connection binding before a dynamic SCIM connection's first authenticated request by supplying its provisioning domain during decommissioning.

  • #9864 41cca60 Thanks @GautamBytes! - Add a user.validateUserInfo provisioning gate that lets applications reject an identity before a user is created or a new account is linked. It runs once at the creation step for every method that provisions a user (OAuth, SSO/SAML, email/password, magic link, email OTP, anonymous, SIWE, phone number, admin-created users, and SCIM), including stateless setups with no persistent database.

    It also re-runs when an existing OAuth or SSO user signs in again (source.action is "sign-in"), where it receives the fresh provider email and profile so a domain or org policy can reject a user whose provider identity moved out of bounds. Non-provider returning sign-ins are not re-validated.

    The callback receives the mapped user plus a source describing the action (create-user, link-account, or sign-in), the method, and provider metadata: source.oauth for OAuth providers and source.sso for OIDC/SAML SSO providers. Return { error, errorDescription } to reject: browser flows redirect to the error URL and programmatic flows return a 403.

1.7.0-rc.6

1.7.0-rc.5

1.7.0-rc.4

Minor Changes

  • #10682 8b96573 Thanks @gustavovalverde! - SCIM PATCH operations that target filtered multi-valued attributes (phoneNumbers, addresses, roles, entitlements, emails) now create the value when the filter matches nothing instead of rejecting the request with a noTarget error. Microsoft Entra ID sends these operations for attributes that are not populated yet, and the rejection also discarded every other operation bundled in the same PATCH request.

1.7.0-rc.3

Minor Changes

  • #10592 26b1949 Thanks @gustavovalverde! - Allow SCIM bearer verification to resolve application-owned connections at request time. Dynamic connections use the same scope enforcement, immutable provisioning-domain binding, decommissioning, and request fencing as code-defined connections, while an empty static connection list is supported when a verifier is configured.

  • #10620 b7683b8 Thanks @gustavovalverde! - Add the standard Enterprise User extension (employeeNumber, costCenter, organization, division, department, manager) and the classic title, userType, preferredLanguage, locale, timezone, phoneNumbers, addresses, roles, and entitlements User attributes, plus name.middleName, name.honorificPrefix, and name.honorificSuffix. All are readable, filterable by type or primary, and writable through PATCH, including the classic Microsoft Entra manager path aliases.

    Add compatibility.microsoftEntra.acceptLegacyGroupSchema to accept Microsoft Entra's legacy, attribute-less Group schema marker on POST /Groups without storing or returning it.

    Microsoft Entra interoperability fixes:

    • A bare attributes/excludedAttributes name for an Enterprise User sub-attribute (for example ?attributes=manager) no longer drops the whole extension from the response.
    • Multi-op PATCH paths filtered by [primary eq true] (or [primary eq "true"]) with a sub-attribute target now work on emails, phoneNumbers, addresses, roles, and entitlements.
    • A single-element array wrapping a scalar PATCH replace value is unwrapped instead of rejected, on User scalars, Enterprise User fields, and Group displayName and externalId.
    • Removing the last sub-attribute of a complex attribute (for example manager.value) clears the emptied Enterprise User extension instead of leaving it declared.
    • Replacing manager with an empty string clears it, matching how Microsoft Entra removes a manager.
    • A PATCH with an empty Operations array is a valid no-op instead of an error, for both Users and Groups.
    • PATCH /Users/:id and PATCH /Groups/:id return 200 OK with the updated resource instead of 204 No Content.
  • #10592 26b1949 Thanks @gustavovalverde! - Add an optional SCIM-owned connection and credential catalog. Configure managedConnections to let trusted server code create runtime tenant connections and issue, rotate, and revoke their bearer credentials through server-only auth.api methods, without a code-defined connection or an application-owned verifier.

Patch Changes

  • #10620 b7683b8 Thanks @gustavovalverde! - Accept exact case-insensitive string Boolean values for SCIM User active and the primary sub-attribute of emails, phoneNumbers, addresses, roles, and entitlements at the HTTP ingress for Microsoft Entra interoperability.

  • #10592 26b1949 Thanks @gustavovalverde! - Allow trusted server code to retain a terminal connection binding before a dynamic SCIM connection's first authenticated request by supplying its provisioning domain during decommissioning.

1.7.0-rc.2

Minor Changes

  • #10474 dec763e Thanks @gustavovalverde! - Add acquireActiveSCIMUserLink for transaction-safe authentication of provisioned users. The helper maps an exact SCIM connection ID and externalId to an active Better Auth User while fencing concurrent subject changes, deactivation, deletion, and connection decommissioning.

    Compose the helper with SSO resolveUser to link the provisioned User without matching by email or userName.

  • #10390 0de88f5 Thanks @gustavovalverde! - SCIM connections can now provision Users, Groups, and direct memberships into application-defined provisioning domains without the organization or SSO plugins. Applications can map Group membership to validated custom roles through projections. The service also supports SCIM 2.0 discovery, filtering, pagination, response attribute selection, atomic PATCH operations, and common request patterns used by Microsoft Entra ID and Okta.

    This replaces the previous SCIM configuration, client APIs, database schema, and organization-backed Group model. Existing SCIM installations cannot migrate provisioning state in place. Follow the SCIM cutover in the 1.7 upgrade guide, including full directory reprovisioning, before resuming traffic.

    Deferred database side effects now run only after a successful transaction. A rolled-back User update no longer refreshes its cached profile, and a rolled-back bulk session revocation no longer invalidates sessions.

1.7.0-rc.1

1.7.0-rc.0

Minor Changes

  • #10249 dfecb48 Thanks @gustavovalverde! - Runtime SCIM tokens now require organizationId; use staticProviders for app-level SCIM.

    SCIM-managed accounts now use namespaced provider IDs (scim:{organizationId}:{providerId} or scim:{providerId} for app-level static providers). Migrate only known SCIM-managed account rows before upgrading; leave non-SCIM accounts unchanged even when they share the same provider ID.

    Organization-scoped active: false now makes a user inactive in that organization while keeping SCIM group and team associations available for reactivation. Use DELETE to fully deprovision organization-scoped SCIM state.

    defaultSCIM has been replaced by staticProviders. linkExistingUsers.trustedDomains has been removed; use requireExistingOrgMembership, shouldLinkUser, or explicit true instead.

1.7.0-beta.10

1.7.0-beta.9

Patch Changes

  • Updated dependencies []:
    • better-auth@1.7.0-beta.9
    • @better-auth/core@1.7.0-beta.9

1.7.0-beta.8

Patch Changes

1.7.0-beta.7

Patch Changes

  • Updated dependencies [3d04fab, de8394d]:
    • better-auth@1.7.0-beta.7
    • @better-auth/core@1.7.0-beta.7

1.7.0-beta.6

Minor Changes

  • #10018 445b034 Thanks @gustavovalverde! - Add durable SCIM Group resources with organization-scoped membership, role projection, metadata, and Group lifecycle endpoints.

Patch Changes

1.7.0-beta.5

Patch Changes

  • #9864 41cca60 Thanks @GautamBytes! - Add a user.validateUserInfo provisioning gate that lets applications reject an identity before a user is created or a new account is linked. It runs once at the creation step for every method that provisions a user (OAuth, SSO/SAML, email/password, magic link, email OTP, anonymous, SIWE, phone number, admin-created users, and SCIM), including stateless setups with no persistent database.

    It also re-runs when an existing OAuth or SSO user signs in again (source.action is "sign-in"), where it receives the fresh provider email and profile so a domain or org policy can reject a user whose provider identity moved out of bounds. Non-provider returning sign-ins are not re-validated.

    The callback receives the mapped user plus a source describing the action (create-user, link-account, or sign-in), the method, and provider metadata: source.oauth for OAuth providers and source.sso for OIDC/SAML SSO providers. Return { error, errorDescription } to reject: browser flows redirect to the error URL and programmatic flows return a 403.

  • Updated dependencies [0cbaf81, e014029, ec8a38c, 7fe0e2b, 4f53b61, e0d2b9e, 91f235f, 76a3342, 41cca60]:

    • better-auth@1.7.0-beta.5
    • @better-auth/core@1.7.0-beta.5

1.7.0-beta.4

Minor Changes

  • #9840 a8ea86e Thanks @gustavovalverde! - Personal (non-organization) SCIM connections now always belong to the user who created them. Owner binding used to be opt-in through the providerOwnership option, which defaulted to off. With it off, a personal connection was stored without an owner, and the management endpoints denied access only when a stored owner differed from the caller. An unowned connection passed that check for any signed-in user, who could read it, list it, regenerate its token, or delete it. Regenerating the token rotated the secret and invalidated the original.

    generateSCIMToken now records the creator's userId on every personal connection. The generate-token, list-provider-connections, get-provider-connection, and delete-provider-connection endpoints grant access only to that owner. Organization-scoped connections keep their existing behavior and continue to use organization membership and the configured requiredRole checks.

    This release is breaking. It removes the providerOwnership option, and owner binding can no longer be disabled. The scimProvider.userId column is now a permanent part of the schema, so run a migration after upgrading with npx auth migrate or npx auth generate.

    Connections created before this release carry no owner. Access now fails closed, so those connections are no longer reachable through the management endpoints, including token regeneration. Reclaim them at the database level: delete scimProvider rows that have neither organizationId nor userId, or set userId to the intended owner, then regenerate tokens as needed. Organization-scoped connections are not affected.

1.6.30

Patch Changes

  • Updated dependencies [07c1718]:
    • @better-auth/core@1.6.30
    • better-auth@1.6.30

1.6.29

Patch Changes

  • Updated dependencies [e6e1b4e]:
    • better-auth@1.6.29
    • @better-auth/core@1.6.29

1.6.28

Patch Changes

  • Updated dependencies [773de54, 2ad2928]:
    • better-auth@1.6.28
    • @better-auth/core@1.6.28

1.6.27

Patch Changes

  • Updated dependencies [2ae491e, 90b5093]:
    • @better-auth/core@1.6.27
    • better-auth@1.6.27

1.6.26

Patch Changes

1.6.25

Patch Changes

1.6.24

Patch Changes

1.6.23

Patch Changes

  • Updated dependencies [8581f97]:
    • better-auth@1.6.23
    • @better-auth/core@1.6.23

1.6.22

Patch Changes

  • #10242 7c126dc Thanks @gustavovalverde! - Tighten the SCIM user write path and honor the active attribute.

    A non-organization SCIM DELETE now unlinks the provider's own account when the user has other linked identities, and deletes the global user only when the SCIM account is their sole identity. PUT and PATCH reject changing a user's email to one already used by another user with a 409 conflict, and clear emailVerified when the email changes.

    The SCIM active attribute is honored on create, update, and patch. active: false deactivates the user through the admin plugin's banned state and revokes their sessions; active: true reactivates. The user resource reports the real state instead of always reporting active. Honoring active requires the admin plugin.

  • Updated dependencies [c06a56d, 8bd43d9, 3a035e9]:

    • better-auth@1.6.22
    • @better-auth/core@1.6.22

1.6.21

Patch Changes

  • #10224 7a7a7b3 Thanks @Bekacru! - Deleting an SSO provider no longer leaves linked accounts that a later provider with the same provider ID can reuse.

    SSO and SCIM provider setup now rejects provider IDs already used by another account provider.

    SSO provider updates now reject identity-defining changes, such as issuer, login endpoints, client ID, SAML metadata, or user ID mappings, after accounts are linked. Secret rotation and same-value updates still work.

  • Updated dependencies [e0762a1, 882cf9e, f52e1ab, 90d509e, b5bec19, 816d7f9, 239bcc8, 1bc370a, 570267c, 461ca6f, 88409b0, 5953157, b046f9e, ae647b4]:

    • better-auth@1.6.21
    • @better-auth/core@1.6.21

1.6.20

Patch Changes

1.6.19

Patch Changes

1.6.18

Patch Changes

  • Updated dependencies [9ef7240, b21a5f7]:
    • better-auth@1.6.18
    • @better-auth/core@1.6.18

1.6.17

Patch Changes

1.6.16

Patch Changes

  • #9974 cb1cbfa Thanks @Bekacru! - SCIM user provisioning no longer links to a pre-existing user by matching email alone. When a user with the same email already exists, createSCIMUser now returns 409 (uniqueness) unless the new linkExistingUsers option explicitly opts in (via true, trustedDomains, requireExistingOrgMembership, or a shouldLinkUser callback). Additionally, an organization-scoped SCIM DELETE now deprovisions the user — removing their organization membership and the SCIM account link — instead of deleting the global Better Auth user. A new canGenerateToken option lets applications authorize SCIM token creation, including restricting personal (non-org) tokens.

  • Updated dependencies [cb1cbfa, cb1cbfa, cb1cbfa, cb1cbfa, cb1cbfa, cb1cbfa, 87e7aa5, cb1cbfa, cb1cbfa, cb1cbfa, 893cf6c, cb1cbfa, cb1cbfa, 5e49c56, cb1cbfa]:

    • better-auth@1.6.16
    • @better-auth/core@1.6.16

1.6.15

Patch Changes

1.6.14

Patch Changes

1.6.13

Patch Changes

1.7.0-beta.3

Patch Changes

  • Updated dependencies [4e8e4c7, 523f95c, 729c00d]:
    • better-auth@1.7.0-beta.3
    • @better-auth/core@1.7.0-beta.3

1.7.0-beta.2

Patch Changes

1.7.0-beta.1

Patch Changes

1.7.0-beta.0

Patch Changes

1.6.10

Patch Changes

1.6.9

Patch Changes

  • Updated dependencies [815ecf6]:
    • @better-auth/core@1.6.9
    • better-auth@1.6.9

1.6.8

Patch Changes

  • Updated dependencies [856ab24, 9aa8e63]:
    • better-auth@1.6.8
    • @better-auth/core@1.6.8

1.6.7

Patch Changes

1.6.6

Patch Changes

1.6.5

Patch Changes

  • Updated dependencies [938dd80, 0538627]:
    • better-auth@1.6.5
    • @better-auth/core@1.6.5

1.6.4

Patch Changes

1.6.3

Patch Changes

1.6.2

Patch Changes

1.6.1

Patch Changes

1.6.0

Minor Changes

Patch Changes

1.6.0-beta.0

Minor Changes

  • 28b1291 Thanks @gustavovalverde! - Add optional version field to the plugin interface and expose version from all built-in plugins

Patch Changes