Power Pages SPA: login redirect
Andrew Elans

Andrew Elans @andrewelans

About: This is my sketchbook where I put things I consider relevant to remember in future and share with others.

Location:
Oslo, Norway
Joined:
Feb 27, 2024

Power Pages SPA: login redirect

Publish Date: Jul 9 '24
3 2

Rev 03 note from 15.05.2025

Article is updated with complete instructions.

Rev 02 note from 06.03.2025

Section Default pages with public access is updated.

Rev 01 note

Some parts of this article are updated 09.08.2024 to conform with the RFC3986 Uniform Resource Identifier (URI) standard.


Login process with Microsoft Entra ID (former Azure AD) identity provider

When a user navigates to any secured page, the Power Pages redirects the user to the sign in page:

https://site.powerappsportals.com/SignIn

Image description

5a0c25a6-4739-ef11-8409-6045bd8728a9 is your Azure AD tenant.

Clicking a button Microsoft Entra ID (Azure AD earlier) on this page will trigger the authentication process redirect which can also be initiated by navigating to the following URL:

https://site.powerappsportals.com/Account/Login/ExternalLogin?provider=https://login.windows.net/5a0c25a6-4739-ef11-8409-6045bd8728a9/&ReturnUrl=%2F

After successful authentication, the user will be taken to the page from the ReturnUrl route. In this case it's the Home page as %2F is the URI-encoded /.

Default pages with public access

Even if you set Page Permissions of all your pages to Authenticated Users web role only, there are some inbuilt pages which will by default be available publicly, ie. for users that are not authenticated:

https://site.powerappsportals.com/_layout/tokenhtml
https://site.powerappsportals.com/_services/about
https://site.powerappsportals.com/SignIn
https://site.powerappsportals.com/Account/Login
https://site.powerappsportals.com/Account/Login/Logoff
https://site.powerappsportals.com/Account/Login/Register
https://site.powerappsportals.com/Account/Login/ExternalAuthenticationFailed
https://site.powerappsportals.com/page-not-found - we will use for MSAL token redirect.

If some other pages are used for the token redirect, MSAL will likely return error block_iframe_reload or hash_empty_error since hash with token is manipulated by the flow.

MSAL recommends:

Our recommended mitigation for this is to set your redirectUri to a blank page that does not implement MSAL when invoking silent APIs.

For this reason the only page we can control and setup web/page templates with msal script is ../page-not-found.

Navigation to a specific hash (fragment) after login

Let's say that I want to go directly to the following route:

https://site.powerappsportals.com/?name=valves&status=active#suppliers

If my user session is active, I may just paste this link to the url bar and see the results I wanted. Since I'm already authenticated, no login redirect is required.

But if I'm not authenticated or my session is expired, the login redirect will be triggered with the following ReturnUrl:

https://site.powerappsportals.com/Account/Login/ExternalLogin?provider=https://login.windows.net/5a0c25a6-4739-ef11-8409-6045bd8728a9/
&ReturnUrl=%2F?name=valves&status=active#suppliers

And... after successful authentication I will be redirected to the Home page instead of the requested route. This happens due to the hash sign and all that comes after it is lost during redirect.

Side note on how the redirect is triggered

If Microsoft Entra ID is enabled as Identity Provider, and when a user who does not have an active session navigates to the portal url, further portal's behaviour depends on one specific setting LoginButtonAuthenticationType.

Go to make.powerapps.com -> Apps -> All tab -> Power Pages administration -> Play -> select Site Settings -> open setting Authentication/Registration/LoginButtonAuthenticationType

When Value field of this setting is blank

The user will be redirected to a page with url https://site.powerappsportals.com/SignIn?ReturnUrl=%2F where he would have to click a button Microsoft Entra ID to proceed with the authentication. You can at this stage open dev tools and note the id of this button that will look like this: https://login.windows.net/5a0c25a6-4739-ef11-8409-6045bd8728a9/.

In this case the portal will load the Header web template.

When Value field of this setting is not blank

You can set the value field of this setting manually to https://login.windows.net/5a0c25a6-4739-ef11-8409-6045bd8728a9/. In this case, the user will be automatically redirected to the authentication form skipping the Header web template.

