How to strictly restrict Portal access by Role?

divyashah
Tera Guru

Hi Community,

I am working on a requirement to strictly isolate user access between two ServiceNow Portals based on roles.

Requirement Details:

  • Partner users should only be able to access the Partner Portal (/partner)

  • Employee users should only be able to access the Employee Center (/esc)

Current Configuration:

  • Login redirection has been implemented using SPEntryPage, and users are correctly redirected to their respective portals after authentication.

Challenge:
While the redirection works as expected, users are still able to manually access unauthorized portals via direct URL manipulation (for example, a Partner user entering /esc in the browser).

Expectation:
I am looking to enforce strict access control at the portal level, such that:

  • Unauthorized users are completely blocked from accessing the portal

  • Access results in a server-side Access Denied or 404-style response

  • The solution follows ServiceNow best practices and is secure and maintainable

Questions:

  1. What is the recommended best practice in ServiceNow to restrict Service Portal access based on roles?

  2. Is there a standard server-side mechanism to enforce this restriction rather than relying only on UI redirection?

  3. Are there any OOB approaches (ACLs, portal configuration, or scripting) that should be preferred for this use case?

Any guidance or proven approach from real-world implementations would be highly appreciated.

Thank you.

2 ACCEPTED SOLUTIONS

divyashah
Tera Guru

[SOLVED] Workaround: Restricting Manual URL Access to Portals using a Header Widget

Post Body:

Thanks @VANSHIKAMUKand @Ankur Bawiskar for your detailed responses and guidance.

The Challenge:

While SPEntryPage successfully handled the initial login redirection, I faced an issue where users could still access unauthorized portals by manually typing the URL (e.g., a Partner user typing /esc).

The Constraint:

As @VANSHIKAMUK mentioned, the standard OOB method is using User Criteria (Can View/Cannot View related lists) on the Portal record. However, in my specific instance, the Service Portal User Criteria Support plugin was not active, and I did not have the permissions/access to enable the specific system properties to expose those related lists.

The Solution (Workaround):

I implemented a "Security Guard" logic directly within the Portal Header. Since the header loads on every page, it acts as a gatekeeper. If an unauthorized user tries to force their way in via URL, the header script detects their role and immediately redirects them back to their allowed portal.

Here is the implementation steps for anyone facing similar constraints:

Step 1: Create a new Widget

  • Name: Portal Security Redirect

  • ID: portal-security-redirect

Server Script:

JavaScript
 
(function() {
    var user = gs.getUser();
    var portal = $sp.getPortalRecord().url_suffix.toString(); 
    
    data.redirect = false;
    data.redirect_url = "";

    // SCENARIO 1: Partner User trying to access Employee Center (/esc)
    // Check if user is a Partner (and NOT an Admin)
    var isPartner = user.hasRole('partner_user') || user.hasRole('partner_mgmt_user');

    if (portal == 'esc' && isPartner) {
        if (!user.hasRole('admin')) {
            data.redirect = true;
            data.redirect_url = '/partner'; // Route back to Partner Portal
        }
    }

    // SCENARIO 2: Internal Employee trying to access Partner Portal (/partner)
    if (portal == 'partner') {
        // If they are NOT a partner and NOT an admin, don't allow them 
        if (!isPartner && !user.hasRole('admin')) {
            data.redirect = true;
            data.redirect_url = '/esc'; // Route back to Employee Center
        }
    }
})();

Client Controller:

JavaScript
 
api.controller = function($window) {
  var c = this;
  if (c.data.redirect) {
      $window.location.href = c.data.redirect_url;
  }
};

Step 2: Embed this Widget in your Portal Header

I opened my custom Header widget (used by the Portal Theme) and added the security widget to the very top.

  • Header Widget Server Script:

    data.securityRedirect = $sp.getWidget('portal-security-redirect');

  • Header Widget HTML Template (at the very top):

    <sp-widget widget="data.securityRedirect"></sp-widget>

This successfully blocks manual URL manipulation without requiring the User Criteria plugin. Thanks again for the help!

View solution in original post

@divyashah 

I believe I also shared a working solution using UI script.

Thank you for marking my response as helpful.

💡 If my response helped, please mark it as correct as well so that this helps future readers find the solution faster! 🙏

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

View solution in original post

5 REPLIES 5

VANSHIKAMUK
Tera Contributor

1) Page‑level authorization with roles (primary control)

  • On each Service Portal page (sp_page), populate the Roles related list with the role that are required to view it.
    • For the Partner Portal pages, add a role like x_partner.user (or your equivalent).
    • For Employee Center (/esc) pages, add sn_hr_sp.hrsp_employee / sn_hr_core or your chosen employee role.
  • When a user without the role hits the page URL, Service Portal won’t render it. Instead, it routes to the portal’s Access denied page (configurable per portal). That’s server‑side enforcement.

2) Configure “Access denied” and “Page not found” pages per portal

  • In each sp_portal record:
    • Requires login: enabled.
    • Access denied page: point to a page that shows a clear 403‑style message to unauthorized users.
    • Page not found page: point to a page with a 404‑style message.
  • These are server‑side outcomes—not just UI messages.

