Engineered Code is proud to announce the availability of ecLearn - the Learning Management System built on top of Microsoft Dataverse


Power Apps Portals: Authentication Overview

If you’re new to Power Apps Portals, or you’re an Adxstudio veteran, Portal authentication can be a tricky concept – there are a lot of options, and since we’re dealing with getting access to potentially sensitive data, you want to make sure you’re doing it right. I’ve got a few posts lined up on this subject, but I thought I’d start with a general overview of how authentication works in Power Apps Portals.

Logged In Portals Users Are Always Contacts

The first thing you need to understand is that all authentication is done in reference to a contact in CDS. Even if you are building an employee self-service portal, and you are using Azure AD to log in, and those people are licensed Power Apps or Dynamics 365 users, they still need to have a contact record to log into a Portal. The “user” object that represents the currently logged in user is always a contact, and never a system user.

When we talked about the options for Portal authentication, we are talking about who manages the actual usernames and passwords that are associated to contacts in CDS.

Two Main Types

At a high level, there are two types of authentication in Power Apps Portals: local and external.

Local authentication is when the username and password information is stored directly in CDS on the contact record. Usernames can either be the contact’s email address, or a special username field. A hashed version of the user’s password is stored, which makes it possible to verify that the correct password has been entered, but makes it impossible to retrieve their password from the database. While convenient and easy to use, local authentication has be deprecated by Microsoft, and should be avoided.

External authentication is when something outside of CDS is managing usernames and passwords – think Microsoft Accounts, Facebook, Twitter, etc. Users log in with credentials from other services, which are associated with a contact in CDS. These external authentication managers are known as identity providers, and there are a few different protocols for identity management. Portals supports four main external identity protocols: OAuth2, SAML, WS-Federation and Open ID Connect.

One of the great things about Portal authentication is that you don’t need to pick just one of these options – you can enable as many as you want. When you go to the sign in page on a Portal, the user is given a choice between all the configured identity providers.

So why doesn’t Microsoft want you to use local authentication? Well I can’t speak for them, but I can take a guess: Microsoft has a team that is focused on technology meant for authenticating people into applications like Power Apps Portals, and it’s not the Power Apps Portals team – instead, it is the team responsible for Azure AD B2C. I’ll be covering Azure AD B2C in a future post but, in short, it is a single identity provider that itself supports other identity providers like Facebook, Twitter, etc. Rather than Portals having to support Open ID Connect, OAuth2, SAML 2.0, etc, wouldn’t it be nicer if Portals just relied on something else that does authentication for a living?

Also, passing authentication off to external identity providers means Portals no longer needs to worry about saving username, passwords, and doesn’t have to worry about things like password resets. All things which are a pain and better dealt with by people who live and breath authentication.

How Is Authentication Configured?

I’m not going to get into the details of how to setup each of these types of authentication, since that documentation already exists on the official Portals documentation site. However, what I’ll mention here is that, at a high level, authentication is configured using Site Settings. Configuring authentication typically involves three or more Site Settings per provider.

How Do Contacts Get Usernames and Passwords?

While all users of a Portal must be a contact, not all contacts can log into the Portal. How do you go about associating a username and password (either local or external) with a contact?

There are typically two ways that contacts get associated with login information – either via registration or invitation.

Registration is used when the contact doesn’t already exist in CDS. If you’ve enabled open registration on your Portal, new users can sign into your Portal using any of the configured identity providers (or local authentication), which will create a bare-bones contact record associated with those login credentials. After logging in, the user will be presented with their profile page, which gives them the opportunity to fill out more details like their name, contact info, etc.

The invitation process is used when contacts already exist in your system. In this case, you don’t want users to register using open registration, as this will create the blank contacts mentioned earlier. Instead, you want to use an invitation code process to invite them to your Portal. Typically this means sending them an email with a unique code that they can enter when signing into the Portal – with this unique code, the Portal knows to associate the login information with the existing contact instead of creating a new blank one. For more details on the invitation process, see this documentation.

In my next post I’m going to dive a bit deeper into the various protocol supported for external authentication.

