Claims mapping script
This sample script automatically maps claims from an external login provider to user profile properties, such as assigning roles during user authentication.
External login providers send information about logged-in users as claims, which vary depending on the provider. In this example, Google
is used as the login provider. Google
provides two claims: givenname
and surname
. The script assumes the M.UserProfile
entity definition includes FirstName
and LastName
properties and maps the givenname
and surname
claims to those properties.
-
Configure the schema editor to include the required properties that aren't included by default, such as
FirstName
andLastName
. -
Ensure the external login provider is integrated with Content Hub and that it provides claims for mapping.
Script
using System.Linq;
using System.Security.Claims;
if (Context.ExternalUserInfo?.Claims == null) return;
var firstName = Context.ExternalUserInfo.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
var lastName = Context.ExternalUserInfo.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
if (string.IsNullOrEmpty(firstName) && string.IsNullOrEmpty(lastName)) return; // No first or lastname claims found, nothing to do.
var userToUserProfile = await Context.User.GetRelationAsync<IParentToOneChildRelation>("UserToUserProfile");
if (!userToUserProfile.Child.HasValue) throw new InvalidOperationException("The logged on user has no user-profile.");
var profile = await MClient.Entities.GetAsync(userToUserProfile.Child.Value);
if (profile == null) throw new InvalidOperationException("The logged on user has no user-profile.");
if (!string.IsNullOrEmpty(firstName))
{
profile.SetPropertyValue("FirstName", firstName);
}
if (!string.IsNullOrEmpty(lastName))
{
profile.SetPropertyValue("LastName", lastName);
}
await MClient.Entities.SaveAsync(profile);
Script explanation
First, the script declares the libraries to be used during run time.
using System.Linq;
using System.Security.Claims;
Users can log in using either basic authentication (with a username and password) or using an external login provider. If the user has logged in using basic authentication, Context.ExternalUserInfo
will be null
, meaning there are no claims to map, so the script exits.
if (Context.ExternalUserInfo?.Claims == null) return;
If the user is logged in using an external provider, the script extracts the required values from the provided claims. These claims are defined as constants on the ClaimTypes
class.
var firstName = Context.ExternalUserInfo.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
var lastName = Context.ExternalUserInfo.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
If no givenname
or surname
claims are provided, there is nothing to map, so the script exits.
if (string.IsNullOrEmpty(firstName) && string.IsNullOrEmpty(lastName)) return;
The logged-in user's profile must be loaded, as specified in Context.User
. This profile is linked to the user through the UserToUserProfile
relation, and every user is expected to have an associated profile. If the user's profile is not found, the script exits.
var userToUserProfile = await Context.User.GetRelationAsync<IParentToOneChildRelation>("UserToUserProfile");
if (!userToUserProfile.Child.HasValue) throw new InvalidOperationException("The logged on user has no user-profile.");
var profile = await MClient.Entities.GetAsync(userToUserProfile.Child.Value);
if (profile == null) throw new InvalidOperationException("The logged on user has no user-profile.");
Next, the script populates the FirstName
and LastName
properties of the profile entity. If one of the claims has not been provided, it is skipped.
if (!string.IsNullOrEmpty(firstName))
{
profile.SetPropertyValue("FirstName", firstName);
}
if (!string.IsNullOrEmpty(lastName))
{
profile.SetPropertyValue("LastName", lastName);
}
Finally, the script stores the supplied user profile changes in the database.
await MClient.Entities.SaveAsync(profile);
Setup
-
Create, publish, and enable a User sign-in script.