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.
[…] post Power Apps Portals: Authentication Overview appeared first on Engineered […]
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.
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.
Nick
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.
Hi Iyke,
I’d recommend using a combination of Liquid and JavaScript to accomplish this – see this blog post:
https://www.engineeredcode.com/blog/powerapps-portals-liquid-and-javascript-better-together
Nick
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?
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:
https://docs.microsoft.com/en-us/powerapps/maker/portals/oauth-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.
Nick
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?
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.
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?
Have you followed the steps available at https://docs.microsoft.com/en-us/powerapps/maker/portals/configure/configure-saml2-settings? It should just be a case of creating the necessary Site Settings.
Sorry, wish I could help more but I’ve never setup SAML with a portal, and to be honest, I hope to never have to!
I’ve been involved in a few projects that used it, but it was other people who had to deal with getting it setup.
Nick
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)
Hey Derek,
Unfortunately the “official” notice was removed – the closest from Microsoft is on https://docs.microsoft.com/en-us/powerapps/maker/portals/configure/migrate-identity-providers 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.
Nick
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)
Thanks,
Derek
The good news is Microsoft has improved the process as part of the 2020 Wave 1 release:
https://docs.microsoft.com/en-us/powerapps/maker/portals/configure/use-simplified-authentication-configuration
But you’re right – the documentation can quickly get out of date – see this: https://crmtipoftheday.com/1346/where-to-find-azure-ad-b2c-metadata-endpoint-for-this-policy/
Nick
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
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.
Nick
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!
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.
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.
Thanks!
Hi!
The Portals website code generates those parameters. It might be possible to duplicate the logic, but I’ve never done that myself. You can see how it is done by looking at the ConfirmEmailRequest (line 535) in the source code release:
https://github.com/Adoxio/xRM-Portals-Community-Edition/blob/77dc1fae0f46c18453dc253ab0060230c73d60cb/Samples/MasterPortal/Areas/Account/Controllers/ManageController.cs
Is there a reason you’re not turning email confirmation off if you don’t want it in some cases? This is controlled via the Authentication/Registration/EmailConfirmationEnabled site setting.
Nick
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?
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.
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
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.
Nick
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.
Hi Tatiana,
Check to see if there are inactive contacts – those are also considered when checking for duplicate emails.
Nick
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.
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.
Nick
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.
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.
Nick
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?
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.
Nick
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 ?
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.
Nick
Is there a way to prevent users to register multiple times with local authentication on?
With local auth, usually we recommend using email address for authentication. Then you can require users to have a unique email address, using the settings described here:
https://learn.microsoft.com/en-us/power-pages/security/authentication/configure-site#configure-general-authentication-settings
Nick
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.
Email
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!
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: https://www.youtube.com/watch?v=sktetGqwTGM
Nick