Get a first look at what's coming. The Developer Passport Australia Release Preview kicks off March 12. Dive in! 

Syncing ServiceNow User Profile Pictures from Azure using REST API

tharun24
Tera Contributor

Introduction

In many organizations, user profile pictures are stored in Microsoft Azure Active Directory (AAD). However, these profile images are not automatically synchronized with ServiceNow user records.

This article explains how to implement a custom integration that synchronizes user profile pictures from Azure to ServiceNow using the following components:

  • REST Message to fetch images from Azure
  • Script Include to process the response and update user avatars
  • Live Profile table (live_profile) to store the avatar reference
  • Scheduled Job to run the synchronization periodically

This solution ensures that ServiceNow user avatars stay consistent with Azure profile pictures.


Understanding How Avatars Work in ServiceNow

In ServiceNow, user avatars are not stored directly on the sys_user record. Instead, the avatar image is retrieved through the following structure:

sys_user
   ↓
live_profile (Avatar metadata)
   ↓
sys_attachment (Actual image file)

 

The live_profile.photo field stores the sys_id of the attachment containing the user's avatar.

Many interfaces such as:

  • Employee Center
  • Service Portal
  • Workspace

retrieve avatars using the internal API:

GlideAvatarFinder.getAvatarID(user_sys_id)

Therefore, updating the live_profile.photo field ensures that the avatar is displayed correctly across the platform.


Solution Architecture

The integration consists of the following components:

Scheduled Job
     ↓
Script Include
     ↓
REST Message → Azure Graph API
     ↓
Save Image as Attachment
     ↓
Update live_profile.photo

 

The process works as follows:

  1. Scheduled job queries active users.
  2. Script Include calls Azure API to retrieve profile pictures.
  3. The image response is saved as an attachment.
  4. The attachment sys_id is stored in the live_profile.photo field.


Step 1: Configure Azure and ServiceNow for OAuth Authentication

To fetch profile pictures from Azure, ServiceNow must authenticate with Microsoft Graph API using OAuth 2.0.

This requires configuration in both Azure and ServiceNow.

The setup consists of the following steps:

  1. Create an App Registration in Azure
  2. Assign required Microsoft Graph permissions
  3. Configure Application Registry in ServiceNow
  4. Create an OAuth Profile
  5. Create the REST Message


1. Create App Registration in Azure

First, create an Application Registration in Microsoft Azure that ServiceNow will use to authenticate with Microsoft Graph.

Steps

  1. Go to the Azure Portal: https://portal.azure.com
  1. Navigate to: Microsoft Entra ID → App registrations
  1. Click: New Registration

Provide the following details

Field

Example Value

Name

ServiceNow Avatar Sync

Supported account types

Accounts in this organizational directory only

Redirect URI

Leave blank

 

Example configuration:

Name: ServiceNow Avatar Sync
Supported Account Type: Single Tenant
Redirect URI: Not required

Click Register.


2. Copy Application Details

After the application is created, copy the following values:

Azure Field

Example

Used In

Application (client) ID

7a2d21c4-1c3f-4d01-b6f0-23dfc0d1f1e2

ServiceNow Application Registry

Directory (tenant) ID

8b3f8f2a-9e1d-45c4-b3c1-3a4e6e44f222

OAuth Endpoint

Client Secret

Generated later

ServiceNow


3. Create Client Secret in Azure

Navigate to: Certificates & secrets

Click: New client secret

Provide the following:

Field

Example

Description

ServiceNow OAuth Secret

Expiry

24 Months

Click Add.

Copy the generated Client Secret value.

 

Example:

Client Secret: x8L~kP9...abc

⚠️Important: This value is visible only once.


4. Add Microsoft Graph API Permission

Navigate to: API permissions

Click: Add permission

Select: Microsoft Graph

Choose: Application permissions

Add the following permission:

User.Read.All

Description:

Allows the application to read all user profiles without a signed-in user.

After adding the permission, click: Grant Admin Consent


5. Configure OAuth Endpoint

The OAuth Token endpoint will be:

https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token

Example:

https://login.microsoftonline.com/8b3f8f2a-9e1d-45c4-b3c1-3a4e6e44f222/oauth2/v2.0/token


6. Create Application Registry in ServiceNow

Navigate to: System OAuth → Application Registry

Click: New

Select: Connect to a third party OAuth Provider

 

Provide the following values

Field

Example Value

Name

Azure OAuth Provider

Client ID

7a2d21c4-1c3f-4d01-b6f0-23dfc0d1f1e2

Client Secret

x8L~kP9...abc

Token URL

https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token

Default Grant Type

Client Credentials

Scope

https://graph.microsoft.com/.default

Example configuration:

Client ID: 7a2d21c4-1c3f-4d01-b6f0-23dfc0d1f1e2
Client Secret: *********
Token URL: https://login.microsoftonline.com/8b3f8f2a-9e1d-45c4-b3c1-3a4e6e44f222/oauth2/v2.0/token
Scope:https://graph.microsoft.com/.default

Save the record.


7. Create OAuth Profile

Navigate to: System OAuth → OAuth Profiles

Click New.

Provide the following values:

Field

Example

Name

Azure OAuth Profile

OAuth Provider

Azure OAuth Provider

Grant Type

Client Credentials

Save the record.


8. Create REST Message

Navigate to: System Web Services → REST Message

Create a new REST Message.

Field

Value

Name

Get User Details

Endpoint

https://graph.microsoft.com/v1.0

Example description:

This REST message retrieves user profile pictures from Azure using Microsoft Graph API.


