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
HTTP | Operation | Type | Object | DTO Why-DTOs? |
---|---|---|---|---|
Query | userAccessPolicyCheck |
UserAccessPolicyCheckInput |
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
To use this service, you need to provide the following input parameter:
createCustomer
, deleteSalesQuote
, query accountingAccounts
, etc.) for which you want to check the current user’s permissions.The service returns an array of objects, each containing the following fields:
true
) or not (false
).Key | Value |
---|---|
Authorization |
Bearer Current access Token How to find? |
X-TenantId |
Current tenant id How to find? |
X-OrganizationId |
Current organization Id How to find? |
x-api-key |
Primary or secondary subscription key of your app How to find? |
query userAccessPolicyCheck($actions: [String!]!) {
userAccessPolicyCheck(actions: $actions) {
action
isAllowed
}
}
{
"actions": ["createCustomer", "deleteSalesQuote", "accountingAccounts"]
}
{
"data": {
"userAccessPolicyCheck": [
{
"action": "createCustomer",
"isAllowed": true
},
{
"action": "deleteSalesQuote",
"isAllowed": false
},
{
"action": "accountingAccounts",
"isAllowed": true
}
]
}
}
Fields | Type | Description |
---|---|---|
actions | Array[String] | List of action names to check permissions for |
Fields | Type | Description |
---|---|---|
action | String | Name of the action checked |
isAllowed | Boolean | Indicates whether the action is permitted for the current user |
documentPdfPreviewSalesQuote
for sales quotes,documentPdfPreviewSalesOrder
for orders,documentPdfPreviewSalesDeliveryNote
for delivery notes,documentPdfPreviewSalesInvoice
for invoices.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.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"
}
}
]
}
global.businessErrors.unknownActionNames
, indicating that one or more actions provided do not match any known operations within the API.The details within the extensions
object provide specific insight into which actions were unrecognized:
"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.
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.
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:
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
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
}
}
`
}
};
qm
object, which encapsulates all queries and mutations the app may perform.//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))];
}
userAccessPolicyCheck
, passing a list of action policies the application uses.The global variable userPolicies ultimately contains a list of objects, each with their access authorization set to either true
or false
.
//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;
}
buttonId
, policyAllowed
, forceDisable
)forceDisable
is true, the corresponding UI element is disabled.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.
//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');
}
}
userPolicies.salesQuotes
permission and displays a warning message if the user does not have this permission.
// Check user's application access
function checkUserAppAccess() {
if (!userPolicies.salesQuotes) {
waitInfo(false);
deleteAllProductListRows();
displayBusinessError("APPFORBIDDEN");
return false;
} else
return true;
}