web
You’re offline. This is a read only version of the page.
close
Skip to main content

Announcements

No record found.

News and Announcements icon
Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Suggested Answer

Best practice for conditional access (check role, duty or privilege?)

(1) ShareShare
ReportReport
Posted on by 2,017

Hi everyone,
 

I'm looking for some advice on the best D365FO security design for the following scenario.
 

Let's assume these users currently have access to a button through their existing roles:
 

UserExisting Role
User1System Admin
User2IT Admin
User3Role1
User4Role2
User5Role3
User6Role2
User7Role3


In the normal scenario, all of these users should continue to have access to the button.


However, when the current record meets a specific condition (for example, ID1 and ID2 are both populated), only some users should still be able to use the button.
 

For example:

UserAccess when IDs are populated
User1
User2
User3
User4
User5
User6
User7


Notice that User4 and User6 both have Role2, but only User6 should retain access. Likewise, User5 and User7 both have Role3, but only User7 should retain access.


To achieve this, we're introducing a new security role that will be assigned only to the users who should retain access in this specific scenario, alongside their existing operational roles. The role will contain a new duty, which in turn contains the privilege required for this button.
 

Since the condition depends on the current record, the logic has to be evaluated in X++.

  public boolean isButtonEnabled()
   {
       boolean ret;

       ret = next isButtonEnabled();

       if (ret && this.isIDsPopulated())
       {
           ret = this.hasButtonAccess();
       }

       return ret;
   }


   public boolean isIDsPopulated()
   {
       return this.Id1 != '' && this.Id2 != '';
   }


   public boolean hasButtonAccess()
   {
       SecurityUserRole securityUserRole;
       SecurityRole     securityRole;

       select firstonly RecId from securityUserRole
           where securityUserRole.User == curUserId()
              && securityUserRole.AssignmentStatus == RoleAssignmentStatus::Enabled
           exists join securityRole
           where securityUserRole.SecurityRole == securityRole.RecId
              && (securityRole.AotName == '-SYSADMIN-'
              || securityRole.AotName  == 'ITAdmin'
              || securityRole.AotName  == 'NewRole');

       return securityUserRole.RecId != 0;
   }

Given this requirement, is there a better D365FO security design than checking the user's roles in hasButtonAccess()? For example, would you check a duty, a privilege, or use another approach?