9. Configure Authentication

In the REST Message: Authentication Type: OAuth 2.0

OAuth Profile: Azure OAuth Profile


10. Create REST Method

Inside the REST Message create a new method.

Field

Value

Name

Get Profile Pic

HTTP Method

GET

Endpoint: https://graph.microsoft.com/v1.0/users/${email}/photo/$value

This endpoint returns the binary image of the user’s profile picture.

Example request: GET https://graph.microsoft.com/v1.0/users/john.doe@company.com/photo/$value

Response: Binary JPEG Image


11. Test the REST Message

Provide a test email: naga.b@company.com

If successful, the response will return: HTTP 200
Binary image

If the user has no profile picture:

HTTP 404


Step 2: Create Script Include for Avatar Synchronization

Create a Script Include that will:

  • Query active users
  • Call the REST API
  • Save the image as an attachment
  • Update the avatar in live_profile
var GetUserProfile = Class.create();
GetUserProfile.prototype = {
    initialize: function() {},

    getUserPicture: function() {
        // Counters and logs for reporting
        var updatedUsersLog = [];
        var noPhotoUsersLog = [];
        var errorUsersLog = [];

        // Query all active users that have SSO source
        var userRecord = new GlideRecord('sys_user');
        userRecord.addEncodedQuery('active=true^sso_sourceISNOTEMPTY^emailISNOTEMPTY');
        userRecord.query();

        while (userRecord.next()) {
            var pic = userRecord.sys_id + '_photo.jpg';
            try {

                // Store reference to the user's Live Profile record
                var liveProfileRecord;

                // REST message to fetch photo from Azure
                var restMessage = new sn_ws.RESTMessageV2('Get User Details', 'Get Profile Pic');
                restMessage.setStringParameterNoEscape('email', userRecord.email);


                // STEP 1: Retrieve or create the live_profile record for this user

                var avatarGR = new GlideRecord('live_profile');
                avatarGR.addQuery('type', 'user'); // Avatar type must be 'user'
                avatarGR.addQuery('document', userRecord.sys_id); // Link to sys_user record
                avatarGR.query();

                if (avatarGR.next()) {
                    liveProfileRecord = avatarGR;
                } else {
                    // If no live_profile exists create one
                    avatarGR.initialize();
                    avatarGR.type = 'user';
                    avatarGR.name = userRecord.name;
                    avatarGR.table = 'sys_user';
                    avatarGR.document = userRecord.sys_id;
                    avatarGR.insert();
                    liveProfileRecord = avatarGR;
                }

                // STEP 2: Save Azure image response as attachment
                restMessage.saveResponseBodyAsAttachment(
                    'live_profile',
                    liveProfileRecord.sys_id,
                    pic
                );

                var response = restMessage.execute();
                var httpStatus = response.getStatusCode();

                // STEP 3: Process REST response

                if (httpStatus == 200) {

                    var newAttachmentSysId = response.getResponseAttachmentSysid();

                    // STEP 4: Delete existing avatar attachment if it exists
                    if (liveProfileRecord.photo) {

                        var oldAttachment = new GlideRecord('sys_attachment');
                        if (oldAttachment.get(liveProfileRecord.photo)) {
                            oldAttachment.deleteRecord();
                        }
                    }

                    // Update avatar reference
                    liveProfileRecord.photo = newAttachmentSysId;
                    liveProfileRecord.update();

                    // Optional: also update sys_user.photo
                    userRecord.photo = newAttachmentSysId;
                    userRecord.update();

                    updatedUsersLog.push("\n " + userRecord.email);

                } else if (httpStatus == 404) {
                    noPhotoUsersLog.push("\n " + userRecord.email);

                } else {
                    errorUsersLog.push(userRecord.email + " | Response: " + response.getBody());
                }

            } catch (exception) {
                errorUsersLog.push(userRecord.email +
                    " | Error: " + exception.message);

            }
        }
        // Final result summary

        var summaryMessage =
            "<b>Azure Avatar Sync Summary</b><br>" +

            "<b>Users Updated:</b> " + updatedUsersLog.length + "<br>" +
            updatedUsersLog.join("<br>") + "<br><br>" +

            "<b>Users Without Azure Photo:</b> " + noPhotoUsersLog.length + "<br>" +
            noPhotoUsersLog.join("<br>") + "<br><br>" +

            "<b>Errors:</b> " + errorUsersLog.length + "<br>" +
            errorUsersLog.join("<br>") + "<br>" +
            "-------------------------";
        gs.info(summaryMessage);
    },
    type: 'GetUserProfile'
};


Step 3: Create a Scheduled Job

Navigate to: System Definition → Scheduled Jobs

Create a new job.

Field

Value

Name

Azure User Avatar Sync

Run

Monthly

Script:

var sync = new GetUserProfile();

var result = sync.getUserPicture();

This job will automatically synchronize user avatars.


Performance Considerations

When syncing avatars for many users:

Avoid Duplicate Attachments

Delete existing avatar attachments before saving new ones.

Skip Users Without Emails

Azure Graph requires an email identifier.

Batch Processing

For large environments process users in batches.

Handle Missing Photos

If Azure returns 404, skip the update.


Example Output

Example log output from the synchronization job:

Azure Avatar Sync Summary

nag.t@company.com - Avatar Updated
pra.now@company.com - Avatar Updated
zoho@company.com - No Azure Photo Found


Conclusion

ServiceNow can now securely fetch user profile images from Azure using OAuth 2.0 authentication and Microsoft Graph API.

0 REPLIES 0