Auto User Sync

 

Table Of Content

Overview - Auto User Sync

Introduced in the February 2024 release, Auto User Sync has been introduced to;

  • Simplify the creation and management of Users by allowing every aspect of them to be configured using a single payload of information

  • Integrate the payload of information with External Authentication flows, meaning the management and configuration of users can take place solely within those systems rather than having to be coordinated between those systems and the Dashboard

The basic premise is to provide a payload with all of the information required to define a user (e.g. their details, the roles they are assigned, the categories they have access to) either through the API or as a claim during External Authentication - and that user will be created or updated to match the information within the payload.

Even for a pre-existing user this payload synchronisation process is not additive. For example, a user that already has Categories assigned to them will no longer have access to them if the payload does not define them

 

Payload Methods

There are two methods to send payloads to the Dashboard:

  • Through the API - via the new POST endpoint /users/sync

  • As part of an External Authentication flow - using the new claim - whilst this is formatted as a URL this is merely to namespace the claims associated with the Dashboard, it is not an actual URL link:
    https://www.panintelligence.com/claims/userSyncPayload

 

Additionally, a new GET endpoint has been created that will return a payload representation of a pre-existing user (/users/syncPayload). The API and External Authentication parts of this feature are detailed separately below but feel free to use a combination of the approaches if that suits your configuration.

The Payload

Structure

The payload is a JSON array containing objects that define various aspects of a user's configuration split into the following sections:

  • User: An object containing key/value pairs that define the settings for that user (e.g. their email or preferred theme) and their User Restrictions (e.g. if they have editChart permission)

  • Variables: An array of objects each of which defines a variable to add to this user

  • Restrictions: An array of objects each of which defines a restriction to add to this user

  • User Roles: An array of roles to assign to the user

  • User Categories: An array of categories to assign to the user

  • Subscription: An array of Subscription that a user has access to for the purpose of Multi Tenancy/Organisations

An Example Payload

[ { "user": { "usercode": "EXAMPLE", "orgIdentifier": "Organisation One", "forenames": "Example", "surname": "User" "userTypeId": 1, "parentIdentifier": "Admin", "editUsers": true }, "variables": [ { "name": "PI_STYLES", "value": "piBerry", "isSecure": false } ], "restrictions": [ { "dataSourceItemIdentifier": "UK Sales", "columnIdentifier": "Department", "value": "Sales" } ], "userRoles": [ "Sales", "Marketing" ], "userCategories": [ "Category 1", "Category 2" ] }, { "subscription": { "usercode": "EXAMPLE", "orgIdentifier": "Organisation Two", "userTypeId": 1, "editUsers": true }, "userRoles": [ "Sales", "Development" ], "userCategories": [ "Category 3" ] } ]

 

The new GET endpoint detailed in the next section can be used to help you construct the payloads for your users. However, the exact details expected in the payload can be found on our SwaggerHub page for the API under the “users” section.

A Minimal Payload Demonstrating How To Achieve A Common Organisation Structure

The payload below is an example that combines this feature with the Organisations feature which may not be applicable to how you manage multi-tenancy. However, It still provides a stripped back example that you may find useful.

The common structure explored is that of wanting a user that is created under an Organisation that is a Child of the top-level ‘Dashboard’ Organisation that also has a subscription to the ‘Dashboard’ Organisation. This example assumes that:

  • ‘Child Organisation’ has been created

  • There is a parent user within that Organisation that the User that is about to be created is going to be a child of

  • All User Restrictions and fields other than those shown are their default values (see section below)

  • The User will be authenticating via username and password

[ { "user": { "usercode": "Child User", "parentIdentifier": "Parent User", "orgIdentifier": "Child Organisation", "clientPassword": "password", }, "variables": [], "restrictions": [], "userRoles": [], "userCategories": [] }, { "subscription": { "usercode": "Child User", "parentIdentifier": "ADMIN", "orgIdentifier": "Dashboard", "ownerOrgIdentifier": "Child Organisation" }, "variables": [], "restrictions": [], "userRoles": [], "userCategories": [] } ]

Note: Both the Parent and the Organisations use ‘identifier’ rather than ‘id’ and the usercode is the same for both ‘sections’ of the payload

Default Values

The SwaggerHub documentation also details the default values for all of the fields. If the payload does not include a field, its default value will be used. This makes the payloads simpler to create, smaller to send, and ensures that the addition of new fields in future releases won’t break your configuration.

Identifiers and IDs

If you look at the example above, you will notice that the Categories and Roles use the string values for those items even though they do have IDs associated with them within the Dashboard. On the other hand, “userTypeId” uses the ID rather than the value associated with this type. This difference is due to “userTypeId” being limited to known values rather than being generated by the Dashboard at the time of creation. Category and Role IDs may differ between different environments, the ID that represents a certain User Type (e.g. Admin, Designer) will not.