3) Enforce with ACLs (data‑level protection)

  • Even if someone finds a way to call a widget or data source directly, the table/field ACLs must block them.
    • Lock down tables used by the Partner portal to x_partner.user (or group/role equivalents).
    • Lock down HR/ESC data to employee roles only (e.g., sn_hr_sp.hrsp_employee).

4) Widget, menu, and module roles (defense‑in‑depth)

  • sp_widget: set Roles on widgets so they can’t execute server scripts for unauthorized users.
  • sp_menu / sp_menu_item: add Roles to keep navigation from surfacing cross‑portal links.
  • Catalogs, Categories, and Items: restrict with roles so they don’t render in the “wrong” portal even if a page is reachable.

5) Routing/layout guards (optional belt‑and‑suspenders)

  • If you have a global layout widget (present on every page), you can add a server‑side guard that:
    • Checks the current portal vs. the user’s allowed audience and,
    • If mismatched, sets a flag to render an Access Denied fragment or route to the portal’s Access Denied page.
  • Treat this as secondary; your primary controls should be sp_page roles + ACLs.

Addressing your questions directly

1) Best practice to restrict Service Portal access based on roles?
Use sp_page Roles to authorize pages (server‑side), backed by table/field ACLs for data. Keep page sets distinct per portal so role gating is absolute.

2) Is there a standard server‑side mechanism rather than UI redirection?
Yes. Service Portal page authorization is done server‑side via sp_page Roles. Unauthorized users do not get the page rendered; the request routes to the portal’s Access denied page. Complement with ACLs to protect data.

3) OOB approaches to prefer (ACLs, portal config, scripting)?

  • OOB & preferred: sp_page Roles, ACLs, Portal → Access denied/Page not found configuration, widget/menu roles, catalog/KB role restrictions.
  • Optional scripting: A global layout widget server script as an extra guard, but avoid making it your only control.

Ankur Bawiskar
Tera Patron

@divyashah 

you are already redirecting but users can change browser URL and navigate and see

For this you can use this workaround

use custom UI script and Ajax to inform them and redirect them to CSM portal automatically.

for that check this

Solution: Redirecting Users to the CSM Portal Based on Roles in ServiceNow

💡 If my response helped, please mark it as correct and close the thread 🔒— this helps future readers find the solution faster! 🙏

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

@divyashah 

Hope you are doing good.

Did my reply answer your question?

💡 If my response helped, please mark it as correct and close the thread 🔒— this helps future readers find the solution faster! 🙏

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

divyashah
Tera Guru

[SOLVED] Workaround: Restricting Manual URL Access to Portals using a Header Widget

Post Body:

Thanks @VANSHIKAMUKand @Ankur Bawiskar for your detailed responses and guidance.

The Challenge:

While SPEntryPage successfully handled the initial login redirection, I faced an issue where users could still access unauthorized portals by manually typing the URL (e.g., a Partner user typing /esc).

The Constraint:

As @VANSHIKAMUK mentioned, the standard OOB method is using User Criteria (Can View/Cannot View related lists) on the Portal record. However, in my specific instance, the Service Portal User Criteria Support plugin was not active, and I did not have the permissions/access to enable the specific system properties to expose those related lists.

The Solution (Workaround):

I implemented a "Security Guard" logic directly within the Portal Header. Since the header loads on every page, it acts as a gatekeeper. If an unauthorized user tries to force their way in via URL, the header script detects their role and immediately redirects them back to their allowed portal.

Here is the implementation steps for anyone facing similar constraints:

Step 1: Create a new Widget

  • Name: Portal Security Redirect

  • ID: portal-security-redirect

Server Script:

JavaScript
 
(function() {
    var user = gs.getUser();
    var portal = $sp.getPortalRecord().url_suffix.toString(); 
    
    data.redirect = false;
    data.redirect_url = "";

    // SCENARIO 1: Partner User trying to access Employee Center (/esc)
    // Check if user is a Partner (and NOT an Admin)
    var isPartner = user.hasRole('partner_user') || user.hasRole('partner_mgmt_user');

    if (portal == 'esc' && isPartner) {
        if (!user.hasRole('admin')) {
            data.redirect = true;
            data.redirect_url = '/partner'; // Route back to Partner Portal
        }
    }

    // SCENARIO 2: Internal Employee trying to access Partner Portal (/partner)
    if (portal == 'partner') {
        // If they are NOT a partner and NOT an admin, don't allow them 
        if (!isPartner && !user.hasRole('admin')) {
            data.redirect = true;
            data.redirect_url = '/esc'; // Route back to Employee Center
        }
    }
})();

Client Controller:

JavaScript
 
api.controller = function($window) {
  var c = this;
  if (c.data.redirect) {
      $window.location.href = c.data.redirect_url;
  }
};

Step 2: Embed this Widget in your Portal Header

I opened my custom Header widget (used by the Portal Theme) and added the security widget to the very top.

  • Header Widget Server Script:

    data.securityRedirect = $sp.getWidget('portal-security-redirect');

  • Header Widget HTML Template (at the very top):

    <sp-widget widget="data.securityRedirect"></sp-widget>

This successfully blocks manual URL manipulation without requiring the User Criteria plugin. Thanks again for the help!