Microsoft Entra ID OIDC Authentication
What you will build: A real Entra ID OIDC sign-in flow using App Roles (not groups) — the enterprise-native role assignment model in Azure AD.
Okta vs Entra: Key Difference in Role Model
| Okta (Lab 2) | Entra ID (This Lab) | |
|---|---|---|
| Role source | groups claim (Okta Groups) | roles claim (Entra App Roles) |
| Where roles are defined | Okta Admin → Groups | Azure Portal → App Registration → Manifest |
| Where roles are assigned | User added to Okta Group | User/Group assigned to App Role in Enterprise App |
| Token claim shape | "groups": ["Admin","Everyone"] | "roles": ["Admin"] |
| Transformation needed | Group name → role name mapping | Direct — already uses internal vocabulary |
What Happens End-to-End
Browser Astro Server Entra ID
│ │ │
│── Click "Sign in" ───► │ │
│ │── Build /authorize ──►│
│◄── Redirect to Entra ──│ (PKCE + state) │
│ │ │
│── Login at Entra ─────────────────────────────►│
│◄── Redirect /callback?code=... ────────────────│
│ │ │
│── GET /callback ──────►│ │
│ │── POST /token ─────────►│
│ │◄─ id_token (roles[]) │
│ │ │
│ │── Fetch JWKS ──────────►│
│ │◄─ Microsoft Public Keys │
│ │ │
│ │ Verify RS256 sig │
│ │ Extract roles[] │
│ │ (no mapping needed) │
│ │ Create session JWT │
│◄── Set cookie ─────────│ │
│── GET /dashboard ─────►│ │ Part A — Azure App Registration Setup
Step 1: Sign in to the Azure Portal
Go to: https://portal.azure.com
Sign in with your Microsoft account.
Step 2: Navigate to Entra ID
- In the top search bar, type Microsoft Entra ID
- Click Microsoft Entra ID from the results
Step 3: Record your Tenant ID
On the Entra ID Overview page, you will see:
- Tenant ID (also called Directory ID): A UUID like
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Copy and save this — you will need it for your .env file.
Part B — Create the App Registration
Step 4: Go to App registrations
- In the left sidebar under Entra ID, click App registrations
- Click + New registration
Step 5: Fill in the registration form
| Field | Value |
|---|---|
| Name | AuthMatrix Lab |
| Supported account types | Accounts in this organizational directory only (Single tenant) |
| Redirect URI | Select Web from the dropdown, then enter: http://localhost:3000/api/auth/entra-callback |
Click Register.
Step 6: Record your Application (Client) ID
After registration, you land on the app's Overview page. Copy:
- Application (client) ID:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
This is your ENTRA_CLIENT_ID.
Step 7: Create a Client Secret
- In the left sidebar of your App Registration, click Certificates & secrets
- Click + New client secret
- Fill in:
- Description:
AuthMatrix Lab Secret - Expires: 180 days
- Description:
- Click Add
- IMMEDIATELY copy the
Valuecolumn — it is only shown once!
.env file right now.
This is your ENTRA_CLIENT_SECRET.
Part C — Define App Roles
Entra App Roles are defined directly in the App Registration manifest. This is different from Okta Groups — the roles are part of the application definition itself.
Step 8: Open the App Roles configuration
- In your App Registration left sidebar, click App roles
- Click + Create app role
Step 9: Create the Admin role
Fill in the panel that appears on the right:
| Field | Value |
|---|---|
| Display name | Admin |
| Allowed member types | Users/Groups |
| Value | Admin |
| Description | AuthMatrix system administrator with full access |
| Do you want to enable this app role? | ✅ Yes |
Click Apply.
Step 10: Create remaining roles
Repeat Step 9 three more times for:
| Display Name | Value | Description |
|---|---|---|
Manager | Manager | AuthMatrix operational manager |
Developer | Developer | AuthMatrix technical engineer |
Auditor | Auditor | AuthMatrix read-only compliance auditor |
Value field matters: The Value is what appears in the roles claim of the token. Setting it to Admin, Manager, etc. means the token matches our internal role vocabulary exactly — no mapping table needed (unlike Okta groups).
Part D — Assign Roles to Users via Enterprise Application
App Roles are assigned through the Enterprise Application object, not the App Registration.
Step 11: Navigate to Enterprise Applications
- Go back to Microsoft Entra ID main page
- In the left sidebar, click Enterprise applications
- Search for AuthMatrix Lab
- Click on it
Step 12: Assign yourself to the Admin role
- In the left sidebar of the Enterprise App, click Users and groups
- Click + Add user/group
- Under Users, click None selected
- Search for your own user account name
- Click on your name to select it → click Select
- Under Select a role, click None selected
- Select Admin from the list → click Select
- Click Assign
You should now see your user listed with role Admin.
Part E — Configure API Permissions (for roles claim)
By default, Entra includes the roles claim in access tokens when App Roles are assigned. However, you need to ensure the token is issued with the right audience.
Step 13: Expose an API scope
- Go back to your App Registration (not Enterprise App)
- In the left sidebar, click Expose an API
- Next to Application ID URI, click Add (or it may auto-populate)
- Accept the default URI or set it to
api://authmatrix-lab - Click Save
Step 14: Verify token configuration
- In the left sidebar, click Token configuration
- If you want the
rolesclaim in ID tokens as well (for easier inspection):- Click + Add optional claim
- Select ID
- Check
roles - Click Add
Part F — Configure Your Local Environment
Step 15: Update your .env file
Open c:\GitHub\Learn IDM\.env. Fill in the Entra section:
# —— MICROSOFT ENTRA ID SETTINGS ——————————————————————————————————
ENTRA_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
ENTRA_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
ENTRA_CLIENT_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ENTRA_REDIRECT_URI=http://localhost:3000/api/auth/entra-callback Replace values with what you recorded.
Step 16: Restart the Astro server
npm run dev --workspace=apps/astro-frontend Part G — Test Entra ID Sign-In
Step 17: Open the login page
Navigate to: http://localhost:3000/login
Step 18: Click "Sign in with Microsoft Entra ID"
What happens on the server:
/api/auth/entra-logingenerates PKCEcode_verifier+code_challenge- Sets
entra_pkce_verifierandentra_oauth_stateHttpOnly cookies - Redirects browser to Entra authorize endpoint
Step 19: Authenticate at Microsoft
- Enter your Microsoft account email and password
- Complete MFA if prompted
- If asked "AuthMatrix Lab is requesting access to..." — click Accept
Step 20: Observe the callback processing
The Astro server's entra-callback.ts runs:
- ✅ Validates
statecookie (CSRF protection) - ✅ POSTs to
https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token - ✅ Receives
id_token(RS256 signed by Microsoft) - ✅ Fetches JWKS from Microsoft and Verifies RS256 signature
- ✅ Extracts
roles[]claim — no mapping needed - ✅ Creates normalized session JWT → sets
auth_tokenHttpOnly cookie - ✅ Redirects to
/dashboard
Step 21: Verify on the Dashboard
- Identity Provider badge: 🔸 Microsoft Entra
- Subject (sub): A UUID like
a1b2c3d4-... - Email: Your Microsoft account email
- Assigned Roles:
Admin - Granted Permissions: All Admin permissions
Part H — Test Role-Based Access
Step 22: Test API endpoints
On the Dashboard API Tester, click each endpoint. Since you're assigned the Admin App Role, all should return 200.
Step 23: Change your role assignment (test Auditor)
- Go back to Azure Portal → Entra ID → Enterprise Applications → AuthMatrix Lab
- Click Users and groups
- Click on your existing assignment → click Edit assignment
- Under Select a role, choose Auditor instead
- Click Assign
- Log out of AuthMatrix → sign back in with Entra
- Dashboard should now show role
Auditor - Clicking
DELETE /audit→ returns 403 Forbidden ✅ (Auditor can read, not delete)
Part I — Token Inspection
Step 25: Inspect raw Entra ID token (Advanced)
To see the actual RS256 token Microsoft issued:
- Open browser DevTools → Network tab
- Sign in with Entra
- Find the request to
/api/auth/entra-callbackin the Network tab
Step 26: Compare with your session token
In the dashboard JWT Inspector, your session token (what's stored in the cookie) shows:
{
"iss": "https://authmatrix.local",
"idp": "entra",
"roles": ["Admin"],
"permissions": ["read:users", "write:users", ...]
} authmatrix.local issuer. The backend API only trusts this internal token — it never receives nor validates Entra tokens directly.
✅ Lab 3 Complete — Validation Checklist
- Signed into Azure Portal and found Tenant ID
- Created App Registration
AuthMatrix Labwith correct redirect URI - Created and saved Client Secret
- Defined 4 App Roles: Admin, Manager, Developer, Auditor
- Assigned own user to Admin role via Enterprise Application
- Exposed API and set Application ID URI
- Filled in
.envwith ENTRA_TENANT_ID, ENTRA_CLIENT_ID, ENTRA_CLIENT_SECRET - Login page shows "✅ Configured" for Entra
- Clicked "Sign in with Microsoft Entra ID" → redirected to Microsoft login
- Authenticated → returned to dashboard with 🔸 Entra badge
- Dashboard shows correct email,
roles: ["Admin"], all permissions - Changed App Role to Auditor → confirmed 403 on DELETE /audit
- Compared raw Entra
roles[]claim with normalized session token