👤 Manage Users
STORE_USERS=false — user records not persisted
1
Create an App Registration (not Enterprise Application)
▾
⚠
Do not use Enterprise Applications → Single sign-on → SAML.
Go to App registrations instead. The Enterprise Application is created automatically when you register the app — you only use it later for user assignment.
In Azure Portal go to Microsoft Entra ID → App registrations → New registration.
- Set a Name (e.g. uptime-saas)
- Under Supported account types choose Accounts in this organizational directory only
- Under Redirect URI select platform Web and enter your callback URL:
https://yourdomain.com/auth/callback
The Redirect URI must be Web platform (not SPA, not Mobile).
It must exactly match
AZURE_REDIRECT_URI in your .env — including https:// vs http:// and no trailing slash.
- Click Register
- On the Overview page, copy both the Application (client) ID and the Directory (tenant) ID
✓
Application (client) ID → this is your
Directory (tenant) ID → this is your
These are different values. Do not mix them up.
AZURE_CLIENT_IDDirectory (tenant) ID → this is your
AZURE_TENANT_IDThese are different values. Do not mix them up.
2
Create a Client Secret
▾
In your App Registration go to Certificates & secrets → Client secrets → New client secret.
- Add a description (e.g. uptime-saas 2026) and choose an expiry
- Click Add
- Immediately copy the Value column — it is only shown once
Copy the Value, not the Secret ID. The Value is the long string like
abc~defGH....
If you lose it, delete the secret and create a new one.
3
Configure API Permissions
▾
In your App Registration go to API permissions → Add a permission → Microsoft Graph → Delegated permissions.
- Search and add:
openid,profile,email,User.Read - Click Add permissions
- Click Grant admin consent for [your org] and confirm — the status column should show green checkmarks
4
User Assignment via Enterprise Application (optional)
▾
Azure automatically creates an Enterprise Application entry when you register the app. Use it only for controlling who can sign in — not for protocol configuration.
- Go to Microsoft Entra ID → Enterprise applications and find your app
- Click Properties → set Assignment required to Yes to restrict access to specific users/groups
- Go to Users and groups → Add user/group to grant access
Do not touch the Single sign-on section in the Enterprise Application.
Leave it as-is or set to OIDC if prompted. Configuring SAML here will NOT affect this app
and will only cause confusion.
With Assignment required = No (default), any user in your tenant can sign in.
5
Configure Your .env File
▾
Copy .env.example to .env and fill in your values:
# From Azure Portal → App Registration → Overview
AZURE_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # Directory (tenant) ID
AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # Application (client) ID
# From Certificates & secrets → Client secrets → Value column
AZURE_CLIENT_SECRET=your~client~secret~value
# Must exactly match the Redirect URI registered in Azure (Web platform)
AZURE_REDIRECT_URI=https://uptime.dmsk.duckdns.org/auth/callback
# Strong random string for session encryption
SESSION_SECRET=replace-with-64-random-chars
- Save as
.envin the project root - Restart:
npm start - Check server console — it should print
[auth] OIDC client ready
6
Test & Diagnose
▾
After restarting the server:
- Visit /auth/debug — confirms config is loaded correctly without exposing secrets
- Open /login and click Sign in with Microsoft
- Sign in with your enterprise credentials
- On success you are redirected to the dashboard
If you see a "Token key validation failed" error, it usually means:
- The SAML SSO was configured on the Enterprise App — ignore it, it doesn't affect OIDC
AZURE_TENANT_IDis set to the Application ID instead of the Directory ID- The Redirect URI in Azure doesn't exactly match
AZURE_REDIRECT_URIin.env
First-time sign-in creates a user record. Subsequent logins reuse it.
1
Create an Enterprise Application with SAML SSO
▾
Go to Azure Portal → Microsoft Entra ID → Enterprise applications → New application → Create your own application.
- Name it (e.g. uptime-saas-saml), select Integrate any other application you don't find in the gallery
- Click Create
- Go to Single sign-on → SAML
Unlike OIDC which uses App Registrations, SAML is configured directly on the Enterprise Application.
2
Configure Basic SAML Settings
▾
In Basic SAML Configuration set:
https://yourdomain.com/auth/saml/metadata
Must exactly match
SAML_ISSUER in .envhttps://yourdomain.com/auth/saml/callback
Must exactly match
SAML_CALLBACK_URL in .env
The Reply URL is a POST endpoint — Azure will POST the SAML assertion to it.
This is different from OIDC which uses a GET redirect.
3
Download the Certificate and Copy Login URL
▾
In SAML Certificates:
- Click Download next to Certificate (Base64) — save the
.cerfile - Open it in a text editor — copy everything between
-----BEGIN CERTIFICATE-----and-----END CERTIFICATE-----(the Base64 block only) - Paste this as
SAML_CERTin your .env (the app strips headers automatically)
In Set up [your app] (step 4 in Azure's UI):
- Copy the Login URL → set as
SAML_ENTRY_POINT
4
Configure .env for SAML
▾
# SAML 2.0 mode — use INSTEAD of AZURE_CLIENT_ID/SECRET/TENANT_ID
SAML_ENTRY_POINT=https://login.microsoftonline.com/{tenant-id}/saml2
SAML_ISSUER=https://yourdomain.com/auth/saml/metadata
SAML_CALLBACK_URL=https://yourdomain.com/auth/saml/callback
SAML_CERT=MIIxxxxx...base64cert...xxxxx=
# Required: install SAML packages
# npm install passport passport-saml
Do not set AZURE_CLIENT_ID when using SAML — the app detects which mode to use based on which env vars are present.
If both are set, OIDC takes precedence.
5
Assign Users and Test
▾
- In the Enterprise Application → Users and groups → Add user/group to grant access
- Set Properties → Assignment required → Yes to restrict to assigned users only
- Restart the server:
npm start - Visit /login → click Sign in with Microsoft (SAML)
- Verify metadata is served at /auth/saml/metadata
First-time sign-in creates a local user record (unless
STORE_USERS=false).
Subsequent logins reuse the existing record.