Profile from Apple is not fully normalized

Hello,

I’m using Apple social connection to login. I can see the user created. The user has field “last_name”, but no field “family_name”. Isn’t the field “family_name” mandatory on normalized profile?
See the screen shot attached

Another example, see screenshot attached. Apple sends “first_name” and “last_name”, but profile has no “given_name” nor “family_name”

I believe (haven’t checked myself), the claims first_name and last_name come like this from Apple, despite family_name and _given_name` being the OIDC standard claims.

If you need to map this though, you can do it within a Rule (tbh - I don’t know why it’s not automatically mapped by the Apple ID social connection by default due to normalization).
So, as a workaround, this rule should work:

function (user, context, callback) {

  // you might want to add a check to only run this 
  // if `user.family_name` and `user.given_name` is actually missing
  if (context.connectionStrategy === "apple")  { 

    var ManagementClient = require('auth0@2.6.0').ManagementClient;
    var management = new ManagementClient({
        token: auth0.accessToken,
        domain: auth0.domain
    });
        
     // persist in user store
    management.updateUser({id: user.user_id}, 
        {family_name: user.last_name, given_name: user.first_name})
    .then(function(u){    
      callback(null, u, context);
    })
    .catch(function(err){
      callback(err);
    });     
  } else { // if not apple
    callback(null, user, context);
  }

}

I’ve tried mathiasconradt’s recommendation but unfortunately it doesn’t work me cause from Auth0 forbid to update family_name, given_name fields for apple connection user without disabling “Sync user profile attributes at each login” option and it gave me an error:

The following user attributes cannot be updated: family_name, given_name. The connection (apple) must either be a database connection (using the Auth0 store), a passwordless connection (email or sms) or has disabled 'Sync user profile attributes at each login'. For more information, see Configure Identity Provider Connection for User Profile Updates

So, I’ve stored last_name and first_name into user_metadata field:

function (user, context, callback) {

  // you might want to add a check to only run this 
  // if `user.family_name` and `user.given_name` is actually missing
  if (context.connectionStrategy === "apple")  { 

    var ManagementClient = require('auth0@2.32.0').ManagementClient;
    var management = new ManagementClient({
        token: auth0.accessToken,
        domain: auth0.domain
    });
        
     // persist in user store
    management.updateUser({id: user.user_id}, 
        {user_metadata: { apple_family_name: user.last_name, apple_given_name: user.first_name }})
    .then(function(u){    
      callback(null, u, context);
    })
    .catch(function(err){
      callback(err);
    });     
  } else { // if not apple
    callback(null, user, context);
  }

}

and reading with fallback in server (in Ruby):

user_profile = auth0_client.user(
  auth0_subject,
  fields: "family_name,given_name,user_metadata"
)
family_name = user_profile["family_name"] || user_profile.dig("user_metadata", "apple_family_name")
given_name = user_profile["given_name"] || user_profile.dig("user_metadata", "apple_given_name")

A simpler solution that doesn’t involve using the Management API would be:

function(user, context, callback) {
  if (context.connectionStrategy === "apple")  { 
    user.family_name = user.family_name || user.last_name;
    user.given_name = user.given_name || first_name;
  }
  callback(null, user, context);
}

This won’t cause any permanent changes in the user profile (it’s just a transient change for the ongoing authentication flow), but it affects the outgoing token being generated by Auth0 (be it an ID Token or a SAML token).
By not using the Management API v2 on every login you ensure better response times, and you stay away from any rate limiting (the Management API v2 has much lower rate limits than the Authentication API, so it’s not a good idea to have a rule that calls the Management API v2 every single time the rule runs).

1 Like

Thanks for helping on this one Nico!

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.