From 011ebf688d17f385af1e0dba601ec1a7750c87e0 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Thu, 2 Jul 2026 08:11:01 -0400 Subject: [PATCH 1/2] docs(kratos): document update identity on login for SAML connections Add an "Update identity on login" subsection to the SAML section of the Organizations guide. It mirrors the existing OIDC data-mapping option: setting update_identity_on_login to automatic re-runs the connection's Jsonnet data mapper on every SAML login and refreshes the identity's traits and metadata, including the metadata_public group claims used for just-in-time provisioning. Covers Console and API configuration, accessing the current identity via std.extVar('identity') in the mapper, and the write/preservation and schema-validation behavior. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/kratos/organizations/organizations.mdx | 81 +++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/docs/kratos/organizations/organizations.mdx b/docs/kratos/organizations/organizations.mdx index 14232c5f1f..2cd5388f44 100644 --- a/docs/kratos/organizations/organizations.mdx +++ b/docs/kratos/organizations/organizations.mdx @@ -433,6 +433,87 @@ local claims = std.extVar('claims'); } ``` +#### Update identity on login + +By default, the data mapper runs only when an identity first signs in through the SAML connection. If you want to keep identity +data in sync with the Identity Provider (IdP), set `update_identity_on_login` to `automatic` on the connection. This re-runs the +connection's Jsonnet data mapper on every SAML login and updates the identity's traits and metadata when they change. + +This is useful when the IdP is the source of truth for user attributes such as group memberships, roles, or profile information +that can change over time. + +The default is `never`, so existing SAML connections keep their current behavior until you opt in. + +```mdx-code-block + + +``` + +1. Go to and open the organization that holds the SAML connection. +2. Edit the Enterprise SAML SSO connection. +3. Set **Update identity on login** to **automatic**. + +```mdx-code-block + + +``` + +Replace the field on the connection you want to update. Adjust the provider index (`0` below) to match the position of your +connection in the `providers` array. + +```shell +curl -X PATCH --location "https://api.console.ory.com/projects/$PROJECT_ID" \ + -H "Authorization: Bearer $WORKSPACE_API_KEY" \ + -H "Content-Type: application/json" \ + -d '[ + { + "op": "replace", + "path": "/services/identity/config/selfservice/methods/saml/config/providers/0/update_identity_on_login", + "value": "automatic" + } + ]' \ + | jq ".project.services.identity.config.selfservice.methods.saml" +``` + +```mdx-code-block + + +``` + +##### Access the current identity in the mapper + +When `update_identity_on_login` is set to `automatic`, the data mapper receives the current identity as an additional variable +`std.extVar('identity')`. This lets you write conditional logic — for example, preserving existing trait values or merging data +selectively. The `identity` variable contains the current `traits`, `metadata_public`, and `metadata_admin`. + +```jsonnet +local claims = std.extVar('claims'); +local identity = std.extVar('identity'); + +// Keep the display name if the user has set one, otherwise use the value from the IdP (if any). +local displayName = std.get(identity.traits, "display_name", std.get(claims.raw_claims, "displayName", "")); + +{ + identity: { + traits: { + email: claims.email, + [if displayName != "" then "display_name" else null]: displayName, + // Always update groups from the IdP. + [if std.objectHas(claims, "raw_claims") && std.objectHas(claims.raw_claims, "groups") then "groups" else null]: + claims.raw_claims.groups, + }, + }, +} +``` + +##### Behavior details + +- Metadata preservation. When the mapper omits `metadata_public` or `metadata_admin` from its output, existing values are + preserved. When the mapper explicitly outputs `{}`, the field is cleared. +- Schema validation. The updated identity is validated against the identity schema before it is persisted. If the mapper produces + invalid traits, the login fails with a validation error. +- No credential changes. Credentials and verified addresses are never modified by this feature. + #### Signing certificate expiry details The SAML connection includes a `valid_to` attribute, which is an array of expiry dates for the signing certificates associated From 047c5e84161484ffc97cc2d9a92b15dc3e8330d7 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 7 Jul 2026 10:00:55 -0400 Subject: [PATCH 2/2] docs: apply review copy-edits for SAML update identity on login Co-Authored-By: Claude Opus 4.8 --- docs/kratos/organizations/organizations.mdx | 34 +++++++++++---------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/kratos/organizations/organizations.mdx b/docs/kratos/organizations/organizations.mdx index 2cd5388f44..ffeb5cca99 100644 --- a/docs/kratos/organizations/organizations.mdx +++ b/docs/kratos/organizations/organizations.mdx @@ -435,14 +435,15 @@ local claims = std.extVar('claims'); #### Update identity on login -By default, the data mapper runs only when an identity first signs in through the SAML connection. If you want to keep identity -data in sync with the Identity Provider (IdP), set `update_identity_on_login` to `automatic` on the connection. This re-runs the -connection's Jsonnet data mapper on every SAML login and updates the identity's traits and metadata when they change. +By default, Ory runs the data mapper only the first time a user signs in through a SAML connection. To keep identity data in sync +with the SAML identity provider (IdP), set `update_identity_on_login` to `automatic` on the connection. With this setting, Ory +re-runs the connection's Jsonnet data mapper on every SAML login and updates the identity's traits and metadata whenever they +change. -This is useful when the IdP is the source of truth for user attributes such as group memberships, roles, or profile information -that can change over time. +Use automatic when the SAML IdP is the source of truth for attributes that change over time, such as group memberships, roles, or +profile information. -The default is `never`, so existing SAML connections keep their current behavior until you opt in. +The default is `never`. Existing SAML connections keep their current behavior until you opt in. ```mdx-code-block @@ -458,8 +459,8 @@ The default is `never`, so existing SAML connections keep their current behavior ``` -Replace the field on the connection you want to update. Adjust the provider index (`0` below) to match the position of your -connection in the `providers` array. +To enable it, set `update_identity_on_login` on the connection you want to update. Change the provider index (0 in the example +below) to match your connection's position in the providers array. ```shell curl -X PATCH --location "https://api.console.ory.com/projects/$PROJECT_ID" \ @@ -482,9 +483,10 @@ curl -X PATCH --location "https://api.console.ory.com/projects/$PROJECT_ID" \ ##### Access the current identity in the mapper -When `update_identity_on_login` is set to `automatic`, the data mapper receives the current identity as an additional variable -`std.extVar('identity')`. This lets you write conditional logic — for example, preserving existing trait values or merging data -selectively. The `identity` variable contains the current `traits`, `metadata_public`, and `metadata_admin`. +When you set `update_identity_on_login` to automatic, Ory passes the current identity to the data mapper as an additional variable +`std.extVar('identity')`. Use it to write conditional logic — for example, to preserve trait values a user has already set, or to +merge SAML IdP data selectively. The `identity` variable holds the identity's current `traits`, `metadata_public`, and +`metadata_admin`. ```jsonnet local claims = std.extVar('claims'); @@ -508,11 +510,11 @@ local displayName = std.get(identity.traits, "display_name", std.get(claims.raw_ ##### Behavior details -- Metadata preservation. When the mapper omits `metadata_public` or `metadata_admin` from its output, existing values are - preserved. When the mapper explicitly outputs `{}`, the field is cleared. -- Schema validation. The updated identity is validated against the identity schema before it is persisted. If the mapper produces - invalid traits, the login fails with a validation error. -- No credential changes. Credentials and verified addresses are never modified by this feature. +- Metadata preservation. When the mapper omits `metadata_public` or `metadata_admin` from its output, Ory preserves the existing + values. When the mapper explicitly outputs `{}`, the field is cleared. +- Schema validation. Before Ory persists the identity, it validates the update against the identity schema. If the mapper produces + invalid traits, Ory fails the login with a validation error. +- No credential changes. This feature never modifies credentials or verified addresses. #### Signing certificate expiry details