This guide walks through setting up a static website on Azure Static Web Apps, authenticated against your organisation's Microsoft Entra ID tenant, deployed via GitHub Actions, with per-branch preview environments. No custom authentication code required.
Create a new private repository on GitHub. The structure will look like this:
my-internal-site/
src/
index.html
style.css
staticwebapp.config.json
.github/
workflows/
deploy.yml
src/ as the app directory, but you can use any folder name or even the repository root.
Create a minimal page to verify the deployment works.
src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Internal Site</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Internal Site</h1>
<p>If you can see this, you are authenticated.</p>
<p><a href="/.auth/logout">Sign out</a></p>
</body>
</html>
src/style.css
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
max-width: 600px;
margin: 2rem auto;
padding: 0 1rem;
color: #333;
}
This is the key file. Create staticwebapp.config.json in the root of the repository (or in your app directory — SWA will find it).
staticwebapp.config.json
{
"auth": {
"identityProviders": {
"customOpenIdConnectProviders": {
"aad": {
"registration": {
"clientIdSettingName": "AAD_CLIENT_ID",
"clientCredential": {
"clientSecretSettingName": "AAD_CLIENT_SECRET"
},
"openIdConnectConfiguration": {
"wellKnownOpenIdConfiguration":
"https://login.microsoftonline.com/YOUR_TENANT_ID/v2.0/.well-known/openid-configuration"
}
},
"login": {
"nameClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
"scopes": ["openid", "profile", "email"]
}
}
}
}
},
"routes": [
{
"route": "/.auth/login/github",
"statusCode": 404
},
{
"route": "/.auth/login/twitter",
"statusCode": 404
},
{
"route": "/*",
"allowedRoles": ["authenticated"]
}
],
"responseOverrides": {
"401": {
"redirect": "/.auth/login/aad",
"statusCode": 302
}
}
}
What this configuration does:
auth.identityProviders — Registers your Entra ID tenant as a custom OpenID Connect provider. The wellKnownOpenIdConfiguration URL contains your tenant ID, which restricts login to that specific tenant. Personal Microsoft accounts cannot sign in.routes — The /* wildcard route requires the authenticated role for all pages. The two GitHub/Twitter routes return 404 to disable the pre-configured providers.responseOverrides — When an unauthenticated user hits a 401, they are redirected to the Entra ID login page automatically.YOUR_TENANT_ID with your actual Entra ID tenant ID (a GUID). You can find it in the Azure Portal under Microsoft Entra ID > Overview > Tenant ID.
You need an app registration so SWA can authenticate users against your tenant.
1 Go to Azure Portal > Microsoft Entra ID > App registrations > New registration.
2 Fill in:
my-internal-site-authhttps://<your-swa-hostname>/.auth/login/aad/callback3 After registration, note the Application (client) ID.
4 Go to Certificates & secrets > New client secret. Create a secret, and copy its Value immediately (it is shown only once).
5 (Optional) To restrict access to specific users or groups: go to Enterprise applications, find your app by its object ID, go to Properties, and set “Assignment required?” to Yes. Then assign the users or groups under Users and groups.
1 Go to Azure Portal > Create a resource > Static Web App.
2 Fill in:
my-internal-sitemain branch./src3 Click Review + Create. Azure will create the SWA and commit a GitHub Actions workflow to your repository.
# Create resource group
az group create \
--name rg-internal-site \
--location westeurope
# Create the Static Web App
az staticwebapp create \
--name my-internal-site \
--resource-group rg-internal-site \
--source https://github.com/YOUR_ORG/my-internal-site \
--branch main \
--app-location "/src" \
--login-with-github \
--sku Standard
After creation, note the default hostname (e.g., purple-sand-0ab1c2d3e.azurestaticapps.net).
https://<your-default-hostname>/.auth/login/aad/callback.
The staticwebapp.config.json references two setting names: AAD_CLIENT_ID and AAD_CLIENT_SECRET. Set these in the SWA resource.
Go to your Static Web App > Configuration > Application settings > Add:
AAD_CLIENT_ID = your Entra ID application (client) IDAAD_CLIENT_SECRET = the client secret value from step 5.4az staticwebapp appsettings set \
--name my-internal-site \
--resource-group rg-internal-site \
--setting-names \
AAD_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
AAD_CLIENT_SECRET=your-client-secret-value
When you create the SWA via the portal with GitHub linked, Azure auto-generates a workflow file. If you prefer to manage it manually (or used the CLI), create the following:
.github/workflows/deploy.yml
name: Deploy to Azure Static Web Apps
on:
push:
branches:
- main
- dev
- 'feature/**'
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- main
jobs:
build_and_deploy:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
runs-on: ubuntu-latest
name: Build and Deploy
steps:
- uses: actions/checkout@v4
- name: Deploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: "upload"
app_location: "/src"
output_location: ""
production_branch: "main"
close_pull_request:
if: github.event_name == 'pull_request' && github.event.action == 'closed'
runs-on: ubuntu-latest
name: Close PR Environment
steps:
- name: Close
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
action: "close"
Key points:
AZURE_STATIC_WEB_APPS_API_TOKEN — A deployment token. Find it in the Azure Portal under your SWA > Overview > Manage deployment token. Add it as a repository secret in GitHub (Settings > Secrets and variables > Actions).production_branch: "main" — Pushes to main deploy to production. Pushes to any other branch deploy to a preview environment.close_pull_request job cleans up ephemeral PR environments when the PR is closed or merged.With the workflow above, SWA automatically creates preview environments for non-production branches.
| Branch / Event | Environment | URL pattern |
|---|---|---|
main |
Production | purple-sand-0ab1c2d3e.azurestaticapps.net |
dev |
Branch preview | purple-sand-0ab1c2d3e-dev.westeurope.azurestaticapps.net |
feature/xyz |
Branch preview | purple-sand-0ab1c2d3e-feature-xyz.westeurope.azurestaticapps.net |
| Pull request #42 | PR preview | purple-sand-0ab1c2d3e-42.westeurope.azurestaticapps.net |
dev.mysite.com to them. Only the production environment supports custom domains. If custom subdomains per branch are critical, consider deploying separate SWA instances per environment or using Azure Front Door as a routing layer (at additional cost).
Each preview environment has a different hostname, so the Entra ID callback URL will differ. You need to add each preview environment's callback URL to your app registration's Redirect URIs. You can add a wildcard-style entry or add them as needed:
https://<hostname>-dev.<region>.azurestaticapps.net/.auth/login/aad/callbackAlternatively, add all expected preview URLs upfront in the Entra ID app registration.
To use your own domain (e.g., internal.yourcompany.com) for the production environment:
1 In the Azure Portal, go to your SWA > Custom domains > Add.
2 Enter your domain name.
3 Azure will ask you to create a CNAME record pointing to your SWA's default hostname, or a TXT record for domain validation (if using an apex domain, you need an ALIAS/ANAME record or Azure DNS).
4 Once validated, Azure automatically provisions a free SSL certificate.
5 Update your Entra ID app registration Redirect URI to use the custom domain:
https://internal.yourcompany.com/.auth/login/aad/callback
main and wait for the GitHub Action to complete./.auth/me to see the authenticated user's claims (JSON).login.microsoftonline.com/common instead of your tenantThis means the wellKnownOpenIdConfiguration URL is wrong or missing. Ensure it contains your specific tenant ID, not common or organizations.
Check that AAD_CLIENT_ID and AAD_CLIENT_SECRET are set correctly in the SWA application settings. Verify the Redirect URI in the Entra ID app registration matches exactly.
The preview environment has a different hostname. Add its callback URL to the Entra ID app registration's Redirect URIs.
The Redirect URI in the Entra ID app registration does not match the callback URL. Ensure it is https://<exact-hostname>/.auth/login/aad/callback.
Custom OpenID Connect providers (including tenant-specific Entra ID) require the Standard plan. The free plan only supports the pre-configured providers which allow any Microsoft account.
my-internal-site/
.github/
workflows/
deploy.yml
src/
index.html
style.css
staticwebapp.config.json
That is the entire setup — three config files, two content files, and zero lines of authentication code. The Microsoft platform handles login, token validation, session management, and access control.
Last updated: April 2026