Categories:
  • Diego Mancassola Profile Picture
    973 Super User 2026 Season 2 on at

    Hi, if i understand, i would avoid checking role names directly.

    Roles and duties are organizational/security-composition elements; they are not the most appropriate authorization boundary for X++ code. A user can receive the same permission through another role, sub-role, or security customization. A direct query against SecurityUserRole would not necessarily reflect the user’s complete effective permissions.

    The recommended design would be:

    Create a dedicated action menu item representing the restricted operation, enable or disable it based on IDs.
    Add that entry point to a dedicated privilege.
    Add the privilege to a duty and to a small supplemental role, if this fits your security structure.
    Assign that role only to the users who may perform the operation when the IDs are populated.
    In X++, check the user’s effective access to the entry point, rather than checking the role, duty, or privilege name.

  • Suggested answer
    André Arnaud de Calavon Profile Picture
    307,097 Super User 2026 Season 2 on at

    Hi ..,

    If the access to a button is available to anyone except when the record has a specific status or condition, then you will need X++ coding to manage the enablement of the button. 

    You can choose to use security to be assigned to users. This is done in the standard application as well. Some items do work based on a role, others based on a privilege. E.g. the access to private addresses is managed using security roles, see: About the private location security in Finance & Operations and Human Resources - Dynamicspedia

    Also the workflow history form is checking for the SysAdmin or IT manager roles to be able to show workflow instances for all users and those who are in an error state.

    In the Financial reporter, the existence of a privilege assigned to the user via security roles is checked.

     

    The role or privilege does not need additional access to the menu item button, you can check in X++ if the user is assigned to a role (as per your example) or if any role has exploded permissions to a privilege.

     

    Instead of hard-coding the security roles, I would choose for a configurable option like the private location security option. You can still choose to have the SysAdmin and IT manager roles hard-coded as they are standard roles. Additional roles can be considered via configuration. Note that you can also choose for privileges instead of roles. 

    Also consider the organization assignment to security roles. That will determine in what legal entities a user has the permission. 

     

    Note that you can also create two menu item buttons. One for the condition is true and another if the condition of the IDs is false. With X++ you can manage the visibility of the menu-items. Then, similar to what Diego mentioned, you can manage access to the menu items with “standard” security. Then only one menu item will be visible on the form at a moment in time, depending on the condition.

     

    Note that the approach to check for ID values is not waterproof. A user could change the value, then use the menu item button. Thereafter revert the value to the original value. Or are these fields read-only?

  • Suggested answer
    Deepak Agarwal Profile Picture
    9,306 Super User 2026 Season 2 on at

    I would avoid checking roles directly in X++. Instead, create a dedicated privilege (e.g. ANNSPostRejectionOveridePrivilege) assign it through a duty and a new security role, and then check whether the user has that privilege when ID1 and ID2 are populated. This keeps the code independent of role names and aligns better with the D365FO security model (Privilege > Duty > Role). If security assignments change later, no code changes are required.

     

    In short, check a dedicated privilege, not role names. A duty check is also acceptable, but privilege is usually the most granular and maintainable approach.

  • .. Profile Picture
    2,017 on at

    Hi @André Arnaud de Cal... @André Arnaud de Cal... 

    Thanks Andre, this is really helpful. I have a few questions to make sure I fully understand the different approaches you suggested.
     

    1. Regarding making the allowed roles configurable:
    In our case, the new NewRole role is being created specifically to act as the additional/exception role for this scenario. If another user needs this access in the future, we could simply assign “NewRole” to that user alongside their existing role, without changing the X++.

    In that case, would you still see an advantage in introducing separate configuration for the allowed roles rather than using the dedicated SPE IT Manager role for this purpose?
     

    2. Regarding organization assignment:
    That's a good point. With my current SecurityUserRole query, how would you recommend ensuring that the role assignment is actually effective for the current legal entity? what changes to do in my code?
     

    3. Regarding the two-menu-item approach: which was aslo suggested by @Diego Mancassola 
    If I understood correctly, I would still need the new “NewRole” role, along with it's duty and privilege and assign that role to the specific users who should retain access when the IDs are populated.

    The difference would be that instead of checking NewRole in X++, I would have two menu items with different security and use X++ only to control which one is visible based on the IDs.

    If that's correct, what would you see as the main advantage of introducing the second menu item compared with keeping one menu item and checking the additional role/permission in X++ when the IDs are populated? Is the main benefit that the authorization remains within the standard D365FO security framework?

    4. Regarding the ID values:
    We checked this and one of the two fields is editable, while the other is read-only.

    I just wanted to clarify your concern. Our logic is based on the current values of those two fields. Therefore, if one of the IDs is changed or cleared, the record would no longer meet the "IDs populated" condition, so the normal logic would intentionally apply.

    Were you assuming that those fields should not be editable at that stage, or were you referring to a different scenario where you would still recommend validating the condition again as part of the actual operation?
    --------------
    And another note that ITAdmin is custom, it's xxxITAdmin

    Thanks @Deepak Agarwal .

    One question: in this scenario, the privilege would also be a newly created, dedicated privilege, so it would still be hardcoded in X++ just like the dedicated “NewRole” role.

    Could you elaborate on the advantage of checking the privilege rather than the role in this case? Is it mainly because the privilege represents the business permission rather than a particular role, or is there another benefit? and what is the x++ code used to do check privilege instead?

  • Suggested answer
    Assisted by AI
    Deepak Agarwal Profile Picture
    9,306 Super User 2026 Season 2 on at

    @.. You may not need to create X++ privilege while you can create this from front end itself. The only thing you need to make sure it to export from source environment and import in target environment as any security object crated from front end will not be part of package deployment. 

     

    Regarding your another question, yes you are nearly there. When we use privilege its more close to object you need to control via access while for ‘Role’ you will not get this clearity   directly. 

     

    For your last question, X++ code generally executes under the current user context, but standard X++ table access does not automatically enforce role-based security for every database operation. you must explicitly consider security, and certain frameworks , and the Table Permission Framework are used to enforce access restrictions.

    try this sample method, (AI generated, not verified)

    public static boolean hasUserSecurityPrivilege(
     
    SecurityPrivilegeName _securityPrivilege,
     
    UserId _userId = curUserId())
     
    {
     
    SecurityRolePrivilegeExplodedGraph rolePrivilege;
     
    SecurityUserRole userRole;
     
    SecurityPrivilege privilege;
     

     
    select firstOnly privilege
     
    where privilege.Identifier == _securityPrivilege
     
    exists join rolePrivilege
     
    where rolePrivilege.SecurityPrivilege == privilege.RecId
     
    exists join userRole
     
    where userRole.SecurityRole == rolePrivilege.SecurityRole
     
    && userRole.User == _userId
     
    && userRole.AssignmentStatus == RoleAssignmentStatus::Enabled;
     
    return privilege.RecId != 0;
     
    }
  • Suggested answer
    vishalsahijwani Profile Picture
    392 on at

    Hi @Diego Mancassola ,

    Your approach of working with a role is correct but the problem here is that you are currently calling specific AOT role names such as SYSADMIN , ITAdmin , NewRole. Instead you can do the same at privilege level. Create a new privilege and a duty. Associate your custom privilege with your custom duty. Change the logic in hasButtonAccess() to call your privilege by its name rather than calling AOT role names.

    Let me know if this helps 

  • Suggested answer
    André Arnaud de Calavon Profile Picture
    307,097 Super User 2026 Season 2 on at

    Hi ..,

    A follow up on your questions. 

    1. In case the role is intended as “IT manager”, and don't expect variations, then you can implement this without an additional configuration table.
    2. You can use the table SecurityUserRoleCondition to find out if there are legal entity restrictions for the user/role assignment (SecurityUserRole). In case there is no organization assigned, there is no record and the user has access to all legal entities.
    3. When using two menu items, you only need to take care of visibility for the menu item based on your condition of the two fields. The security framework will then hide the menu for users who don't have access to the second one. This security framework is also by default taking care of the organization assignment.
    4. I'm not telling you if the fields should be editable or not. There is an option that a smart user will change the value, just because of being curious to open the menu item. Depending on the exact process this might still be a security risk.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Season of Sharing Community Challenge Winners!

Congratulations to our community stars!

Women in Power Builds Momentum

Expanding mentorship, skilling, and AI innovation

Congratulations to the July Top 10 Community Leaders

These are the community rock stars!

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Martin Dráb Profile Picture

Martin Dráb 415 Most Valuable Professional

#2
CU10121822-0 Profile Picture

CU10121822-0 374

#3
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 365 Super User 2026 Season 2

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans