HTTP Operation Type Object
(Query) userAccessPolicyCheck

Description

The UserAccessPolicyCheck service enables you to verify the current user’s permissions to perform specific actions within the application, based on their roles and access rights.
Furthermore, the Sage Active solution not only considers the user’s role but can also restrict access to certain data based on the Sage Active solution in use.

This service provides a mechanism to dynamically enable or disable features, or adjust the UI elements (like buttons or links), ensuring a tailored user experience that aligns with the user’s permissions.

See also: Key concepts / Users management

img

Functionality

Required Parameters

To use this service, you need to provide the following input parameter:

Response

The service returns an array of objects, each containing the following fields:

Key Value
Authorization Bearer Current access Token How to find?
X-TenantId Current tenant id Why deprecated ?
X-OrganizationId Current organization Id How to find?
x-api-key Primary or secondary subscription key of your app How to find?
GraphQL Query
query userAccessPolicyCheck($actions: [String!]!) {
  userAccessPolicyCheck(actions: $actions) {
    action
    isAllowed
  }
}
GraphQL Variables
{
  "actions": ["createCustomer", "deleteSalesQuote", "accountingAccounts"]
}
Example Response
{
  "data": {
    "userAccessPolicyCheck": [
      {
        "action": "createCustomer",
        "isAllowed": true
      },
      {
        "action": "deleteSalesQuote",
        "isAllowed": false
      },
      {
        "action": "accountingAccounts",
        "isAllowed": true
      }
    ]
  }
}

userAccessPolicyCheck Input parameters

Fields Type Description
actions Array[String] List of action names to check permissions for

userAccessPolicyCheck Response

Fields Type Description
action String Name of the action checked
isAllowed Boolean Indicates whether the action is permitted for the current user
Info
  • For the documentPdfPreview and the documentPdfEmail operations, it is necessary to specify the document type as part of the operation name according to the type of document being accessed.
    • documentPdfPreviewSalesQuote or documentPdfEmailSalesQuote for sales quotes,
    • documentPdfPreviewSalesOrder or documentPdfEmailSalesItemOrder for orders,
    • documentPdfPreviewSalesDeliveryNote or documentPdfEmailSalesDeliveryNote for delivery notes,
    • documentPdfPreviewSalesInvoice or documentPdfEmailSalesInvoice for invoices.
  • The userAccessPolicyCheck action should not be included in the list of actions because this operation needs to be functional regardless of the user’s profile and is not subject to access authorization.

Error Management

If an attempt is made to check permissions for actions that are not recognized by the API, such as incorrectly named operations, this error will be returned.
Instead of requesting permissions for customers and salesTariffs, we request them as an example of error for xustomers and xalesTariffs.

{
    "errors": [
        {
            "message": "global.businessErrors.unknownActionNames",
            "locations": [
                {
                    "line": 2,
                    "column": 3
                }
            ],
            "path": [
                "userAccessPolicyCheck"
            ],
            "extensions": {
                "details": "xustomers|xalesTariffs"
            }
        }
    ]
}

This error can also be triggered if the action userAccessPolicyCheck is passed as a parameter, as this action is not subject to access control rules and should not be included in the list of actions for permission checking.

When to Call userAccessPolicyCheck?

Since it is possible to assign different roles to the same user for different organizations, userAccessPolicyCheck must be called for each organization accessible to the current user.

Example:

John has an Admin role for organization ORG1 but has a ReadOnly role for organization ORG2.
Your application utilizing the public API provides a selection interface for the list of organizations accessible to the current user.
Here, John will see both ORG1 and ORG2 in the list.
Your application also stores the last organization used by John in local preferences.

As a result, it is necessary to call userAccessPolicyCheck and trigger the application interface to update and respect the refreshed permissions:

How the Sample Quotes App Utilizes userAccessPolicyCheck ?

Explore the Must-See Sage Active Public API V2 Quoting Example!

Dive into the invaluable resource of our front-end app example!
This example showcases the practical use of Sage Active Public API for efficient quote management.

It’s a perfect demonstration of how you can leverage the API’s capabilities in real-world scenarios, significantly simplifying the quoting process.

Now, this application also allows you to import a complete set of demo data into the current company if it does not yet have any data.

Click here to access the example : Sample quotes

img

To ensure certain actions within the Sample Quotes app are not permitted through the application interface if the current user does not have a role that allows them to utilize all functionalities, the logic is as follows:

Declaration of all queries and mutations in an object qm that contains a list of all objects used by the app.
For each operation, the policy parameter contains the name of the action.

