Login redirect in Power Pages SPA with hash and query params
Tags: powerpages, powerplatform, javascript, msal
Published: 2024-07-07 20:09:43

## Single Page Application with Power Pages
Single Page Application implementation in Power Pages is not something Microsoft provides as a part of built-in functionality. In a series of posts I will share how it may be done using Power Pages with optional MicroSoft Authentication Library (MSAL) for direct query of Dataverse, Azure Storage and other services.

## Setup
The Power Pages redirect functionality described in this post works with the following setup:

- Azure Active Directory enabled as Identity Provider
- Local sign in disabled
- Page permissions are set to Authenticated Users Web Role
- In portal.azure.com => App registrations => Authentication => Web Redirect URIs is set to `https://<your.powerappsportal.com>`

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

```
https://<your.powerappsportal.com>/SignIn
```

Clicking a button <kbd>Azure AD</kbd> on this page will start authentication process redirecting first to:

```
https://<your.powerappsportal.com>/Account/Login/ExternalLogin
?provider=https://login.windows.net/<Azure-tenant-ID>/&ReturnUrl=/
```

and then on success to the ReturnUrl. In the above case it's the Home route <kbd>/</kbd>.

## Default pages with public access
Even if you set Page Permissions of all your pages including Home to Authenticated Users only, there are some inbuilt pages which will by default be available publicly. These include:

```
https://<your.powerappsportal.com>/SignIn
https://<your.powerappsportal.com>/Account/Login
https://<your.powerappsportal.com>/Account/Login/Register
```

Navigating to these pages will not trigger the authentication process.

## Routing in Power Pages SPA
I couldn't set up the slash-based routing with Power Pages due to inability to change the server-side functionality, so we will implement the hash-based routing instead. In addition, we will use query parameters with [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API) to maintain: 

1. Back and forward navigation based on user's searching activity
2. Navigation to a specific search result (share a link to a supplier, save in favourites, etc.)

```
Slash-based
https://<your.powerappsportal.com>/suppliers?name=valves&status=active
https://<your.powerappsportal.com>/frame-agreements

Hash-based
https://<your.powerappsportal.com>/#suppliers?name=valves&status=active
https://<your.powerappsportal.com>/#frame-agreements
```




## Navigation to a specific hash after login

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

```
https://<your.powerappsportal.com>/#suppliers?name=valves&status=active
```
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 using this URL:
```
https://<your.powerappsportal.com>/Account/Login/ExternalLogin
?provider=https://login.windows.net/<tenant-ID>/
&ReturnUrl=%2F#suppliers?name=valves&status=active
```
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 is lost during the redirect.

## How to fix

In the redirect URL we need to replace in `ReturnUrl` the hash sign `#` with `%23` (`encodeURIComponent`) so that this part of the redirect url:

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

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

How to do this is in the next post...