Solutions
ForgeRock Identity Platform
ForgeRock Identity Cloud

First name and last name get blanked out when signing in to Identity Cloud or AM 7.x using Apple social sign-on

Last updated May 11, 2022

The purpose of this article is to provide assistance if a user's first name and last name get blanked out when signing in to ForgeRock Identity Cloud or AM with Apple® social single sign-on (SSO).


Symptoms

When a user signs in to Identity Cloud or AM using Apple social single sign-on (SSO), the First Name and Last Name details get blanked out. This occurs when the user has previously signed in with Apple and the social authentication journey includes a Patch Object node as part of the progressive profiling of user details. 

Recent Changes

OpenID Connect (OIDC) Social SSO with Apple has been implemented. See Apple SSO integration with Identity Cloud for social authentication/registration and Configure Social Identity Providers for further information.

A social authentication journey has been configured that includes the Patch Object node for progressive profiling.

Causes

Apple does not conform to the usual standards for UserInfo when acting as an OIDC SSO provider. It only returns the user information the first time the user consents to share their information and does not return this information during the subsequent sign-ins with Apple. See Authenticating Users with Sign in with Apple for further information.

In a typical authentication journey that is configured to use more than one social provider, each social provider (other than Apple) returns the user information on each sign-in. Typically in a journey that includes progressive profiling, a Patch Object node is responsible for continually updating the user profile data each time a user logs in. When a user chooses to sign in with Apple, this may result in the removal of their first name and last name when the user logs in after the first time.

Solution

The issue can be resolved by doing the following:

  1. AM only: Update the Normalized Profile to Managed User script so that it sets a flag when the givenName and familyName are not available.

This step does not apply to Identity Cloud since the updated Normalized Profile to Managed User script is included in the Identity Cloud deployment.

  1. Add a Scripted Decision node to your social authentication journey. The purpose of this node is to skip patching the user's details when givenName and familyName are missing.

Update the Normalized Profile to Managed User script (AM only)

You will need to update the Normalized Profile to Managed User script to set a flag when the givenName and FamiliyName are not available. 

AM console

  1. Go to Realms > [Realm Name] > Scripts and select the Normalized Profile to Managed User script.
  2. Add the following code snippet to the script, as appropriate:
  • JavaScript // if the givenName and familyName is null or empty // then add a boolean flag to the shared state to indicate names are not present // this could be used elsewhere // for eg. this could be used in a scripted decision node to by-pass patching // the user object with blank values when givenName and familyName is not present var noGivenName = normalizedProfile.get('givenName').isNull() || normalizedProfile.get('givenName').asString().trim().length === 0 var noFamilyName = normalizedProfile.get('familyName').isNull() || normalizedProfile.get('familyName').asString().trim().length === 0 sharedState.put('nameEmptyOrNull', noGivenName && noFamilyName)