39 responses to “Power Apps Portals: Authentication Overview”

  1. […] post Power Apps Portals: Authentication Overview appeared first on Engineered […]

  2. Ankush says:

    Thanks Nicholas, for the great Post.
    I have an powerapps portal wherein I only want contacts already created in system to access portals.
    To make my portals (secure) I disabled all other authentication except local and even there I disabled registering as a new contact.
    Rather we will have contact created in cds and then we will send username and password to the contact so that we don’t have blank contacts.
    However portal contact does have option to visit profile page and update their details.

    Now regarding setting password, currently we use portals contact form and dialog box to set new password for the contact.

    I am not sure if my approach is completely secure but will look forward to if you have any inputs on the same.

    • Nicholas Hayduk says:

      Hi Ankush,

      I’d recommend using the invitation code process. It sounds like right now you are sending users their username and password in an email, which isn’t secure for a few reasons, including that the email might be intercepted, and because then you know the user’s password (ideally only the user knows their own password).

      Instead, create the contact, and then send them an invitation. They will get an email with a link where they can choose their own username and password.

      This would end up with a similar user experience, but much more secure.


  3. Iyke says:

    I am trying to customise the knowledge article detail page, and as far as I’m aware there’s no way to do that using Liquid, unless you want to write a new web template to replace the default hidden one for this page. So I am left with javascript, but the problem is I don’t know how to check whether the user is logged in or not, using javascript. Any help would be greatly appreciated.

  4. JC says:

    Is it possible to embed another website passing the already authenticated user to this site?
    I understand it would depend on what the embeded website supports, but does the portal supports passing the credentials to other site?

    • Nicholas Hayduk says:

      A couple options I can think of – depends on your use case. If you’re just looking for single sign on, if you use something like Azure AD B2C on both sites, users wouldn’t be prompted with another login.

      If your other site needs to know the ID of the contact logged into the portal, there is the support for OAuth 2.0 implicit grant flow:

      This allows you to generate a token that contains the ID of the contact who is logged in. I could imagine a scheme where you pass this token to the other site to enable single sign on.


  5. JC says:

    Thank you very much i´ve been reading your posts amd watching your youtube videos, and they are great.

    I have taken a look and ADB2C seems to be the way to go, but don’t know if i understood correctly, if the other site uses ADB2C, can the other site “know” more than just the fact that the users is authenticated?

    • Nicholas Hayduk says:

      I haven’t done this myself, but if the other site has a connection to CDS, there might be some data in the Azure AD B2C claims that might allow you to identify which contact it is. One thing you can look at is the External Identity entity related to the contact – it contains an ID that is unique to the user. Not sure if that ID is specific to the Portal, or if it is ID that would be available in the claims on the other site.

  6. Jeff Orris says:

    Excellent post! I’m a seasoned Dynamics dev. However, authentication wasn’t ever my strong suite with external IdPs. Specifically, bc I wasn’t ever given the task to handle that.

    I have a request to enable SAML2 in Dynamics 365 Online Customer Self-Service Portal and am testing with CircleSSO.

    I have the following requirements (to my knowledge that are required)

    1) SingleLogoutService Binding=”urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect” Location
    2) SingleSignOnService Binding=”urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect” Location
    3) urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
    4) ds:X509Certificate

    However, I’m fighting on how to implement these values with portal. Do you have a blog on how to achieve this?

  7. Derek H says:

    Hi Nick,

    I am trying to find reference to the deprecation of local authentication, and any timeline for it’s removal but haven’t been able to find any public announcement. Do you have an official source… we have several clients using local auth and cannot use the likes of google/facebook for auth, and Azure B2C could be overkill. The issue we are having is that password changes using the ADX workflow assembly in CRM are not being synced/overwriting cache on the portal (in the most recent case for a couple of days, until we did a full cache refresh)

    • Nicholas Hayduk says:

      Hey Derek,

      Unfortunately the “official” notice was removed – the closest from Microsoft is on where they recommend Azure AD B2C.

      That being said, I can confirm that I’ve had this conversation with the Microsoft Portals product team within the last few weeks, and it is definitely deprecated. The challenge is that Azure AD B2C is not currently supported in all Azure data centers. Until that happens, local login will still be available.

      I don’t consider Azure AD B2C to be overkill – we use it for even small portals with hundreds of users. That would be my recommendation.


  8. Derek H says:

    Hi Nick,
    Thanks for the prompt response and answer, I have passed it back to the team. I guess at some stage I am going to have to learn the config of Azure B2C in the next little while.

    I must say last time I looked at trying to get Azure B2C up and running with portals was a very long time ago and the guides out there were old, incomplete or simply didn’t work. Hopefully that has improved since (hell, you probably have a blog post about it)


  9. Eduardo says:

    Hi Nick,

    Thanks for the great article. The company I work with has roughly 250 employees and only about 40 with Microsoft buisness standard licences(these employees work in the office). I plan on implementing a portal for our states covid reporting responsibilities. Do you know if any external logins/page views are included or do these all need to be purchased as add ons? Also is each external authenticator individually priced? I plan on getting a per user power apps plan for myself and the per app plan for the other 39 in office employees. Thank you for any help

    • Nicholas Hayduk says:

      Hi Eduardo,

      There are no external logins or page views included with any other packages – they must be purchased separately as an addon.

      Are the people using the portal employees? If so, they’ll need Power Apps/Dynamics licenses as well – external logins can only be used by people who aren’t employed by your organization.

      I’m not sure what you mean by “is each external authenticator individually priced”. For external logins, you can setup as many other providers (Twitter, Facebook, Google, etc) as you want – you don’t pay for those. You pay each time someone logs in with those (one charge per 24 hours). These logins packs are purchased in bundles of at least 100.


  10. Eduardo says:

    Hey Nick,

    Thank you for answering my questions. Is there any reason why you wouldn’t want to or couldn’t have employees use the portal? Like security or lack of user permissions? We have about 300 employees and only about 40ish in the office have a buisness std licences already and I thought we could avoid getting everyone office and power apps licences by using a portal. Most of our emoloyees are field staff and do not need an office license. Mainly trying to create a form to track employee covid symptoms. Thank you very much for your help!

    • Nicholas Hayduk says:

      If people are employees of the organization, they’ll require at least a Power Apps license (or Dynamics, depending on what entities they are interacting with) to access a portal – using external licenses for them is not allowed. A portal can’t be used to avoid licensing – think of it as just another interface for Dynamics/Power Apps.

  11. Dibyajyoti says:

    Hi Nick,

    I have a question regarding Powerapps portal “Send Email Confirmation”.
    Q- I’m looking to configure a Send E-Mail Confirmation workflow using the Send Email Confirmation To Contact process (the Action). I’m looking to automatically send the Email Confirmation when specific fields are completed in the User Profile so I have this configured as a Workflow, calling the Action.

    However, within the Action I need to provide the following:

    CallbackUrl; Code; UrlCode; UserId and Target (Target is a Lookup)

    I’m assuming that target is the Contact that this is in relation to so I can get this easily enough from within the Form Assistant but any idea how I go about configuring the other field elements?

    I know there’s a setting in the Portal I can use that essentially stops a user from progressing until they’ve completed the email registration part (so they’d get an email and then they’d need to go and confirm the email is theirs) but we have another form on the Portal that requires the user to be logged in and I don’t want this affected by the user needing to go elsewhere, kick on a link, confirm the link and then renavigate back to the form…a bit of a pain for them.

    Any other way that this may work would be great.


  12. Steve says:

    Hi Nicolas,
    I’m setting up a portal app and would like to use the AD B2C and provide access to users only if they have a contact in CDS. Is there a way to authenticate with ADB2C and have the invitation code process?

    • Nicholas Hayduk says:

      Yes, for sure! The invitation code process works regardless of what type of authentication you have.

      When users accept their invitation code, they’ll still need to pick an external identity provider or setup a local account with Azure AD B2C, depending on what options you’ve configured.

  13. Kalpana says:

    Hi Nicholas,

    Thanks for posting this, highly informative. I am currently stuck with a blocker related to the Portals. When I click on the ‘Sign in’ link on the portal, I get the below error and the sign in page does not load. If you have any ideas or tips to solve this, kindly let me know. Thanks.

    Server Error in ‘/’ Application.
    Object reference not set to an instance of an object.
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

    [NullReferenceException: Object reference not set to an instance of an object.]
    Adxstudio.Xrm.Web.c__DisplayClass12_1.b__3(WebPageNode x) in S:\Framework\Adxstudio.Xrm\Web\ContentMapCrmSiteMapProvider.cs:368
    System.Linq.WhereListIterator`1.MoveNext() +80
    System.Linq.Enumerable.FirstOrDefault(IEnumerable`1 source) +242
    Adxstudio.Xrm.Web.c__DisplayClass12_0.b__1(ContentMap map) in S:\Framework\Adxstudio.Xrm\Web\ContentMapCrmSiteMapProvider.cs:366
    Adxstudio.Xrm.Cms.c__DisplayClass20_0`1.b__0() in S:\Framework\Adxstudio.Xrm\Cms\ContentMap.cs:143
    Adxstudio.Xrm.Cms.ContentMap.Using(ContentMapLockType lockType, Action action, String memberName, String sourceFilePath, Int32 sourceLineNumber) in S:\Framework\Adxstudio.Xrm\Cms\ContentMap.cs:195
    Adxstudio.Xrm.Cms.ContentMap.Using(ContentMapLockType lockType, Func`1 action, String memberName, String sourceFilePath, Int32 sourceLineNumber) in S:\Framework\Adxstudio.Xrm\Cms\ContentMap.cs:143
    Adxstudio.Xrm.Web.ContentMapCrmSiteMapProvider.b__12_0() in S:\Framework\Adxstudio.Xrm\Web\ContentMapCrmSiteMapProvider.cs:357
    Adxstudio.Xrm.Web.ContentMapCrmSiteMapProvider.CachePerRequest(String method, String key, Func`1 get) in S:\Framework\Adxstudio.Xrm\Web\ContentMapCrmSiteMapProvider.cs:617
    Adxstudio.Xrm.Web.ContentMapCrmSiteMapProvider.GetRootNodeCore() in S:\Framework\Adxstudio.Xrm\Web\ContentMapCrmSiteMapProvider.cs:343
    System.Web.SiteMapProvider.get_RootNode() +20
    Adxstudio.Xrm.Web.Mvc.Liquid.SiteMapDrop.b__2_0() in S:\Framework\Adxstudio.Xrm\Web\Mvc\Liquid\SiteMapDrop.cs:18
    System.Lazy`1.CreateValue() +708
    System.Lazy`1.LazyInitValue() +399
    Adxstudio.Xrm.Web.Mvc.Html.LiquidExtensions.GetLiquidEnvironment(HtmlHelper html) in S:\Framework\Adxstudio.Xrm\Web\Mvc\Html\LiquidExtensions.cs:186
    Adxstudio.Xrm.Web.Mvc.Html.LiquidExtensions.RenderLiquid(HtmlHelper html, String source, String sourceIdentifier, TextWriter output, IDictionary`2 variables) in S:\Framework\Adxstudio.Xrm\Web\Mvc\Html\LiquidExtensions.cs:433
    Adxstudio.Xrm.Web.Mvc.Html.LiquidExtensions.Liquid(HtmlHelper html, String source, IDictionary`2 variables) in S:\Framework\Adxstudio.Xrm\Web\Mvc\Html\LiquidExtensions.cs:361
    ASP.masterpages_default_master.__RenderTitle(HtmlTextWriter __w, Control parameterContainer) +53
    System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +117
    System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +132
    ASP.masterpages_default_master.__Render__control6(HtmlTextWriter __w, Control parameterContainer) +55
    System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +117
    System.Web.UI.HtmlControls.HtmlTitle.Render(HtmlTextWriter writer) +81
    System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +132
    System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +262
    System.Web.UI.HtmlControls.HtmlHead.RenderChildren(HtmlTextWriter writer) +27
    System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer) +47
    System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +132
    ASP.masterpages_default_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) +332
    System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +117
    System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +132
    System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +262
    System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +132
    System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +262
    System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +75
    System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +132
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +9490

    • Nicholas Hayduk says:

      Hi Kalpana,

      Have you customized the header or footer web templates? I’m wondering if you added Liquid code that gets information about the current web page, which is failing because the Sign In page isn’t a real “web page”, so it would fail looking it up.


  14. Tatiana says:

    Hi Nicholas,

    thanks for the post!
    I can’t seem to find any information regarding my issue.
    I tried registering users (both local and external accounts) and the records are not saved under Contacts entity. When I try to register the same users again – it says the email already taken. System User entity doesn’t contain this information. So where did the user info go? Am I missing something? Or are there any settings that need to be implemented.

    Thank you in advance.

    • Nicholas Hayduk says:

      Hi Tatiana,

      Check to see if there are inactive contacts – those are also considered when checking for duplicate emails.


  15. Ayushi says:

    Hi. I want to configure Email Invitations and redeem code to “Register” on power portals using Azure B2C. I want to pass Email ID as a parameter in the “Signup” URL for power portals. Any ideas how to pass. And users should only be allowed t login with that email id.

    • Nicholas Hayduk says:

      Unfortunately there is no way that I know of to pass the email from CDS to Azure AD B2C. The best I can think of is you can pass the email address back from Azure AD B2C via claims and validate it after the fact.


  16. Andreas says:

    Hi Nick! as always many thanks for sharing.

    in the other hand i have a question, i’m currently using Azure AD to allow our partners to login in our portal, but is not quite clear for me if is better to have the authentication method using Azure AD B2C or if it is finally the same, using Azure AD than A B2C.

    • Nicholas Hayduk says:

      I’m assuming you’ve enabled multi-tenant Azure AD to allow partners to login. That’s fine as long as all of your partners have Azure AD accounts. Using Azure AD B2C opens up more authentication choices (LinkedIn, Microsoft Account, etc.) in case Azure AD isn’t an option for one of your partners.


  17. Mab says:

    Hi Nick,
    Its great article.
    I have a scenario where D365 licensed user is logged into D365 Customer Engagement (Customer Service Hub). There is button in the ribbon on Case form, D365 User clicks on the page and gets redirected to Powerappe/Microsoft Portals. I want user to authenticated automatically using Azure AD with Azure App registration. Requirement is that user should not see or click on sign in button in the portal or get prompted to provide credentials. Instead just authenticated and should be able to see authorised portal contents.
    Is this possible?

    • Nicholas Hayduk says:

      I believe if you make the page require login, and you’ve got a single identity provider set as the default (in this case it would be Azure AD), then this is possible. When the user visits the page that requires authentication, it will redirect to the login page (again, this would be Azure AD), but they’ll already be authenticated, so they’ll get redirected back to the portal.


  18. george says:

    if a CDS user authenticates in powerapps portal, do any of the dataverse security roles still apply ?

    If the CDS “user” is configured to access only team owned records, does this apply to the portal experience as well ? or user will be able to see all records in a given entity when logged in portal ?

    • Nicholas Hayduk says:

      All users on a portal are contacts, not users. Even if someone logs in using Azure AD, they are still related to a contact, not a user. So none of the security roles applied to a user have any effect on the portal.


  19. Eatsam says:

    Is there a way to prevent users to register multiple times with local authentication on?

  20. Hannah Cutler says:

    I have a few questions….

    Background: Our contacts already have a login for a portal and power pages will be a downstream app. We have used a SAML2 for SSO and we do not want to have to use invitation codes or any registration steps (per contact pov).

    1. We keep getting Account/Login/ExternalLoginCallback errors after an external login. Any suggestions?

    Register your external account
    The username “*****@GMAIL.COM” is already taken.
    The Email field is required.
    Provide an email address to complete the external account registration.

    2. Any tips on how to streamline our contact list to be able to sign up without going through any registration steps? (Update all contact records with username, password, any other columns?)

    Many thanks in advance!

    • Nicholas Hayduk says:

      For 1, have you tried setting the “Authentication/UserManager/UserValidator/RequireUniqueEmail” site setting to false?
      For 2, perhaps the “Contact mapping with email” feature would work for you. Assuming the contacts have emails setup, and the email is passed via the SAML provider, then it can automatically map the users. Alternatively, you could pre-create the External Identity rows. This is the table that maps Contacts to their username. It’s a simple table that contains a field for the identity providers (SAML), a lookup to the contact, and a field for their username. So you can design a process that create the External Identity rows if you know what the contact’s username is, using custom development or Power Automate. I talk about the External Identity table in this tip:


Leave a Reply

Your email address will not be published. Required fields are marked *


Engineered Code is a web application development firm and Microsoft Partner specializing in web portals backed by Dynamics 365 & Power Platform. Led by a professional engineer, our team of technology experts are based in Regina, Saskatchewan, Canada.