DEV Community

Andrew Elans
Andrew Elans

Posted on

Power Pages: how to get contact's Dataverse team membership in web template with Liquid

When building internal portals on Power Pages, you often need to drive UI logic based on who the logged-in user is in Dataverse - not just their portal web roles, but their actual Dataverse team memberships. This post shows the correct approach and why the obvious path doesn't work.


The naive approach - and why it fails

The logged-in user in a portal is a contact record. Your first instinct might be to traverse owninguser on the contact to get the backing systemuser, then look up their team memberships from there:

{% assign systemuserId = entities.contact[user.contactid]['owninguser'].id %}
{% assign teams = entities.systemuser[systemuserId]['teammembership_association'] %}

Enter fullscreen mode Exit fullscreen mode

This doesn't work. In the portal context, owninguser on the contact is always the same portal service account - not the actual logged-in person. You'll get the same result for every user.


The correct approach - start from the team

Instead of starting from the user and looking up their teams, start from the known team and check whether the current user is a member. The team entity exposes teammembership_association, and you can filter it by internalemailaddress against user.emailaddress1:

{% assign procurementTeamId = 'a3a5a17e-4a64-ef11-bfe3-000d3a48fb1c' %}
{% assign procurementTeamMember = entities.team[procurementTeamId]['teammembership_association'] | where: 'internalemailaddress', user.emailaddress1 | select: 'internalemailaddress' %}

Enter fullscreen mode Exit fullscreen mode

If the result is non-empty, the current user is a member of that team.


Driving UI with team membership

Web templates in Power Pages are shared across all portal users, but you often need to surface UI elements - buttons, sections, forms, tabs - that are only relevant to members of a specific Dataverse team. By resolving team membership server-side in Liquid, you can conditionally render those elements before the page reaches the browser, without any client-side Web API calls or duplicating logic in the portal web role model. The team membership in Dataverse becomes the single source of truth.

A clean pattern is to assign a role variable first, then use it to branch your UI:

{% assign userRole = 'standard' %}
{% assign procurementTeamId = 'a3a5a17e-4a64-ef11-bfe3-000d3a48fb1c' %}
{% assign procurementTeamMember = entities.team[procurementTeamId]['teammembership_association'] | where: 'internalemailaddress', user.emailaddress1 | select: 'internalemailaddress' %}

{% if procurementTeamMember and procurementTeamMember != empty %}
    {% assign userRole = 'procurement' %}
{% endif %}

{% if userRole == 'procurement' %}
    <h1>Hi Procurement User</h1>
{% else %}
    <h1>Hi Standard User</h1>
{% endif %}

Enter fullscreen mode Exit fullscreen mode

This keeps the membership check separate from the rendering logic, which scales well when you have multiple teams to check - set all your role variables up front, then branch your UI below.


A note on table permissions

For the Liquid query to work, Read table permissions must be granted to both the Team and System User tables in the Power Pages management app, scoped to Authenticated Users. Without these, the entities traversal will return blank regardless of what data exists in Dataverse.

The entities object in Liquid supports N:N relationship traversal in both directions - from systemuser and from team. The key insight for portal use cases is that you need to start from the team side, since owninguser on contact always resolves to the portal service account, not the logged-in user.


That's it. Start from the known team GUID, filter teammembership_association by the user's email, and use the result to drive conditional UI - all server-side, no client-side API calls needed.


A note on how this was found

I was looking for a reliable way to connect a portal contact to their backing systemuser in Liquid - something that doesn't seem to be documented anywhere in a straightforward way. Part of what makes this tricky is that there is no direct link or relationship between the contact table record and the systemuser record in Dataverse. They are separate entities, and bridging them in the portal context requires an indirect approach. The team-first pattern shown here is one solution. I'll cover another approach in a follow-up post.

Top comments (0)