The updated script will look like this (with initial comments removed for readability):(function () {    var frJava = JavaImporter(         org.forgerock.json.JsonValue     );     var managedUserData = frJava.JsonValue.json(frJava.JsonValue.object());     managedUserData.put('givenName', normalizedProfile.get('givenName'));     managedUserData.put('sn', normalizedProfile.get('familyName'));     managedUserData.put('mail', normalizedProfile.get('email'));     managedUserData.put('userName', normalizedProfile.get('username'));     if (normalizedProfile.get('postalAddress').isNotNull()) {         managedUserData.put('postalAddress', normalizedProfile.get('postalAddress'));     }     if (normalizedProfile.get('addressLocality').isNotNull()) {         managedUserData.put('city', normalizedProfile.get('addressLocality'));     }     if (normalizedProfile.get('addressRegion').isNotNull()) {         managedUserData.put('stateProvince', normalizedProfile.get('addressRegion'));     }     if (normalizedProfile.get('postalCode').isNotNull()) {         managedUserData.put('postalCode', normalizedProfile.get('postalCode'));     }     if (normalizedProfile.get('country').isNotNull()) {         managedUserData.put('country', normalizedProfile.get('country'));     }     if (normalizedProfile.get('phone').isNotNull()) {         managedUserData.put('telephoneNumber', normalizedProfile.get('phone'));     }     // if the givenName and familyName is null or empty     // then add a boolean flag to the shared state to indicate names are not present     // this could be used elsewhere     // for eg. this could be used in a scripted decision node to by-pass patching     // the user object with blank values when givenName  and familyName is not present      var noGivenName = normalizedProfile.get('givenName').isNull()                                       || normalizedProfile.get('givenName').asString().trim().length === 0      var noFamilyName = normalizedProfile.get('familyName').isNull()                                        || normalizedProfile.get('familyName').asString().trim().length === 0      sharedState.put('nameEmptyOrNull', noGivenName && noFamilyName)     return managedUserData; }());

  • Groovy // if the givenName and familyName is null or empty // then add a boolean flag to the shared state to indicate names are not present // this could be used elsewhere // for eg. this could be used in a scripted decision node to by-pass patching // the user object with blank values when givenName and familyName is not present boolean noGivenName = normalizedProfile.givenName.isNull() || (!normalizedProfile.givenName.asString()?.trim()) boolean noFamilyName = normalizedProfile.familyName.isNull() || (!normalizedProfile.familyName.asString()?.trim()) sharedState.put("nameEmptyOrNull", noGivenName && noFamilyName)

The updated script will look like this (with initial comments removed for readability): import static org.forgerock.json.JsonValue.field import static org.forgerock.json.JsonValue.json import static org.forgerock.json.JsonValue.object import org.forgerock.json.JsonValue JsonValue managedUser = json(object(        field("givenName", normalizedProfile.givenName),         field("sn", normalizedProfile.familyName),         field("mail", normalizedProfile.email),         field("userName", normalizedProfile.username))) if (normalizedProfile.postalAddress.isNotNull()) managedUser.put("postalAddress", normalizedProfile.postalAddress) if (normalizedProfile.addressLocality.isNotNull()) managedUser.put("city", normalizedProfile.addressLocality) if (normalizedProfile.addressRegion.isNotNull()) managedUser.put("stateProvince", normalizedProfile.addressRegion) if (normalizedProfile.postalCode.isNotNull()) managedUser.put("postalCode", normalizedProfile.postalCode) if (normalizedProfile.country.isNotNull()) managedUser.put("country", normalizedProfile.country) if (normalizedProfile.phone.isNotNull()) managedUser.put("telephoneNumber", normalizedProfile.phone) // if the givenName and familyName is null or empty // then add a boolean flag to the shared state to indicate names are not present // this could be used elsewhere // for eg. this could be used in a scripted decision node to by-pass patching // the user object with blank values when givenName  and familyName is not present boolean noGivenName = normalizedProfile.givenName.isNull() || (!normalizedProfile.givenName.asString()?.trim()) boolean noFamilyName = normalizedProfile.familyName.isNull() || (!normalizedProfile.familyName.asString()?.trim()) sharedState.put("nameEmptyOrNull", noGivenName && noFamilyName) return managedUser

  1. Click Save.

Add a Scripted Decision node to your authentication journey

You will need to add a Scripted Decision node to your social authentication journey with a script that uses a flag to skip the patching when givenName and familiyName are missing. This node should be placed directly before the Patch Object node in your social authentication progressive profile journey.

Create the decision node script

Identity Cloud admin UI:

  1. Go to Scripts > Auth Scripts.
  2. Click New Script.
  3. Select Journey Decision Node and click Next.
  4. Enter a name for the script and enter the Javascript script, similar to this example: if (sharedState.get('nameEmptyOrNull')) {  outcome = 'true' } else {   outcome = 'false' }
  5. Click Save and Close.

AM console:

  1. Go to Realms > [Realm Name] > Scripts and click New Script.
  2. Enter a name for the script and select Decision node script for authentication trees as the script type.
  3. Click Create.
  4. Enter the script details, similar to this example:
    • Javascript if (sharedState.get('nameEmptyOrNull')) {  outcome = 'true' } else {   outcome = 'false' }
    • Groovy if (sharedState.get("nameEmptyOrNull").asBoolean()) {  outcome = "true" } else {   outcome = "false" }
  5. Click Save Changes.

Add a scripted decision node to the social authentication journey

  1. Select the social authentication journey you wish to update:
    • Identity Cloud admin UI: Go to Journeys > [Journey Name]
    • AM console: Go to: Realms > [Realm Name] > Authentication > Trees > [Tree Name]
  2. Add a Scripted Decision node directly before the Patch Object node. In the node details:
    • Enter a suitable name for the node, for example, Skip Patching?.
    • Select the script you created in the previous steps.
    • Set the Outcomes as true and false.
  3. Click Save Changes.

An example journey that includes the Skip Patching? node may look similar to this:

See Also

Apple SSO integration with Identity Cloud for social authentication/registration

Configure Social Identity Providers

How do I create end user journeys for social registration and login in Identity Cloud?


Copyright and Trademarks Copyright © 2022 ForgeRock, all rights reserved.