Microsoft Power Pages & Portals — Complete Guide
Power Pages Architecture · Liquid Templates · Web Roles · Authentication · Dataverse Integration · ALM · Scenarios · Cheat Sheet
Table of Contents
- Core Concepts — Basics
- Architecture & Components
- Authentication & Web Roles
- Liquid Templates & Customisation
- Dataverse Integration & Forms
- ALM, Security & Performance
- Scenario-Based Questions
- Cheat Sheet — Quick Reference
1. Core Concepts — Basics
What is Microsoft Power Pages and how did it evolve?
Microsoft Power Pages is a low-code platform for building secure, data-driven external-facing websites and portals. It is built on the Power Platform and uses Dataverse as its primary data store.
Evolution:
- Dynamics 365 Portals (pre-2018): tightly coupled with Dynamics 365
- Power Apps Portals (2018–2022): rebranded, part of Power Platform
- Microsoft Power Pages (2022–present): standalone product with a modern design studio, enhanced security, and dedicated site management
What Power Pages enables:
- External customer portals (case management, self-service)
- Partner portals (deal registration, partner onboarding)
- Employee self-service portals (expense claims, HR requests)
- Community portals (forums, knowledge bases)
- Government/citizen service portals
- Event registration and management portals
Key positioning: Power Pages is the "external-facing" complement to model-driven Power Apps (internal). Where model-driven apps serve employees, Power Pages serves customers, partners, and citizens.
What is the difference between Power Pages and Power Apps model-driven apps?
Power Apps Model-Driven Apps:
→ Audience: internal users (employees)
→ Authentication: Entra ID (Azure AD) — requires M365/Azure licence
→ Interface: Unified Interface, Dataverse forms/views
→ Access: direct Dataverse access with security roles
→ Customisation: Power Apps designer, canvas controls
→ Licensing: per user (Power Apps licence)
→ Use for: CRM, ERP, internal workflows
Power Pages:
→ Audience: external users (customers, partners, citizens)
→ Authentication: identity providers (Entra B2B, Azure B2C,
Google, Facebook, local accounts, LinkedIn)
→ Interface: custom web pages, HTML/CSS/JS, Liquid templates
→ Access: filtered Dataverse data via table permissions + web roles
→ Customisation: Power Pages design studio, VS Code, Liquid/JS
→ Licensing: per page view or capacity (Power Pages licence)
→ Use for: customer portals, partner portals, citizen services
What are the Power Pages licence models?
Power Pages Authenticated Users:
→ Licensed per authenticated user per month
→ For portals where users must sign in to access content
→ Includes internal and external authenticated users
→ Covers: case submissions, account management, personalised content
Power Pages Anonymous Users (Capacity):
→ Licensed per page view (capacity units)
→ For public-facing portals where content is accessible without login
→ Anonymous users: 100 page views per capacity unit
→ Covers: public websites, event info, knowledge base browsing
Power Pages add-on:
→ Purchased as a standalone capacity add-on
→ Can be pooled across an environment
Included with Dynamics 365 licences:
→ D365 Customer Service Enterprise → 1 Power Pages production capacity
→ D365 Sales Enterprise → 1 Power Pages production capacity
What are the key portal templates available in Power Pages?
| Template | Use Case |
|---|---|
| Blank website | Start from scratch with full control |
| Customer self-service | Case creation, knowledge base, account management |
| Community | Forums, idea submissions, community discussions |
| Partner | Deal registration, partner onboarding, MDF claims |
| Employee self-service | HR requests, expense claims, internal announcements |
| Modern Community | Updated community template with modern UI |
| Starter layout 1-5 | Pre-built page structures for rapid starts |
2. Architecture & Components
What is the Power Pages architecture?
Power Pages Architecture:
External User (Browser)
↓ HTTPS
Power Pages Web Application (Azure-hosted)
↓
Caching Layer (Azure CDN / Portal Cache)
↓
Liquid Template Engine
↓
Power Pages Web API / FetchXML
↓
Dataverse (entity/table data)
↓
Connected Services:
→ Entra ID / Azure AD B2C (authentication)
→ Azure Blob Storage (file attachments)
→ SharePoint (document management)
→ Power Automate (workflow triggers)
→ Azure API Management (external API calls)
Key architectural facts:
→ Power Pages runs as a dedicated Azure Web App per environment
→ Each portal is associated with ONE Dataverse environment
→ Portal metadata (pages, content, web roles) stored in Dataverse tables
→ Content served via Liquid templates + static assets (CSS, JS, images)
→ Changes in Power Pages design studio write to Dataverse metadata tables
What are the core Power Pages components?
Webpages:
→ The URL-addressable pages of the portal
→ Each webpage has: name, partial URL, parent page, web template
→ Hierarchy: Home → About → Services → Contact
→ Published/Draft state: draft pages not visible to portal visitors
Web Templates:
→ Liquid + HTML defining how a page renders
→ Assigned to webpages
→ Can include: HTML, Liquid tags, JavaScript, Bootstrap CSS classes
→ Reusable across multiple pages
Content Snippets:
→ Small reusable pieces of text/HTML
→ Managed separately from page content
→ Used for: site name, footer text, error messages, shared labels
→ Editable by portal admins without editing the web template
Entity (Table) Forms:
→ Dataverse forms surfaced on the portal
→ Create, edit, or read-only modes
→ Linked to Dataverse table + form definition
→ Control: which columns visible, required fields, validation
Entity (Table) Lists:
→ Dataverse views surfaced as lists/grids on portal
→ Filter, sort, and paginate Dataverse records
→ Column display, search, linked forms for detail view
→ Supports: OData feeds, download as Excel/CSV
Web Files:
→ Static assets stored in Dataverse and served by the portal
→ Images, CSS overrides, JavaScript files, PDF downloads
→ Managed via Portal Management app or design studio
Site Settings:
→ Key-value configuration pairs controlling portal behaviour
→ Examples: Authentication/Registration settings, search settings,
file upload limits, header/footer behaviour
→ Critical settings control authentication providers, email configs
What is the Portal Management app?
The Portal Management app is a model-driven Power App that provides full configuration access to all portal components — webpages, web templates, web roles, table permissions, entity forms, entity lists, site settings, and more.
When to use Portal Management app vs Design Studio:
Design Studio (Power Pages studio):
→ Visual, low-code experience
→ Page layout, sections, components drag-and-drop
→ Form/list configuration
→ Navigation management
→ Theme and styling
→ Best for: makers and page builders
Portal Management App:
→ Full access to all portal metadata tables in Dataverse
→ Advanced configuration not available in design studio
→ Web role and table permission configuration (complex setups)
→ Site settings configuration
→ Web template source code editing
→ Page hierarchy management
→ Authentication provider configuration
→ Best for: advanced developers and administrators
3. Authentication & Web Roles
What authentication providers does Power Pages support?
Supported identity providers:
Microsoft Entra ID:
→ Entra ID (Azure AD) — for employees and internal users
→ Entra External ID (B2B) — for partner organisations
→ Azure AD B2C — for consumer identities with custom flows
→ Protocol: OpenID Connect / OAuth 2.0
Social providers:
→ Microsoft Account (personal)
→ Google
→ Facebook
→ LinkedIn
→ Twitter/X (via custom OAuth)
Enterprise providers:
→ Any SAML 2.0 provider
→ Any OpenID Connect provider
→ WS-Federation
Local authentication:
→ Email/password accounts managed within Power Pages
→ Email confirmation, password reset flows included
→ NOT recommended for production — use federated IdPs
Multi-provider configuration:
→ A single portal can support multiple providers simultaneously
→ User sees options: "Sign in with Google" + "Sign in with Entra ID"
→ Contact matching: link sign-ins from different providers to same Contact record
What are Web Roles and how do they control access?
Web Roles are the primary access control mechanism in Power Pages — they determine what authenticated users can see and do on the portal.
Web Role structure:
Name: "Customer Standard"
Users: portal contacts assigned this role
Permissions: table permissions linked to this role
Special web roles:
Authenticated Users: automatically assigned to ALL signed-in users
Anonymous Users: automatically assigned to ALL non-signed-in users
Custom web roles examples:
→ Customer Basic: read own cases + create new cases
→ Customer Premium: read all cases for their account + create
→ Partner Manager: manage all partner accounts and opportunities
→ Portal Admin: manage portal content (pages, content snippets)
→ Knowledge Manager: publish/unpublish knowledge articles
Assigning web roles:
→ Manually: Portal Management app → Contacts → assign web role
→ Automatically: Power Automate flow → when user registers, assign role
→ Via invitation: send role-specific invitation links
Web Role + Table Permissions (together = access control):
Web Role defines WHO
Table Permission defines WHAT they can do to WHICH data
What are Table Permissions and how do they work?
Table Permissions (formerly Entity Permissions) define what authenticated or anonymous users can do with Dataverse data on the portal.
Table Permission configuration:
Table: which Dataverse table (e.g., incident/Case)
Access type: Global, Contact, Account, Parent, Self
Privileges: Create, Read, Write, Delete, Append, AppendTo
Web Roles: which web roles this permission applies to
Access types:
Global: can access ALL records in the table (admin-level)
Contact: can only access records where Contact = logged-in user
Account: can access records belonging to the same Account
Parent: can access child records via a parent relationship
Self: Contact record can only access their own Contact record
Example — Customer case portal:
Table: incident (Case)
Access type: Contact (customerid = logged-in Contact)
Privileges: Create, Read, Write
Web Roles: [Authenticated Users]
→ Each user sees and edits ONLY their own cases
Example — Account manager portal:
Table: incident (Case)
Access type: Account (customerid.parentcustomerid = user's Account)
Privileges: Read
Web Roles: [Account Manager]
→ Account managers see all cases for their account company
Table permission hierarchy (child permissions):
Parent table: Account (Access type: Contact)
Child table: Contact (Access type: Parent, via accountid)
→ User can read their own account AND contacts in that account
Critical: Without table permissions, portal users have NO access to any Dataverse data. Table permissions are additive — a user gets the union of all permissions from all their assigned web roles.
What is the portal registration and profile management flow?
New user registration flow:
1. User visits portal → clicks "Sign in"
2. Selects identity provider (Entra ID, Google, local account)
3. Completes IdP authentication
4. First time: portal creates/matches a Contact record in Dataverse
Contact matching: by email address (configurable)
5. Optional: registration page for additional profile data
(name, company, preferences — writes to Contact record)
6. Default web roles assigned: "Authenticated Users"
7. Optional: email confirmation required before full access
8. Custom roles: assigned manually or via Power Automate flow
Invitation flow (pre-approved access):
1. Admin creates Invitation record in Dataverse
2. Sets: invitation type (single/group), assigned web roles, expiry
3. Portal sends invitation email with unique link
4. User clicks link → completes registration
5. Assigned web roles applied automatically on redemption
6. Use for: partner onboarding, controlled external access
4. Liquid Templates & Customisation
What is Liquid and how is it used in Power Pages?
Liquid is an open-source template language used in Power Pages to generate dynamic HTML content. It allows web templates to access portal data, user context, and Dataverse records.
{# Liquid template example — personalised greeting and case list #}
{% if user %}
<h1>Welcome back, {{ user.fullname }}!</h1>
<p>Your open cases:</p>
{% fetchxml %}
<fetch mapping="logical" count="10">
<entity name="incident">
<attribute name="title" />
<attribute name="statecode" />
<attribute name="createdon" />
<filter>
<condition attribute="customerid" operator="eq"
value="{{ user.id }}" />
<condition attribute="statecode" operator="eq" value="0" />
</filter>
<order attribute="createdon" descending="true" />
</entity>
</fetch>
{% endfetchxml %}
{% if results.entities.size > 0 %}
<ul>
{% for case in results.entities %}
<li>{{ case.title }} — Created: {{ case.createdon | date: "%d %b %Y" }}</li>
{% endfor %}
</ul>
{% else %}
<p>You have no open cases.</p>
{% endif %}
{% else %}
<p>Please <a href="/signin">sign in</a> to view your cases.</p>
{% endif %}
What are the key Liquid objects available in Power Pages?
{# Core Liquid objects #}
user → currently authenticated portal user (Contact record)
{{ user.fullname }} ← Contact's full name
{{ user.emailaddress1 }} ← Contact's email
{{ user.id }} ← Contact's GUID
{{ user.roles }} ← collection of web roles
page → current webpage being rendered
{{ page.title }}
{{ page.adx_partialurl }}
{{ page.breadcrumbs }}
website → the portal website object
{{ website.name }}
{{ website.adx_primarydomainname }}
request → current HTTP request
{{ request.url }}
{{ request.params['search'] }} ← query string parameter
{{ request.cookies['name'] }}
settings → site settings (key-value store)
{{ settings['Authentication/Registration/Enabled'] }}
snippets → content snippets
{{ snippets['site/tagline'] }}
now → current date/time
{{ now | date: "%Y-%m-%d" }}
Liquid filters (transform values):
{{ value | upcase }} ← UPPERCASE
{{ value | downcase }} ← lowercase
{{ value | truncate: 50 }} ← truncate to 50 chars
{{ value | date: "%d %b %Y" }} ← format date
{{ value | escape }} ← HTML escape (XSS prevention)
{{ value | default: "N/A" }} ← default if null
What is FetchXML in Power Pages and how do you use it?
FetchXML is Dataverse's XML-based query language used within Liquid templates to retrieve data from Dataverse tables.
{# FetchXML example — get top 5 knowledge articles by rating #}
{% fetchxml %}
<fetch mapping="logical" count="5">
<entity name="knowledgearticle">
<attribute name="title" />
<attribute name="description" />
<attribute name="adx_averagerating" />
<filter type="and">
<condition attribute="statecode" operator="eq" value="3" /> <!-- Published -->
<condition attribute="isinternal" operator="eq" value="0" /> <!-- External -->
</filter>
<order attribute="adx_averagerating" descending="true" />
</entity>
</fetch>
{% endfetchxml %}
{% for article in results.entities %}
<div class="article-card">
<h3>{{ article.title }}</h3>
<p>{{ article.description | truncate: 150 }}</p>
<span>Rating: {{ article.adx_averagerating | round: 1 }}/5</span>
</div>
{% endfor %}
{# FetchXML with linked entities (JOIN) #}
{% fetchxml %}
<fetch mapping="logical">
<entity name="incident">
<attribute name="title" />
<attribute name="statecode" />
<link-entity name="contact" from="contactid" to="customerid" alias="cust">
<attribute name="fullname" alias="customername" />
</link-entity>
<filter>
<condition attribute="ownerid" operator="eq-userid" />
</filter>
</entity>
</fetch>
{% endfetchxml %}
What is the Power Pages Web API and when do you use it?
The Power Pages Web API provides a RESTful endpoint for reading and writing Dataverse data from client-side JavaScript — enabling rich interactive experiences without page reloads.
// Power Pages Web API examples
// GET — read records (table permissions enforced):
const response = await fetch(
'/_api/incidents?$select=title,statecode,createdon&$filter=statecode eq 0',
{
headers: {
'__RequestVerificationToken': document.querySelector(
'input[name="__RequestVerificationToken"]').value
}
}
);
const data = await response.json();
data.value.forEach(c => console.log(c.title));
// POST — create a record:
await fetch('/_api/incidents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'__RequestVerificationToken': getToken()
},
body: JSON.stringify({
title: 'New Support Request',
description: 'Issue description here',
'customerid_contact@odata.bind': `/contacts(${userId})`
})
});
// PATCH — update a record:
await fetch(`/_api/incidents(${caseId})`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'__RequestVerificationToken': getToken()
},
body: JSON.stringify({ description: 'Updated description' })
});
// Key rules:
// → Table permissions enforced — users can only access permitted records
// → Anti-forgery token required for POST/PATCH/DELETE (CSRF protection)
// → Columns must be enabled for Web API in table settings
// → Use $select to limit returned columns
5. Dataverse Integration & Forms
How do Entity Forms work in Power Pages?
Entity Forms (Table Forms) surface Dataverse forms directly on the portal, allowing portal users to create, edit, or view Dataverse records.
Entity Form configuration:
Name: friendly name for the form
Table: which Dataverse table (e.g., incident)
Form: which Dataverse form definition to use
Mode: Insert (create), Edit, ReadOnly
Record source: QueryString (ID from URL), Current Portal User,
Fixed Record (always same record)
Entity Form metadata:
→ Additional settings overlaid on the Dataverse form
→ Control: redirect after submit, success message
→ Validation: custom JavaScript validation
→ On Success: URL redirect, show message, or load another form step
Multi-step forms (Form Steps):
→ Wizard-style multi-page forms
→ Each step = one Entity Form
→ Steps linked via Web Form (multi-step form container)
→ Progress indicator, back/next navigation
→ Data saved incrementally between steps
→ Final step submits all data
Example — 3-step case creation wizard:
Step 1: "What is the issue?" → capture Title + Description
Step 2: "Contact details" → capture Contact info
Step 3: "Review and submit" → display summary + submit
Entity List on form:
→ Related records displayed below the main form
→ e.g., Case form with related Notes list below
How do Entity Lists work in Power Pages?
Entity Lists (Table Lists) display Dataverse records as searchable, filterable lists on the portal.
Entity List configuration:
Table: which Dataverse table
View: which Dataverse saved view to use (filter + columns)
Page size: number of records per page (default 10)
Search: enable/disable search across listed columns
Filter: metadata filters (filter by date, status, lookup)
Actions: Create (link to Entity Form), View, Edit, Delete actions
OData feed:
→ Entity List can expose an OData endpoint
→ External apps can consume portal data via OData
→ URL: /[listname]/odata — returns JSON
→ Filtered by table permissions (user only sees permitted records)
Subgrids:
→ Entity List embedded as a subgrid within an Entity Form
→ e.g., Account page shows all Cases for that Account
→ Configured via Entity List with parent filter
Portal search integration:
→ Entity List results included in portal search
→ Requires search enabled on the entity list
→ Records indexed based on view columns
How does SharePoint document management integrate with Power Pages?
SharePoint integration setup:
1. Enable SharePoint integration in Dataverse (Power Platform Admin Centre)
2. Configure document location: Dataverse record → SharePoint folder
3. Portal displays document library on Entity Form
How it works:
→ User opens a Case record on the portal
→ Entity Form displays "Documents" section (if configured)
→ Documents stored in SharePoint (not Dataverse attachment)
→ Portal fetches document list via SharePoint integration
→ User can upload/download documents from the portal
→ Files stored in SharePoint → version history, large file support
Supported operations via portal:
→ View document list for a record
→ Upload new documents (stored in SharePoint)
→ Download documents
→ Delete documents (with appropriate permissions)
Limitations:
→ Requires SharePoint integration enabled at environment level
→ SharePoint must be in same M365 tenant
→ Anonymous users cannot access SharePoint-integrated documents
6. ALM, Security & Performance
How do you manage Application Lifecycle Management (ALM) for Power Pages?
Power Pages ALM approach:
1. Dataverse Solutions:
→ Package portal metadata in a Dataverse solution
→ Solution contains: webpages, web templates, entity forms/lists,
table permissions, web roles, site settings, content snippets
→ Export as managed solution (for target environments)
→ Import into Test → UAT → Production
2. Power Platform CLI (pac cli):
→ pac pages upload / download — sync portal files to/from local disk
→ Local editing: edit Liquid templates, CSS, JS in VS Code
→ Upload changes back to Dataverse portal tables
→ pac solution export/import for full solution-based ALM
3. Source control (Git):
→ Export portal files with pac CLI → commit to Git
→ Enables: version history, PR review of template changes,
branch-based development
→ CI/CD: GitHub Actions / Azure DevOps pipeline using pac CLI
4. Environment variables:
→ Site settings that differ between environments
→ Dev: dev.contoso.com, Prod: portal.contoso.com
→ Connection strings, API endpoints, feature flags
ALM workflow:
Developer → local edit → pac upload → Dev environment test
→ pac solution export → PR review
→ merge → automated pipeline → UAT → Production
What are the key security considerations for Power Pages?
Security layers:
1. Table permissions (data layer):
→ Always configure — no table permissions = no data access
→ Follow least privilege — start restrictive, open as needed
→ Test with different user types (anonymous, authenticated, roles)
→ Audit table permissions regularly
2. HTTPS (transport layer):
→ Always enforced — Power Pages provides SSL certificate automatically
→ Custom domain: upload your own SSL certificate or use Let's Encrypt
3. Content Security Policy (CSP):
→ Configure allowed script/style sources
→ Prevent XSS attacks via CSP headers
→ Site setting: HTTP/X-Content-Security-Policy
4. Anti-forgery tokens:
→ Required for all POST/PATCH/DELETE Web API calls
→ Prevents CSRF attacks
→ Built into Entity Forms automatically
5. Rate limiting:
→ Configure site settings to limit API call frequency per user
→ Prevents abuse of Web API endpoints
6. Bot protection:
→ Configure reCAPTCHA or Cloudflare Turnstile on registration + forms
→ Site setting: Recaptcha/Enabled, Recaptcha/PublicKey
7. IP restrictions:
→ Restrict portal access to specific IP ranges
→ Site setting: Maintenance Mode for controlled access
8. Authentication hardening:
→ Disable local authentication in production (use federated IdPs)
→ Configure session timeout (Site/SessionTimeoutEnabled)
→ Require email confirmation for registration
9. Content hiding vs Table Permissions:
→ Hiding a page in navigation does NOT secure the data
→ Table Permissions control actual data access
→ "Security through obscurity" is not security — always use table permissions
What are Power Pages performance best practices?
Caching:
→ Portal output caching: pages cached for 15 minutes by default
→ Clear cache: Power Pages studio → Sync (clears portal cache)
→ Partial caching: use {% cache %} tag for expensive Liquid blocks
→ Static files: served via CDN (Azure CDN) — always fast
FetchXML optimisation:
→ Use count attribute to limit records returned
→ Use $select equivalent — only fetch needed attributes
→ Avoid N+1 queries: use link-entity instead of nested loops
→ Index frequently filtered columns in Dataverse
Entity List performance:
→ Set reasonable page size (10-25 records)
→ Ensure Dataverse view has appropriate filters (don't load all records)
→ Index columns used in view filters
Web API performance:
→ Always use $select to limit returned columns
→ Use $top to limit result count
→ Avoid calls on page load for non-critical data — lazy load
Liquid template performance:
→ Avoid complex Liquid in high-traffic page templates
→ Use content snippets for frequently changing small content
→ Minimise FetchXML calls per page (each = a Dataverse query)
CDN and static assets:
→ Use web files for CSS/JS (served via CDN)
→ Compress images before uploading as web files
→ Minimise inline CSS/JS in web templates
7. Scenario-Based Questions
Scenario: Design a customer self-service portal for a financial services company.
Requirements: Customers log in, view their accounts, create service requests, track case status, and download statements.
-
Authentication: Azure AD B2C with custom branding. Email/password + optional social login. MFA enforced via B2C policy. Contact matching by email.
-
Portal structure:
- Home (public) — product information, login CTA
- My Account (authenticated) — account details, balance, contact info
- Service Requests (authenticated) — create new case, view case history
- Documents (authenticated) — download statements from SharePoint
- Knowledge Base (public) — FAQ, guides
-
Web Roles:
Authenticated Customers— read own account, create cases, view own casesPremium Customers— all above + priority case routing flag
-
Table Permissions:
- Contact: Self access → read own Contact record
- Account: Contact access → read their associated Account
- Incident (Case): Contact access → create + read own cases
- KnowledgeArticle: Global → read published external articles
-
Forms:
- Case creation: multi-step form (Issue type → Details → Confirmation)
- Case detail: read-only view with status timeline
- Profile update: edit mode for Contact email/phone
-
Security: reCAPTCHA on registration and case creation. CSP headers configured. Disable local authentication — B2C only.
-
ALM: solution-based deployment. Dev → UAT → Production pipeline via GitHub Actions + pac CLI.
Scenario: How do you restrict a portal page to users with a specific web role?
Three approaches (all needed together for full security):
1. Page visibility in navigation:
→ Webpage → Publishing State: Published
→ Web Role restriction on webpage: only visible to "Premium Customers" role
→ Page does NOT appear in navigation for other users
→ This is NOT security — page URL may still be accessible directly
2. Webpage Access Control (Entity Permission on Webpage):
→ Associate the webpage with a specific web role
→ Users without the role see: 403 Forbidden or redirect to sign-in
→ Configured via: Webpage → Web Roles (many-to-many relationship)
→ This IS the correct security control for pages
3. Table Permissions (data layer):
→ Even if user accesses the page, data is only visible if
table permissions allow it
→ Defence in depth: page access + data access both restricted
Example:
Webpage "Premium Dashboard":
Web Roles: [Premium Customers] ← page access
Entity List on page:
Table: financial_statement
Access: Account
Web Roles: [Premium Customers] ← data access
Result: non-Premium users cannot see the page AND cannot access
the data even if they somehow reach the URL.
Scenario: How do you implement a multi-language portal?
Power Pages multi-language support:
1. Enable languages:
→ Portal Management app → Website → Supported Languages
→ Add languages: en-US (default), fr-FR, de-DE, es-ES
→ Install language packs for each language
2. Content localisation:
→ Webpages: create a localised copy per language
Home (en-US) → Home (fr-FR) → Home (de-DE)
→ Content Snippets: create per-language versions
→ Entity Form labels: localised via Dataverse column label translations
3. Language switcher:
→ Liquid template: loop through supported languages
{% for lang in website.supported_languages %}
<a href="{{ request.url | set_language: lang.code }}">
{{ lang.name }}
</a>
{% endfor %}
4. URL structure:
→ Language in URL: /en-US/home, /fr-FR/home
→ Or: subdomain — en.portal.contoso.com, fr.portal.contoso.com
5. Right-to-left (RTL) support:
→ Enable RTL for Arabic (ar), Hebrew (he)
→ Configure Bootstrap RTL CSS for RTL languages
6. Browser language auto-detection:
→ Site setting: Globalization/AutoDetectLanguage = true
→ Portal automatically redirects to preferred language based on
browser Accept-Language header
Scenario: How do you troubleshoot a portal page that shows no data despite the user being authenticated?
Diagnostic checklist:
1. Check if user is authenticated:
Liquid: {% if user %}...{% endif %}
→ If user object is empty: authentication not completing → check IdP config
2. Check Web Role assignment:
→ Portal Management app → Contacts → find user → Web Roles
→ Verify "Authenticated Users" role is assigned (should be automatic)
→ Verify custom role is assigned if page requires specific role
3. Check Table Permissions:
→ Portal Management app → Table Permissions → find permission for the table
→ Verify: correct table, correct access type, correct web roles, correct privileges
→ Permission must have Read privilege for data to display
4. Check if Entity List/Form has correct table:
→ Verify Entity List points to the correct Dataverse table
→ Verify the Dataverse view used exists and returns data in model-driven app
5. Check FetchXML (if custom Liquid):
→ Add debug output: {{ results | dump }}
→ Check if FetchXML returns data in XrmToolBox FetchXML Builder
→ Verify filter conditions match actual data values
6. Check Portal Cache:
→ Design Studio → Sync (clears portal output cache)
→ Table permission changes require cache clear to take effect
7. Check browser console:
→ Web API errors appear in browser console
→ 403: table permission blocking access
→ 401: user not authenticated for this API call
→ 500: server error — check portal diagnostic logs
8. Enable portal diagnostics:
→ Append ?enableportaldiagnostics=true to URL
→ Shows diagnostic information for admins
8. Cheat Sheet — Quick Reference
Power Pages Component Summary
Webpages: URL-addressable pages, publish/draft state
Web Templates: Liquid + HTML templates assigned to pages
Content Snippets: Reusable text/HTML fragments
Entity Forms: Dataverse forms (create/edit/read)
Entity Lists: Dataverse views displayed as lists
Web Roles: Access groups controlling what users can see/do
Table Permissions: Data access control (who reads/writes which records)
Web Files: Static assets (CSS, JS, images, PDFs)
Site Settings: Key-value portal configuration
Table Permission Access Types
Global: ALL records in the table (use sparingly — admin-level)
Contact: records WHERE contact lookup = logged-in user
Account: records WHERE account lookup = user's parent account
Parent: child records accessible via parent record permission
Self: Contact record = user's own Contact only
Privileges: Create | Read | Write | Delete | Append | AppendTo
Example combinations:
Cases (own): Table=incident, Access=Contact, Priv=Create+Read+Write
Cases (account): Table=incident, Access=Account, Priv=Read
Articles: Table=knowledgearticle, Access=Global, Priv=Read
Own profile: Table=contact, Access=Self, Priv=Read+Write
Key Liquid Objects
{{ user }} → authenticated Contact record
{{ user.fullname }} → Contact display name
{{ user.id }} → Contact GUID
{{ user.roles }} → collection of web role names
{{ page.title }} → current page title
{{ page.adx_partialurl }} → current page URL segment
{{ request.url }} → full current URL
{{ request.params['key'] }} → query string value
{{ settings['key'] }} → site setting value
{{ snippets['name'] }} → content snippet value
{{ now }} → current datetime
Authentication Provider Site Settings
Key site settings for authentication:
Authentication/Registration/Enabled = true/false
Authentication/Registration/RequiresConfirmation = true/false
Authentication/Registration/LocalLoginEnabled = false (production)
Authentication/Registration/ExternalLoginEnabled = true
Azure AD:
Authentication/OpenIdConnect/AzureAD/Authority = https://login.microsoftonline.com/{tenantId}/v2.0
Authentication/OpenIdConnect/AzureAD/ClientId = {appId}
Authentication/OpenIdConnect/AzureAD/ClientSecret = {secret}
Google:
Authentication/OpenIdConnect/Google/Authority = https://accounts.google.com
Authentication/OpenIdConnect/Google/ClientId = {clientId}
Session:
Site/SessionTimeoutEnabled = true
Site/SessionTimeoutMinutes = 30
ALM Quick Reference
pac CLI commands for Power Pages:
pac auth create --url https://contoso.crm.dynamics.com
pac pages upload --path ./portal-root --deploymentProfile dev
pac pages download --path ./portal-root --environment contoso-dev
pac solution export --name PortalSolution --path ./solutions --managed
pac solution import --path ./solutions/PortalSolution_managed.zip
Environment-specific settings:
→ Use Dataverse environment variables for site settings
→ Dev/Test/Prod have different values for:
Portal URL, API endpoints, reCAPTCHA keys, email settings
GitHub Actions pipeline example:
1. pac auth create (service principal)
2. pac solution import (deploy portal solution)
3. pac pages upload (deploy template/file changes)
4. Clear portal cache (POST to /_services/about/clearcache)
Top 10 Tips
-
Table Permissions are mandatory — without them, authenticated users see NO Dataverse data. The most common portal configuration mistake is forgetting to set table permissions. Start here in any debugging scenario.
-
Web Roles control page access, Table Permissions control data access — both are needed for full security. A page visible to the wrong role but with correct table permissions still shows no data. A page hidden but without table permissions is security-through-obscurity only.
-
Power Pages vs model-driven apps — Power Pages serves external users (customers/partners), model-driven serves internal users (employees). They use the same Dataverse but different access mechanisms (table permissions + web roles vs Dataverse security roles).
-
Authenticated Users web role is automatic — every signed-in user gets this role automatically. Design your table permissions baseline around this role. Custom roles are additive on top.
-
FetchXML is the query language — know the basic structure: fetch → entity → attribute + filter + order. Use link-entity for joins. Use alias for linked entity attributes. This comes up in every advanced Power Pages technical round.
-
Portal cache must be cleared after table permission changes — table permission changes don't take effect immediately. Clear cache in Design Studio or sync via pac CLI. A frustrating "why isn't this working?" scenario solved by a cache clear.
-
Anti-forgery token required for Web API — POST/PATCH/DELETE calls without
__RequestVerificationTokenreturn 400 Bad Request. Always retrieve this token from the hidden input on the page and include in API request headers. -
pac CLI is the ALM tool —
pac pages upload/downloadsyncs portal files to/from disk for source control. Know the basic commands. Every enterprise Power Pages project uses this for CI/CD. -
Multi-step forms = Web Form + Form Steps — not just multiple Entity Forms. The Web Form container manages session state between steps. Each step is a separate Entity Form but data persists until final submit.
-
Disable local authentication in production — local accounts (email/password managed by portal) should be disabled for enterprise portals. Use federated identity providers (Entra ID, Azure AD B2C) for proper security, audit trails, and MFA support.
No comments:
Post a Comment