-
Notifications
You must be signed in to change notification settings - Fork 1
Self Hosted Deployment
The PIMActivation Portal can be deployed into your own Azure tenant in a single operation using the included Bicep template. This page is the long-form walkthrough; the README has the short version.
Source of truth:
Portal/deploy/bicep/portal-selfhosted.bicep.Portal/deploy/azuredeploy.jsonis auto-generated by the Sync Deployment Templates workflow.
- An Azure Static Web App serving the portal SPA.
- A user-assigned managed identity scoped narrowly as Website Contributor on the SWA only (so the deployment script can read the SWA deployment token via
listSecrets()— no broader resource-group access). - A customer-owned storage account that caches the downloaded portal source archive for fallback redeploys.
- A deployment script that downloads, configures, and deploys the portal in one shot, and attempts to add the generated SPA redirect URIs to your Entra app registration.
- An Azure subscription and a resource group you can deploy into.
- An existing single-tenant Entra ID SPA app registration for the portal. See App Registration Setup. Azure deployment scripts cannot complete interactive sign-in to Microsoft Graph reliably, so the app registration must exist before deployment and its application (client) ID is a required parameter.
-
Tenant-wide admin consent for the delegated permissions if your tenant requires it. The deployment outputs an
adminConsentUrlyou can use after deployment.
Click Deploy to Azure in the README — or use the URL directly:
https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FNoble-Effeciency13%2FPIMActivation-Portal%2Fmain%2FPortal%2Fdeploy%2Fazuredeploy.json
You will be prompted for the parameters below.
| Parameter | Required | Default | Description |
|---|---|---|---|
applicationClientId |
yes | — | Application (client) ID of an existing single-tenant Entra ID SPA app registration. |
tenantId |
no | subscription().tenantId |
Tenant ID. Defaults to the current subscription tenant. |
customDomain |
no | '' |
Optional custom domain (e.g. pim.contoso.com). Included in the redirect URI auto-merge attempt. The Static Web App custom domain must still be bound manually after DNS validates. |
portalSourceBranch |
no | main |
Branch to download. Each deployment pulls the latest commit at deployment time. |
portalSourceArchiveUrl |
no | '' |
Override the source download with a publicly reachable ZIP. The archive must contain Portal/index.html. |
deploymentScriptRunId |
no | utcNow('yyyyMMddHHmmss') |
Forces the deployment script to rerun and gives each run a fresh resource name to avoid Azure Files sharing violations on retry. |
location |
no | resourceGroup().location |
Azure region. |
staticWebAppSku |
no | Free |
Free or Standard. |
resourceTag |
no | PIMActivation |
Tag applied to all created resources. |
- Downloads the portal source ZIP from
portalSourceBranch(or yourportalSourceArchiveUrl). - Caches the archive in the customer-owned storage account for fallback redeploys.
- Locates
Portal/index.htmlinside the extracted archive. -
Injects your
applicationClientIdandtenantIdintoPortal/js/msal-config.jsviasedreplacement of the__PORTAL_CLIENT_ID__and__PORTAL_TENANT_ID__placeholders. - Verifies that no placeholders remain after injection (fails the deployment if any are left).
- Copies
index.html,staticwebapp.config.json, and thecss,js,imagesfolders into a deployment payload directory. - Reads the SWA deployment token via
az staticwebapp secrets list. - Installs the SWA CLI (
@azure/static-web-apps-cli) and uploads the payload. - Attempts to merge the generated default hostname (and
customDomain, if supplied) into the app registration's SPA redirect URIs through Microsoft Graph.
| Output | Use |
|---|---|
portalUrl |
URL of the deployed Static Web App. |
staticWebAppName |
Name of the SWA resource. |
redirectUris |
SPA redirect URIs to add to the app registration if the script could not auto-add them. |
clientId |
Echoes the client ID you supplied. |
customDomainNextStep |
If you supplied customDomain, the CNAME and binding instructions. |
adminConsentUrl |
Tenant-wide admin consent URL for the app registration. |
sourceArchiveCache |
The customer-owned blob that holds the cached source archive. |
nextStep |
A reminder to verify redirect URIs and grant admin consent if needed. |
-
Open
portalUrl. You should see the portal sign-in screen. -
Verify redirect URIs. If the deployment log shows a Microsoft Graph permission warning, copy the
redirectUrisoutput and add them under your app registration's Authentication blade → Single-page application platform. -
Grant admin consent if your tenant requires it, using the
adminConsentUrloutput. -
(Optional) Bind your custom domain. If you supplied
customDomain, followcustomDomainNextStep: create a CNAME pointing your domain at the SWA default hostname, then add and validate the custom domain on the Static Web App resource.
The deployment script uses a fresh resource name on each run (driven by deploymentScriptRunId), which sidesteps the Azure Files sharing violations that can otherwise block retries. Reruns therefore pick up the newest commit on portalSourceBranch automatically.
If the GitHub branch download fails and portalSourceArchiveUrl was not supplied, the script falls back to the cached source archive in the customer-owned storage account.
If you fork the repository privately, GitHub returns 404 to the unauthenticated deployment script. To deploy from a private fork, build a ZIP of the repository (PowerShell Compress-Archive works) and upload it somewhere publicly reachable — for example a public Azure Blob with a short-lived SAS URL — then pass that URL as portalSourceArchiveUrl. The archive must contain Portal/index.html somewhere inside it.
Check the deployment script logs for placeholder injection failed. If the placeholders were not replaced, the SPA can't construct a valid MSAL config. Re-run the deployment with the same parameters.
The deployment identity could not update the app registration. Add the redirectUris output manually under Authentication → Single-page application in your app registration.
Almost always one of:
- The user does not actually have a PIM-eligible assignment for the role.
- The tenant requires admin consent for one of the delegated scopes — use the
adminConsentUrloutput. - An Conditional Access policy requires an auth context the portal hasn't been told about (open the role's policy in Entra and check Activation requirements).
After binding the custom domain on the Static Web App, make sure that domain is also listed under your app registration's SPA redirect URIs. The deployment script attempted to add it; if the attempt failed, add it manually.
The redirect URI was not added to the app registration. Add the value of the redirectUris output (or the deployed SWA URL with no trailing slash) under Authentication → Single-page application.
Browser favicon caches are sticky. Open in a private window or clear site data to validate.
See also Troubleshooting for runtime issues.