That's not what we want if we have SPA setup with fragment based routing as explained in this post looking like this: https://site.powerappsportals.com/?name=valves&status=active#suppliers.

#suppliers here represent html content loaded as Suppliers SPA page.

How to prevent # from disappearing

Task

In the ReturnUrl the hash sign # shall be replaced with %23 so that this part of the redirect url:

...ReturnUrl=%2F?name=valves&status=active#suppliers

becomes:

...ReturnUrl=%2F?name=valves&status=active%23suppliers

Steps in short

To do this we need to:

1) ensure that the setting LoginButtonAuthenticationType is blank so that the header is rendered

2) add additional script to the portal's Header web template to replace the # with %23 and trigger the authentication process

Steps in details

Go to make.powerapps.com -> Apps -> All tab -> Power Pages administration (or Portal Management in earlier versions) -> Play

1) Check LoginButtonAuthenticationType settings

select Site Settings -> open setting Authentication/Registration/LoginButtonAuthenticationType -> make sure the value field is blank

2) Add additional script

select Web Templates -> open Header

This will have some liquid and JavaScript code that renders portal's header. We need to add extra script on top, before other content:

Script with comments

<script>
// Example navigation to https://site.powerappsportals.com/?name=valve&sapid=123456#suppliers
const l = location;
const p = l.pathname.toLowerCase();
const shallRedirect = p.includes('signin'); 
// alternatively add || p.includes('login') + some other routes from above
// but exclude Account/Login/Logoff and Account/Login/ExternalAuthenticationFailed
if (shallRedirect) {
    // this logic will run only if user is redirected to the sign in page, and also if he manually goes to /SignIn/ or /Account/Login/ or /Account/Login/Register/
    const hash = l.hash ? l.hash.replace('#', '%23') : ''; // %23suppliers
    const tenant = window["Microsoft"]?.Dynamic365?.Portal?.tenant; // 5a0c25a6-4739-ef11-8409-6045bd8728a9
    // Power Pages create a global object Microsoft with portal details, from here we can extract the tenant id
    // alternatively we can hardcode it
    const search = l.search.replace('?', '&');  // &ReturnUrl=%2F%3Fname%3Dvalve%26sapid%3D123456
    location.replace(l.origin + '/Account/Login/ExternalLogin?provider=https://login.windows.net/' + tenant + '/' + search + hash)
}
// resulted redirect url:
// https://site.powerappsportals.com/Account/Login/ExternalLogin?provider=https://login.windows.net/5a0c25a6-4739-ef11-8409-6045bd8728a9/&ReturnUrl=%2F%3Fname%3Dvalve%26sapid%3D123456%23suppliers
document.currentScript.remove(); // clean up a bit
</script>

<!-- default Header content continues further -->
{% assign defaultlang = settings['LanguageLocale/Code'] | default: 'en-us' %}
Enter fullscreen mode Exit fullscreen mode

Script without comments

<script>
const l = location;
const p = l.pathname.toLowerCase();
const shallRedirect = p.includes('signin'); 
if (shallRedirect) {
    const hash = l.hash ? l.hash.replace('#', '%23') : '';
    const tenant = window["Microsoft"]?.Dynamic365?.Portal?.tenant;
    const search = l.search.replace('?', '&');
    location.replace(l.origin + '/Account/Login/ExternalLogin?provider=https://login.windows.net/' + tenant + '/' + search + hash)
}
document.currentScript.remove();
</script>
Enter fullscreen mode Exit fullscreen mode

Final results as tested

1) User navigates to url https://site.powerappsportals.com/?name=valve&sapid=123456#suppliers
2) The user is redirected to url https://login.microsoftonline.com/... and asked to provide email and password
3) After login is successful, the user is redirected back to this url: https://site.powerappsportals.com/?name=valve&sapid=123456#suppliers

Comments 2 total

  • Lutz
    LutzMay 14, 2025

    Hi. I just run into the same issue as you described. What would be the fix you are talking about?

  • Andrew Elans
    Andrew ElansMay 14, 2025

    the article is updated, hope it will help solving your needs

Add comment