Enable e-signature for Service Portal
You can configure e-signature in Service Portal to require re-authentication from approving users.
Before you begin
The com.snc.integration.esig.window system property is supported to enable SSO login in a new window.
Role required: admin
Procedure
-
Activate the Approvals with e-Signature [com.glide.e_signature_approvals] plugin.
-
Navigate to System Definition > e-Signature Registry.
-
Add any tables you want to require an e-signature for to the list.
Result
With e-signature enabled, approvers are required to provide a password to approve or reject any requests. Authentication with touch ID works in the mobile app. On the mobile web, approvers are still required to enter a password. For more information on configuring e-signature, see Approval with e-signature.
Parent Topic:Managing portal access
Enable SSO login in a new window
Open a new window for SSO authentication when using e-Signature for approvals.
Before you begin
Security Assertion Markup Language (SAML) login is only supported on the desktop Service Portal.
For additional information, see the e-signature SSO login KB article.
Role required: admin
Procedure
-
Enter the spEsignatureCustom script.
-
Enter
sys_ui_script.listin the Filter navigator. -
Select New, and create a new UI script.
-
On the UI Script form, enter
spEsignatureCustomin the API Name field. -
In the UI Type field, select Mobile/Service Portal.
-
Paste the spEsignatureCustom script in the Script field.
-
Select Submit.
-
-
Enter the spAuthCustom script.
-
In the same
sys_ui_script.listtable, create another new UI script by selecting New. -
On the UI Script form, enter
spAuthCustomin the API Name field. -
In the UI Type field, select Mobile/Service Portal.
-
Paste the spAuthCustom script in the Script field.
-
Select Submit.
-
-
Associate the UI scripts to the JS Include record.
-
Navigate to Service Portal > Portals.
-
Identify the Service Portal you want to apply the esignature support to and select the Theme.
-
In the related lists, select JS Includes.
-
Select New.
-
On the form, fill in the fields.
Field Description Display name Name for your JS Include. Enter spEsignatureCustomand associate the record with the spEsignatureCustom UI script you created, or enterspAuthCustomand associate the record with spAuthCustom you created.Source Source for your JS Include record. Select UI Script. UI script UI script source for your JS Include record. Select either spEsignatureCustom or spAuthCustom depending on the record you're creating. Application Application for your JS Include record. The default application is Global. Updated Field displaying when the record was last updated. Package Field that establishes the JS Include package. -
Select Submit.
-
Result
A new window opens when you use E-Signature for approvals.
spEsignatureCustom script
Paste the spEsignatureCustom script in the sys_ui_script.list script field.
angular.module('sn.$sp').provider('spEsignature', function() { 'use strict';
this.$get = function spEsignature($q, $http, $window, urlTools, xmlUtil) { var w = window; var esignOW; var windowWidth; var windowHeight; var redirectURL;
function isWindowChosen() { var postParams = { sysparm_scope: 'global', sysparm_processor: 'ESignatureAuthUtils', sysparm_name: 'isWindowChosen' }; return $http({ method: 'POST', url: '/xmlhttp.do', data: urlTools.encodeURIParameters(postParams), headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, transformResponse: function(response) { return xmlUtil.getDataFromXml(response); } }).then( function(response) { var data = response.data ? response.data[0] : {}; return data.answer === 'true' }, function(response) { // Handling failure case. switch (response.status) { default: case 404: return false; } }); }
function initiateEsignature() { var postParams = { sysparm_scope: 'global', sysparm_processor: 'ESignatureAuthUtils', sysparm_name: 'fetchAuthDetails' } return $http({ method: 'POST', url: '/xmlhttp.do', data: urlTools.encodeURIParameters(postParams), headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, transformResponse: function(response) { return xmlUtil.getDataFromXml(response, 'result'); } }).then( function(response) { var data = response.data ? response.data[0] : {}; process(data); }); }
function process(data) { var shouldLogoutFirst = data.logoutFirst === 'true'; w['windowHeight'] = data.popup_window_height; w['windowWidth'] = data.popup_window_width; w['redirectURL'] = data.loginURL; if (shouldLogoutFirst) openEsignatureWindow(data.logoutURL); else authenticate(); }
function openEsignatureWindow(url) { w['esignOW'] = window.open(url, 'esignatureAuthentication', 'height='+w['windowHeight']+',width='+w['windowWidth']+',top=100,left=100,toolbar=0,location=0,menubar=0'); }
w['authenticate'] = function(){ if(w['redirectURL']){ if(w['esignOW']) //when we signed out previously, a window is already opened. reuse it. w['esignOW'].location.href = w['redirectURL']; else openEsignatureWindow(w['redirectURL']); } };
w['evaluateRedirect'] = function(msg) { w['esignOW'].close(); if (msg == "saml2 login complete") { $window.onReauthenticationComplete(msg); } };
return { isWindowChosen: isWindowChosen, initiateEsignature: initiateEsignature };
};});spAuthCustom script
Paste the spAuthCustom script in the sys_ui_script.list script field.
angular.module('sn.$sp').factory('spAuthModal', function($q, spModal, i18n, $http, spAuthentication, glideUserSession, cabrillo, $cookies, $window, spUtil, $uibModal, spEsignature) { "use strict";
function _showAuthenticationModal(requestParams, username, userSysId) { var currentUser; var deferred = $q.defer(); glideUserSession.loadCurrentUser({reload: true}).then(function(user) { if (!user) { deferred.reject({ error: { status: 'ANONYMOUS', message: i18n.getMessage('Not logged in') } }); return; } currentUser = user; var serializedUser = { sysId: currentUser.userID, userName: currentUser.userName, firstName: currentUser.firstName, lastName: currentUser.lastName };
// hand off to native clients if (cabrillo.isNative()) { cabrillo.auth.reauthenticate(currentUser).then(function() { deferred.resolve(serializedUser); }, function(error) { if (error && error.status) { deferred.reject({ error: error }); } //TODO: Handle rejection a little more gracefully deferred.reject(); }); return; }
var loginMethod = currentUser.$private.loginMethod; if (!loginMethod) { // As we were unable to determine the login method via the HTTP session, trying to get glide_sso_id cookie which is set in case of multisso login var providerSysId = $cookies.get('glide_sso_id'); loginMethod = providerSysId ? 'multisso' : 'db'; }
if (loginMethod === 'saml' || loginMethod === 'oidc' || loginMethod === 'multisso') { spEsignature.isWindowChosen().then(function(result) { var modal; if (!spUtil.isMobile() && loginMethod !== 'oidc' && result === true) { // If enabled, Opening a new window for desktop saml login spEsignature.initiateEsignature(); } else { glideUserSession.getSsoReauthenticationUrl().then(function(url) { requestParams.externalLoginURL = url; openExternalAuthModal(requestParams).then(function(m) { modal = m; }); }); } $window.onReauthenticationComplete = function(result) { deferred.resolve(serializedUser); if (modal) modal.close(); }; }); } else { spModal.open({ title:i18n.getMessage("Approver authentication"), message:i18n.getMessage("Additional authentication is required, enter your usename and password to continue."), footerStyle: {border: 'none', 'padding-top': 0}, widget: 'simpleloginui', widgetInput: {}, shared: requestParams, onSubmit: function() { return onLoginModalSubmit(requestParams, username); } }).then(function(confirm) { if (confirm.label == i18n.getMessage("OK")) { deferred.resolve(serializedUser); } else { deferred.reject(); } }); } });
return deferred.promise; }
function onLoginModalSubmit(requestParams, username) { //(1) call login service to verify auth //(2) verify same user return $q(function(resolve, reject) { var errorMessage = null;
if(!requestParams.username || requestParams.username.trim() === "" || !requestParams.password || requestParams.password.trim() === "") { errorMessage = i18n.getMessage("User name or password invalid"); } else if(requestParams.username !== username) { errorMessage = i18n.getMessage("Attempted to authenticate as a different user"); }
if(!errorMessage || errorMessage === "") { spAuthentication.validateCreds(requestParams.username, requestParams.password).then(function(res) { resolve({status: res.success, errorMessage: res.message}); }); } else { resolve({status: !errorMessage || errorMessage === "", errorMessage: errorMessage}); } });
}
function openExternalAuthModal(requestParams) { var deferred = $q.defer();
var options = { title: i18n.getMessage("Approver authentication"), message: '', messageOnly: false, errorMessage: '', input: false, label: '', size: 'lg', value: '', required: false, footerStyle: {border: 'none', 'padding-top': 0}, values: false, onSubmit: null, widget: 'simpleloginui', widgetInput: {}, shared: requestParams, buttons: [{label: i18n.getMessage('Cancel'), cancel:true}] };
var widgetURL = spUtil.getWidgetURL(options.widget); $http.post(widgetURL, options.widgetInput).success(function(response) { options.widget = response.result; options.widget.options.shared = options.shared; var modal = $uibModal.open({ templateUrl:'sp-modal.html', controller: spModalCtrl, size: options.size, resolve: { options: function() { return options; } } });
deferred.resolve(modal); }); return deferred.promise; }
function spModalCtrl($scope, options) { $scope.options = options; $scope.form = {};
$scope.buttonClicked = function(button){ if (button.cancel) { $scope.$dismiss(); return; } } }
return { prompt: _showAuthenticationModal }}).decorator("spAuthModal", function($delegate) { return( $delegate );});---
title: Enable e-signature for Service Portal
description: You can configure e-signature in Service Portal to require re-authentication from approving users.Open a new window for SSO authentication when using e-Signature for approvals.Paste the spEsignatureCustom script in the sys\_ui\_script.list script field.Paste the spAuthCustom script in the sys\_ui\_script.list script field.
locale: en-US
canonical_url: https://www.servicenow.com/docs/r/platform-user-interface/service-portal/enable-esignature-sp.html
release: brazil
product: Service Portal
classification: service-portal
topic_type: task
last_updated: "2026-09-10"
reading_time_minutes: 5
breadcrumb: [Managing portal access, Configuring Service Portal, Service Portal, Configure UIs and portals, Configure user experiences]
---
# Enable e-signature for Service Portal
You can configure e-signature in Service Portal to require re-authentication from approving users.
## Before you begin
The **com.snc.integration.esig.window** system property is supported to enable SSO login in a new window.
Role required: admin
## Procedure
1. Activate the Approvals with e-Signature \[com.glide.e\_signature\_approvals\] plugin.
2. Navigate to **System Definition** > **e-Signature Registry**.
3. Add any tables you want to require an e-signature for to the list.
## Result
With e-signature enabled, approvers are required to provide a password to approve or reject any requests. Authentication with touch ID works in the mobile app. On the mobile web, approvers are still required to enter a password. For more information on configuring e-signature, see [Approval with e-signature](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/brazil/markdown/build-workflows/approval-with-e-signature.md).
**Parent Topic:**[Managing portal access](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/brazil/markdown/platform-user-interface/service-portal/portal-security.md)
## Enable SSO login in a new window
Open a new window for SSO authentication when using e-Signature for approvals.
### Before you begin
Security Assertion Markup Language \(SAML\) login is only supported on the desktop Service Portal.
For additional information, see the [e-signature SSO login KB article](https://support.servicenow.com/kb?id=kb_article_view&sys_kb_id=2dca1fe8db49a010190b1ea668961999).
Role required: admin
### Procedure
1. Enter the spEsignatureCustom script.
1. Enter `sys_ui_script.list` in the Filter navigator.
2. Select **New**, and create a new UI script.
3. On the UI Script form, enter `spEsignatureCustom` in the API Name field.
4. In the UI Type field, select **Mobile/Service Portal**.
5. Paste the [spEsignatureCustom script](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/brazil/markdown/platform-user-interface/service-portal/enable-esignature-sp.md) in the **Script** field.
6. Select **Submit**.
2. Enter the spAuthCustom script.
1. In the same `sys_ui_script.list` table, create another new UI script by selecting **New**.
2. On the UI Script form, enter `spAuthCustom` in the API Name field.
3. In the UI Type field, select **Mobile/Service Portal**.
4. Paste the [spAuthCustom script](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/brazil/markdown/platform-user-interface/service-portal/enable-esignature-sp.md) in the **Script** field.
5. Select **Submit**.
3. Associate the UI scripts to the JS Include record.
1. Navigate to **Service Portal** > **Portals**.
2. Identify the Service Portal you want to apply the esignature support to and select the Theme.
3. In the related lists, select **JS Includes**.
4. Select **New**.
5. On the form, fill in the fields.
|Field|Description|
|-----|-----------|
|Display name|Name for your JS Include. Enter `spEsignatureCustom` and associate the record with the spEsignatureCustom UI script you created, or enter `spAuthCustom` and associate the record with spAuthCustom you created.|
|Source|Source for your JS Include record. Select **UI Script**.|
|UI script|UI script source for your JS Include record. Select either spEsignatureCustom or spAuthCustom depending on the record you're creating.|
|Application|Application for your JS Include record. The default application is **Global**.|
|Updated|Field displaying when the record was last updated.|
|Package|Field that establishes the JS Include package.|
6. Select **Submit**.
### Result
A new window opens when you use E-Signature for approvals.
## spEsignatureCustom script
Paste the spEsignatureCustom script in the sys\_ui\_script.list script field.
```
angular.module('sn.$sp').provider('spEsignature', function() {
'use strict';
this.$get = function spEsignature($q, $http, $window, urlTools, xmlUtil) {
var w = window;
var esignOW;
var windowWidth;
var windowHeight;
var redirectURL;
function isWindowChosen() {
var postParams = {
sysparm_scope: 'global',
sysparm_processor: 'ESignatureAuthUtils',
sysparm_name: 'isWindowChosen'
};
return $http({
method: 'POST',
url: '/xmlhttp.do',
data: urlTools.encodeURIParameters(postParams),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
transformResponse: function(response) {
return xmlUtil.getDataFromXml(response);
}
}).then(
function(response) {
var data = response.data ? response.data[0] : {};
return data.answer === 'true'
},
function(response) {
// Handling failure case.
switch (response.status) {
default:
case 404:
return false;
}
});
}
function initiateEsignature() {
var postParams = {
sysparm_scope: 'global',
sysparm_processor: 'ESignatureAuthUtils',
sysparm_name: 'fetchAuthDetails'
}
return $http({
method: 'POST',
url: '/xmlhttp.do',
data: urlTools.encodeURIParameters(postParams),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
transformResponse: function(response) {
return xmlUtil.getDataFromXml(response, 'result');
}
}).then(
function(response) {
var data = response.data ? response.data[0] : {};
process(data);
});
}
function process(data) {
var shouldLogoutFirst = data.logoutFirst === 'true';
w['windowHeight'] = data.popup_window_height;
w['windowWidth'] = data.popup_window_width;
w['redirectURL'] = data.loginURL;
if (shouldLogoutFirst)
openEsignatureWindow(data.logoutURL);
else
authenticate();
}
function openEsignatureWindow(url) {
w['esignOW'] = window.open(url, 'esignatureAuthentication',
'height='+w['windowHeight']+',width='+w['windowWidth']+',top=100,left=100,toolbar=0,location=0,menubar=0');
}
w['authenticate'] = function(){
if(w['redirectURL']){
if(w['esignOW']) //when we signed out previously, a window is already opened. reuse it.
w['esignOW'].location.href = w['redirectURL'];
else
openEsignatureWindow(w['redirectURL']);
}
};
w['evaluateRedirect'] = function(msg) {
w['esignOW'].close();
if (msg == "saml2 login complete") {
$window.onReauthenticationComplete(msg);
}
};
return {
isWindowChosen: isWindowChosen,
initiateEsignature: initiateEsignature
};
};
});
```
## spAuthCustom script
Paste the spAuthCustom script in the sys\_ui\_script.list script field.
```
angular.module('sn.$sp').factory('spAuthModal', function($q, spModal, i18n, $http, spAuthentication, glideUserSession, cabrillo, $cookies, $window, spUtil, $uibModal, spEsignature) {
"use strict";
function _showAuthenticationModal(requestParams, username, userSysId) {
var currentUser;
var deferred = $q.defer();
glideUserSession.loadCurrentUser({reload: true}).then(function(user) {
if (!user) {
deferred.reject({
error: {
status: 'ANONYMOUS',
message: i18n.getMessage('Not logged in')
}
});
return;
}
currentUser = user;
var serializedUser = {
sysId: currentUser.userID,
userName: currentUser.userName,
firstName: currentUser.firstName,
lastName: currentUser.lastName
};
// hand off to native clients
if (cabrillo.isNative()) {
cabrillo.auth.reauthenticate(currentUser).then(function() {
deferred.resolve(serializedUser);
}, function(error) {
if (error && error.status) {
deferred.reject({
error: error
});
}
//TODO: Handle rejection a little more gracefully
deferred.reject();
});
return;
}
var loginMethod = currentUser.$private.loginMethod;
if (!loginMethod) {
// As we were unable to determine the login method via the HTTP session, trying to get glide_sso_id cookie which is set in case of multisso login
var providerSysId = $cookies.get('glide_sso_id');
loginMethod = providerSysId ? 'multisso' : 'db';
}
if (loginMethod === 'saml' || loginMethod === 'oidc' || loginMethod === 'multisso') {
spEsignature.isWindowChosen().then(function(result) {
var modal;
if (!spUtil.isMobile() && loginMethod !== 'oidc' && result === true) {
// If enabled, Opening a new window for desktop saml login
spEsignature.initiateEsignature();
} else {
glideUserSession.getSsoReauthenticationUrl().then(function(url) {
requestParams.externalLoginURL = url;
openExternalAuthModal(requestParams).then(function(m) {
modal = m;
});
});
}
$window.onReauthenticationComplete = function(result) {
deferred.resolve(serializedUser);
if (modal)
modal.close();
};
});
} else {
spModal.open({
title:i18n.getMessage("Approver authentication"),
message:i18n.getMessage("Additional authentication is required, enter your usename and password to continue."),
footerStyle: {border: 'none', 'padding-top': 0},
widget: 'simpleloginui',
widgetInput: {},
shared: requestParams,
onSubmit: function() {
return onLoginModalSubmit(requestParams, username);
}
}).then(function(confirm) {
if (confirm.label == i18n.getMessage("OK")) {
deferred.resolve(serializedUser);
} else {
deferred.reject();
}
});
}
});
return deferred.promise;
}
function onLoginModalSubmit(requestParams, username) {
//(1) call login service to verify auth
//(2) verify same user
return $q(function(resolve, reject) {
var errorMessage = null;
if(!requestParams.username || requestParams.username.trim() === "" ||
!requestParams.password || requestParams.password.trim() === "") {
errorMessage = i18n.getMessage("User name or password invalid");
} else if(requestParams.username !== username) {
errorMessage = i18n.getMessage("Attempted to authenticate as a different user");
}
if(!errorMessage || errorMessage === "") {
spAuthentication.validateCreds(requestParams.username, requestParams.password).then(function(res) {
resolve({status: res.success, errorMessage: res.message});
});
} else {
resolve({status: !errorMessage || errorMessage === "", errorMessage: errorMessage});
}
});
}
function openExternalAuthModal(requestParams) {
var deferred = $q.defer();
var options = {
title: i18n.getMessage("Approver authentication"),
message: '',
messageOnly: false,
errorMessage: '',
input: false,
label: '',
size: 'lg',
value: '',
required: false,
footerStyle: {border: 'none', 'padding-top': 0},
values: false,
onSubmit: null,
widget: 'simpleloginui',
widgetInput: {},
shared: requestParams,
buttons: [{label: i18n.getMessage('Cancel'), cancel:true}]
};
var widgetURL = spUtil.getWidgetURL(options.widget);
$http.post(widgetURL, options.widgetInput).success(function(response) {
options.widget = response.result;
options.widget.options.shared = options.shared;
var modal = $uibModal.open({
templateUrl:'sp-modal.html',
controller: spModalCtrl,
size: options.size,
resolve: {
options: function() {
return options;
}
}
});
deferred.resolve(modal);
});
return deferred.promise;
}
function spModalCtrl($scope, options) {
$scope.options = options;
$scope.form = {};
$scope.buttonClicked = function(button){
if (button.cancel) {
$scope.$dismiss();
return;
}
}
}
return {
prompt: _showAuthenticationModal
}
}).decorator("spAuthModal", function($delegate) { return( $delegate );});
```
| title | Enable e-signature for Service Portal |
| description | You can configure e-signature in Service Portal to require re-authentication from approving users.Open a new window for SSO authentication when using e-Signature for approvals.Paste the spEsignatureCustom script in the sys\_ui\_script.list script field.Paste the spAuthCustom script in the sys\_ui\_script.list script field. |
| locale | en-US |
| canonical_url | https://www.servicenow.com/docs/r/platform-user-interface/service-portal/enable-esignature-sp.html |
| release | brazil |
| product | Service Portal |
| classification | service-portal |
| topic_type | task |
| last_updated | 2026-09-10 |
| reading_time_minutes | 5 |
| breadcrumb | Managing portal accessConfiguring Service PortalService PortalConfigure UIs and portalsConfigure user experiences |