const qm = {
  queryUserProfile: {
    context: "User Profile",
    policy: "userProfile",
    body: `
      query {
        userProfile {
          applicationLanguageCode
          authenticationEmail
          fullName
        }
      }
    `
  },
  // Other operations follow...
  updateSalesQuote: {
    context: "Sales Quote Update",
    policy: "updateSalesQuote",
    body: `
      mutation ($values: SalesQuoteUpdateGLDtoInput!) {  
        updateSalesQuote (input: $values) {
          id
        }
      }
    `
  }
};
getListOfPolicies()

This utility function extracts all policy names from the qm object, which encapsulates all queries and mutations the app may perform.
It ensures that the list of policies is unique and free of null values.
This list is then used to check against the user’s allowed actions, determining what functionalities will be available to them within the app.

img

//Get all policies from queries_mutations.js (remove duplicates and null values)
function getListOfPolicies() {
  return [...new Set(Object.values(qm).filter(item => item.policy !== null).map(item => item.policy))];
}
checkUserAccessPolicies()

This function is responsible for fetching the access policies applicable to the current user. It makes a GraphQL query to the userAccessPolicyCheck, passing a list of action policies the application uses.
The response is then processed by createPolicyAuthorizationMap to create a map of policies indicating which actions the user is allowed to perform.
This map is essential for conditionally enabling or disabling parts of the UI based on user permissions.

The global variable userPolicies ultimately contains a list of objects, each with their access authorization set to either true or false.

img

//Fetches the access policies for the current user using the specified policies used by the application.
/*Fyi qm.queryUserAccessPolicyCheck defined in query_mutation.js contains :
    {
      context: "User policies check",
      policy: null,
      body: `
        query ($actions: [String!]!) {
          userAccessPolicyCheck (actions: $actions) {
            action
            isAllowed
          }     
        }
        `
    }
*/
var userPolicies= {};
function checkUserAccessPolicies() {
  return new Promise((resolve, reject) => {

    const query = qm.queryUserAccessPolicyCheck; 
    var variables = { actions: getListOfPolicies() };
    
    genericFetchPublicAPI(headerWithOrganization, query, variables, handleResponse);

    function handleResponse(data) {
      if (data && data.data && data.data.userAccessPolicyCheck) {
        userPolicies = createPolicyAuthorizationMap(data);
        resolve();
      } else {
        reject();
      }
    }
  });
}

//Creates a map of policies and their authorization status
function createPolicyAuthorizationMap(userAccessData) {
  const policyAuthorizationMap = {};
  userAccessData.data.userAccessPolicyCheck.forEach(policyCheck => {
    policyAuthorizationMap[policyCheck.action] = policyCheck.isAllowed;
  });
  return policyAuthorizationMap;
}

adjustButtonAccessibility(buttonId, policyAllowed, forceDisable)

This function adjusts the accessibility of UI elements, such as buttons, based on the user’s permissions.
It uses the policy authorization map to check if an action is allowed.
If not, or if forceDisable is true, the corresponding UI element is disabled.
This ensures that users are only able to interact with elements they have permissions for.

Of course, this concerns adjusting the interface according to user rights, but it’s important to keep in mind that security is primarily ensured by the API.

For example, if the user does not have the right to create a quote, the “Create Quote” button will be disabled, but if the button’s status is modified to allow to execute the action, in the end, the createSalesQuote will be denied by the API.

img

//Adjusts the accessibility of a button based on the user's policy and the business rules
function adjustButtonAccessibility  (buttonId, policyAllowed, forceDisable) {
  if (policyAllowed=== null) 
    policyAllowed=true;
  else if (policyAllowed=== undefined) {
    setTimeout(() => {
      waitInfo(false);
      displayBusinessError("UNKNOWNUSERPOLICY", "adjustButtonAccessibility : " + buttonId);
    }, 1000);
  }

  const $button = $('#' + buttonId);
  const shouldDisable = !policyAllowed || forceDisable;
  $button.prop('disabled', shouldDisable);
  if (!policyAllowed) {
    $button.addClass('unauthorized');
  } else {
    $button.removeClass('unauthorized');
  }
}
checkUserAppAccess()

This function is used to test whether the user’s profile permits them to use the application.
For instance, if the user has a role that does not authorize them to use the Sales feature, they should be warned as soon as they log into the application.
The function tests the userPolicies.salesQuotes permission and displays a warning message if the user does not have this permission.

img

// Check user's application access
function checkUserAppAccess() {
  if (!userPolicies.salesQuotes) {
    waitInfo(false);
    deleteAllProductListRows();
    displayBusinessError("APPFORBIDDEN");
    return false;
  } else 
    return true;
}