Access Control Lists for Data Items


In Part 1, we synchronized OutSystems application data with Microsoft Search & Intelligence using the Microsoft Graph External Data Connections API. This, along with a search vertical and result display template, made our data available to users in the search console.
During synchronization, we gave permission to the ingested data records to the "everyone" group, allowing all organization users to search and view the data. In a real application, you will likely need to restrict who can search and view the ingested data. In this tutorial, we will explore how to manage access control lists for ingested data records to ensure that only authorized users have access.
Demo Application
This article series includes a demo application called "ODC with Graph Demo," available on ODC Forge. Be sure to download the version of the application that matches this article.
For this article, you need to install Version 0.2 from ODC Forge.
In the ODC Portal, go to Forge - All Assets.
Search for "ODC with Graph Demo".
Click on the Asset (Do not click on Install on the tile!).
Switch to the Version tab and click on Install next to Version 0.2.
Version 0.2 depends on other Forge components:
OAuthTokenExchange - An external logic library that helps retrieve access tokens easily. In this tutorial however we use an action to retrieve the discovery document from Microsoft Entra only.
Graph External Data Connections API - A connector library that integrates with Microsoft Graph API for external data connections.
Graph Users API - A connector library that integrates with Microsoft Graph API users endpoint to retrieve user details.
What we build
In this part of the tutorial series, we will add specific access control list entries to ingested testimonials, allowing access only to designated users. This involves the following steps:
Mapping User Accounts - Map OutSystems application users to Microsoft Entra users.
Access Control List - Add access control list entries during data ingestion to Microsoft Graph.
Prerequisites
Before we begin, please reset the existing external data connection configurations in your Microsoft 365 tenant by following the cleanup steps and recreating the external data connection schema as described in part one of the series.
Entra Application Permissions
Our application registration we are using to ingest data requires one additional permission to retrieve Entra user details. In the Entra admin center, go to Applications - App Registrations and select the “Graph External Data Connection ODC” registration.
In the API permissions menu, click Add permission.
Select Microsoft Graph and Application permission.
Search for and select User.ReadBasic.All permission.
Click Add permission.
This permission requires an administrator to grant admin consent.
- Click Grant admin consent <your domain> and confirm the dialog.
Before we try the demo application, let's explore Access Control List entries for external data in Microsoft Graph a bit more in depth.
Access Control List Entries
Access Control List entries in Microsoft Graph for external data specify who can access certain ingested data records and the level of access they have.
Entries are defined by a type attribute that identifies the identity you want to grant permissions to. The type can have one of the following values:
user - Indicates that you want to grant permission to an individual Entra user account.
group - Indicates that you want to grant permission to an individual Entra group.
externalGroup - A non-Entra group that your application manages. We will discuss external groups shortly.
everyone - A special type that indicates public access.
application - Grants permission to a specific Entra application registration.
Next, a value must be provided that corresponds to the type you specified:
user - The Entra user's object identifier.
group - The Entra group's object identifier.
externalGroup - The external group identifier.
everyone - Must be set to “everyone”.
application - The Application (client) ID of the Entra application registration.
Finally, the accessType attribute defines the level of permission:
grant - Grants access to the record.
deny - Denies access to the record. Deny Access Control List entries take precedence over grant entries.
A sample JSON representation of a single Access Control List entry that grants a specific Entra user access to a record looks like this.
{
"accessType": "grant",
"type": "user",
"value": "381a61cf-7d4e-40a3-a225-83c5bc36fbf0"
}
A Graph ingested data record can have multiple Access Control List entries with different types.
Mapping User Accounts
Microsoft 365 users are authenticated through Microsoft Entra, and Entra does not automatically recognize OutSystems user accounts. Therefore, to manage authorizations, we need to identify which Entra user account matches an OutSystems user.
Even if OutSystems users log in through Entra, we, as of today, cannot directly access the login identification data within our application. The only information we have is the user data from the User entity. This means we have to use the user's email address to identify the corresponding Entra user.
There are two ways to do this. If the email address of an OutSystems user matches the Universal Principal Name (UPN) of the Entra user, we can easily get the Entra user details using the Graph_GetUser action from the Graph Users API connector library.
If the OutSystems user's email address does not match Entra's UPN, you can use the Graph_ListUsers action from the Graph Users API connector library. This allows you to filter for the user whose mail attribute matches the OutSystems user's email address. The filter would look like this
mail eq 'mail@domain.com'
Read more on OData filters in the Microsoft Documentation.
External Groups
External Groups represent group entities from systems outside of Microsoft Entra. These groups are used to reflect the access control structures of external data sources.
When developing an OutSystems application with record-level permissions (Entity records), it's better to manage permissions at the group or role level instead of individual user accounts. This makes permission management easier over time.
External Groups for Microsoft Graph External Data let you sync your application's group or role structures and use them in Access Control List entries for item permissions.
An external group is identified by a unique identifier that you need to specify when creating an external group in Microsoft Graph. This identifier can be any alphanumeric string without special characters. The external identifier is then used in all future member management operations.
The Graph External Data Connections API connector library offers the actions you need to create, update, and delete external groups, as well as add and remove group members.
Creating an External Group
With the Graph_CreateExternalGroup action you can create a new external group in Microsoft Graph by providing the following information.
ExternalGroupId - The unique identifier of the external group. Can be any alphanumeric string without special characters.
DisplayName - Optional display name
Description - Optional description
Adding and Removing External Group Members
The actions Graph_CreateIdentity and Graph_DeleteIdentity let you add and likewise remove members from an external group. Members can be one of the following types
user - A Microsoft Entra user account identified by its object identifier.
group - A Microsoft Entra group identified by its object identifier.
externalGroup - Another, already existing, external group that you want to nest.
Adding an External Group Item Access Control List Entry
Using an external group in an ACL is straight forward. The JSON representation of an external group ACL would look like this.
{
"accessType": "grant",
"type": "externalGroup",
"value": "externalGroupIdentifier"
}
Now that we have covered the basics, let's explore the implementation of the demo application.
Demo Application Walkthrough
In this walkthrough, we will explore the key implementation details. Be sure to check the comments in the various server actions as well.
The demo application assigns Access Control List entries based only on user accounts, without using external groups. As a small challenge, try implementing a group permission structure in the demo application on your own.
In ODC Studio, open the ODC with Graph Demo application.
Saving a Testimonial
In the Logic tab, open the SaveTestimonial action under Server Actions - Actions. This action runs when a user creates or updates a testimonial on the Testimonial screen.
This action first performs a check if it is a new testimonial or an existing one and depending on the outcome executed either the Testimonial_Create or Testimonial_Update CRUD wrappers.
The AddPermission server action is executed when creating a new and is responsible for creating the initial record permission for the creator of the testimonial.
GetUserDetails - Reads the current user's email from the User entity.
GetEntraAccessToken - Retrieves an access token using the application credentials to access Microsoft Graph.
Graph_GetUser - Queries Microsoft Graph using the user's email address to obtain Entra user details with the Universal Principal Name.
TestimonialMember_Create - A CRUD wrapper to create a record in the TestimonialMember entity with the OutSystems User Identifier and the Entra user's object identifier.
Back in the SaveTestimonial action, whether creating or updating a testimonial, the IngestContent finally syncs the testimonial with Microsoft Graph.
Most of the action flow was already explained in part 1. The new addition is the GetTestimonialAccessList action, which retrieves the current permissions from the TestimonialMember entity and returns a list of ItemAccessControlList and assigned to the Graph_CreateOrUpdateItem request structure.
Modifying Permissions
You can modify testimonial permissions in the demo application for existing testimonials. In the Permissions tab of a testimonal you can add or remove OutSystems users.
Adding a new member with permissions to a testimonial triggers the AddTestimonialMember action under Server Actions - Actions. Removing a member triggers the RemoveTestimonialMember action.
Both actions first execute the AddPermission or DeletePermission actions, followed by the IngestContent action to update the record with the new ACL entries in Microsoft Graph.
This wraps up the demo application walkthrough. Try using the demo application with different user accounts to see the search results in Microsoft 365. As an extra challenge, try adding external group management to the application.
Notes and Recommendations
The demo application performs all actions synchronously, triggered from the frontend. In a real use case, you should offload data ingestion to Microsoft Graph to a workflow.
In addition, I recommend implementing a queue that stores an entry for each data item (testimonial) to create, update, and delete, and removes the entry from the queue once the data ingestion operation succeeds. This way, you minimize the risk of application data and graph data becoming inconsistent.
Summary
In this tutorial, we explored how to define Access Control List entries for ingested data items to limit access for specific user accounts. We also discussed how the Graph External Data Connections API and Graph Users API connector libraries can be used to manage external groups and their memberships.
I hope you enjoyed it and would appreciate your feedback.
Subscribe to my newsletter
Read articles from Stefan Weber directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Stefan Weber
Stefan Weber
As a seasoned Senior Director at Telelink Business Services EAD, a leading IT full-service provider headquartered in Sofia, Bulgaria, I lead the charge in our Application Services Practice. In this role, I spearhead the development of tailored software solutions using no-code/low-code platforms and cutting-edge cloud-ready/cloud-native solutions based on the Microsoft .NET stack. Throughout my diverse career, I've accumulated a wealth of experience in various capacities, both technically and personally. The constant desire to create innovative software solutions led me to the world of Low-Code and the OutSystems platform. I remain captivated by how closely OutSystems aligns with traditional software development, offering a seamless experience devoid of limitations. While my managerial responsibilities primarily revolve around leading and inspiring my teams, my passion for solution development with OutSystems remains unwavering. My personal focus extends to integrating our solutions with leading technologies such as Amazon Web Services, Microsoft 365, Azure, and more. In 2023, I earned recognition as an OutSystems Most Valuable Professional, one of only 80 worldwide, and concurrently became an AWS Community Builder.