A crucial example of this to note is the parentIdentifier which is used in place of parentId. This is required for the POST request and should correspond to the usercode of the user you want to be assigned as the parent of this one.

Generating A Payload For A Pre-Existing User

A new API endpoint has been created that will GET the payload that defines a pre-existing user. The endpoint can be hit by making a GET request to /users/syncPayload and requires the user's usercode to be provided as a query parameter - this usercode is case-sensitive. For example, a GET request to retrieve the payload for a user with the usercode “EXAMPLE“ would look something like this:

https://server:port/pi/api/v2/users/syncPayload?usercode=EXAMPLE

This endpoint can serve as a convenient way to initially generate payloads for the users you are planning to subsequently manage through Auto User Sync or, alternatively, be used to generate an example that you can then base your payloads off of without having to create users via the Dashboard.

Not all of the information within this Payload is required for the synchronisation. For example, there will be some IDs (e.g. userId) that are present purely for informational purposes but, due to being dynamically generated values, are ignored.

Submitting A Payload

Once you have your payloads ready to deploy you can use them to ‘Auto Sync’ users. There are two ways to do this:

Through The API

Send the payload as the body of a POST request to the /users/sync endpoint. The Dashboard will then process this request and attempt to synchronise (i.e. create/update) the user described by this payload. The user defined in the payload must be manageable by the user that is calling this endpoint.

Via External Authentication

How you add a custom claim to a user will vary slightly depending upon your External Auth provider or setup. If you already manage your login with External Authentication, you should be able to leave that aspect untouched as it currently uses the Email Address of the user to identify who has been authenticated and this is fully compatible with Auto User Sync. Note, whilst the Email Address remains a valid identifier a usercode claim can be defined and will be used in preference to the email address should it exist. Whichever identifier you use also has to be present and matching within the payload or it will fail to validate.

It is likely that you are using your External Auth for more than just the Dashboard, that is why the custom claims that we have recognise are namespaced with our domain to avoid potential conflicts with other applications - they are the following:

  • Usercode: https://www.panintelligence.com/claims/usercode

  • User Sync Payload: https://www.panintelligence.com/claims/userSyncPayload

  • Email: https://www.panintelligence.com/claims/email - Self-managed JWT configurations only

Note: The Email Claim above is not processed as part of the login flow when using External Auth Identity providers. These providers populate their own email claims and those are used even if the custom claim is present. The Email claim will only work for self-managed JWT authentication configurations

Once the payload claim has been successfully set up for a user, every time they login the Dashboard will attempt to synchronise that user with the information contained in the payload. This happens as part of the pre-existing authentication flow meaning there is no extra configuration or prompts from the perspective of the authenticating user.

In keeping with the idea of managing users solely through External Auth, there is no setting in the Dashboard related to this feature; it is the presence of the 'userSyncPayload' claim that dictates whether or not synchronisation will be attempted. Do not set this claim if you do not want to use this feature as a malformed payload will block login.

The Synchronisation Process

Whether through directly calling the API endpoint or as part of the External Auth Login flow, if the Dashboard receives a payload it will attempt to parse that payload and create/update a user based upon the information it contains.

The payload represents the entirety of the configuration for that user. Even if a user already exists within the Dashboard and has been assigned certain roles, categories etc if these aren’t present within the payload that configuration will be lost. This is a synchronisation as opposed to a deletion followed by a creation - meaning that some Dashboard generated information about the user will be retained such as their User ID - but as a general rule thinking of it as a destructive process is the better approach.

What If The Synchronisation Fails?

If the synchronization fails then no changes will be made to that user. Any changes that have been made during the process will be rolled back and the user will remain configured as it was prior to the attempt.

In the case of the API, a failure will result in not only a status matching the cause but a detailed breakdown of which part of the process failed. This should help you find which part of the payload needs amending.

In the case of External Auth, the login attempt for that user will fail even if the user already exists and was successfully authenticated. This is to prevent the possibility of a user logging in with permissions or access that have since been removed.

Things To Be Considerate Of

  • IMPORTANT: When creating a new user via the Auto User Sync API, the Authenticating User must be the Super Admin account. This is something we will be adjusting in our March 23 release (pi#2341).

  • A failed External Auth attempt will result in a rather generic error message being displayed. Sending the payload through the API is a good way to identify is there is an issue with the payload as it returns far more explicit errors

  • If using the usercode claim to identify a user you can’t then update that usercode within the body of the payload - they must match. The same applies to the use of the email claim (whether using the Panintelligence claim or the External Auths standard email claim)

  • Users created/updated through External Auth will have ‘allowPasswordLogin’ set to false and ‘allowExternalLogin’ set to true regardless of their field values in the payload

  • Parent Categories have to be included in the userCategories array in order to grant access to a child category