Claims mapping example

This is an example of a User sign-in script that reads the information provided by an external login provider and stores them on the logged on user's profile.

Use case

External login providers provide information about logged on users in the form of claims. The claims provided are highly dependent on which login-provider has been used.

This example has been developed using Google as login provider. Google provides us with 2 claims: givenname and surname. We assume that the M.UserProfile entity-definition contains 2 properties: FirstName and LastName. The script maps the values of the givenname and surname claims to these properties.

Note

The "FirstName" and "LastName" properties do not exist out of the box. They have been added using the schema-editor.

Script

RequestResponsec#
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

  1. Include the libraries to be used in the script.

    RequestResponsec#
    using System.Linq;
    using System.Security.Claims;
  2. Users can log in using either basic-authentication (username and password) or using an external login provider. If the user's been logged on using basic-authentication, Context.ExternalUserInfo will be null. In that case, there are no claims to map, so simply return from the script.

    RequestResponseshell
    if (Context.ExternalUserInfo?.Claims == null) return;
  3. Extract the values from the provided claims. The claims are defined as constants on the "ClaimTypes" class.

    RequestResponseshell
    var firstName = Context.ExternalUserInfo.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
    var lastName = Context.ExternalUserInfo.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
  4. If no givenname or surname claims have been provided, there is nothing to map, so return from the script.

    RequestResponseshell
    if (string.IsNullOrEmpty(firstName) && string.IsNullOrEmpty(lastName)) return;
  5. The user-profile related to the logged on user needs to be loaded. The logged on user is specified in Context.User. The user-profile is associated with the User using the "UserToUserProfile" relation. It is expected for every user in the system to have an associated profile. If the user-profile cannot be found, something is wrong and we throw an exception.

    RequestResponseshell
    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.");
  6. Populate the "FirstName" and "LastName" properties of the profile entity. If one of the claims has not been provided, simply skip it.

    RequestResponseshell
    if (!string.IsNullOrEmpty(firstName))
    {
        profile.SetPropertyValue("FirstName", firstName);
    }
    
    if (!string.IsNullOrEmpty(lastName))
    {
        profile.SetPropertyValue("LastName", lastName);
    }
  7. Store the changes made to the user-profile in the database.

    RequestResponseshell
    await MClient.Entities.SaveAsync(profile);

Setup

  • Create, publish and enable a User sign-in script.

Do you have some feedback for us?

If you have suggestions for improving this article,