Authentication & Entra ID
Relevant source files
The following files were used as context for generating this wiki page:
Authentication in this project is implemented using Microsoft Entra ID (formerly Azure AD) as the primary identity provider. The system utilizes a decoupled architecture where the frontend (React/TanStack) handles user sessions and OAuth flows via Auth.js, while the backend (.NET API) validates JWT tokens issued by Entra ID.
The implementation ensures secure access to protected resources, supports automatic token refreshing on the client-side, and utilizes a "Just-In-Time" provisioning mechanism to sync authenticated Entra ID users with the local application database.
Sources: CHANGELOG.md:10, packages/web/src/lib/auth.server.ts:4-8, packages/api/Common/Extensions/AuthExtensions.cs:12-15
System Architecture
The authentication system is split between the Web package and the API package, communicating via OAuth 2.0 and JWT.
Frontend Authentication (Web)
The frontend uses @auth/core with the Microsoft Entra ID provider. It manages the OAuth flow, session persistence using JWT-based cookies, and token refresh logic.
- Provider: Microsoft Entra ID v2.0 endpoint.
- Session Strategy: JWT stored in HTTP-only cookies.
- Scope:
openid profile email offline_accessand a custom API scopeapi://{CLIENT_ID}/access_as_user.
Sources: packages/web/src/lib/auth.server.ts:11-13, packages/web/src/lib/auth.server.ts:54-61
Backend Authentication (API)
The backend uses standard ASP.NET Core Authentication and Authorization middleware configured for JWT Bearer tokens.
- Authority:
https://login.microsoftonline.com/{tenantId}/v2.0. - Validation: Validates the Audience (
api://{clientId}) and Issuer. - Claims: Maps inbound claims to local user identities, specifically extracting name and UPN/email for user identification.
Sources: packages/api/Common/Extensions/AuthExtensions.cs:22-35, packages/api/Modules/Users/UserEndpoints.cs:17-23
Authentication Flow
The following sequence diagram illustrates the interaction between the User, Web Client, Microsoft Entra ID, and the API during a sign-in and protected resource request.
The flow utilizes Auth.js on the frontend to manage the complex OAuth handshake.
Sources: packages/web/src/lib/auth-client.ts:38-42, packages/web/src/lib/auth.server.ts:54-70, packages/api/Modules/Users/UserEndpoints.cs:15-30
User Provisioning & Session Management
Just-In-Time Provisioning
When a user authenticates via /api/users/me, the system checks if the user exists in the local database by their email (extracted from the preferred_username, upn, or email claim). If the user does not exist, they are automatically provisioned with a default User role.
Sources: packages/api/Modules/Users/UserEndpoints.cs:17-27, packages/api/Modules/Users/UserService.cs:161-179
Token Refresh Logic
To maintain sessions without requiring frequent re-logins, the auth.server.ts includes logic to refresh the Entra ID access token using a refresh token when the current token is within 60 seconds of expiration.
// packages/web/src/lib/auth.server.ts:25-30
async function refreshAccessToken(refreshToken: string) {
const res = await fetch(`https://login.microsoftonline.com/${env.AUTH_TENANT_ID}/oauth2/v2.0/token`, {
method: 'POST',
body: new URLSearchParams({
client_id: env.AUTH_CLIENT_ID,
grant_type: 'refresh_token',
refresh_token: refreshToken,
scope: SCOPE,
}),
});
// ... returns new tokens
}
Sources: packages/web/src/lib/auth.server.ts:25-45, packages/web/src/lib/auth.server.ts:103-118
Configuration
The authentication system requires specific environment variables and configuration keys to function.
Environment Variables (Web)
| Variable | Description |
|---|---|
AUTH_CLIENT_ID | The Application (client) ID from Entra ID portal. |
AUTH_CLIENT_SECRET | The client secret generated in Entra ID. |
AUTH_TENANT_ID | The Directory (tenant) ID. |
AUTH_SECRET | A secret used to encrypt the Auth.js session cookie. |
Sources: packages/web/src/lib/auth.server.ts:55-57, packages/web/src/lib/auth.server.ts:133-143
API Configuration
| Key | Type | Default | Description |
|---|---|---|---|
Auth:TenantId | string | - | The Entra ID Tenant ID. |
Auth:ClientId | string | - | The Entra ID Client ID. |
Auth:Disabled | boolean | false | If true, authentication is bypassed (dev only). |
Sources: packages/api/Common/Extensions/AuthExtensions.cs:16-20, packages/api/Common/Extensions/AuthExtensions.cs:40-45
Key Components
AuthExtensions.cs
A static extension class for WebApplicationBuilder and WebApplication that encapsulates the JWT Bearer configuration. It configures the JwtBearerOptions.Authority and TokenValidationParameters.
Sources: packages/api/Common/Extensions/AuthExtensions.cs:8-49
auth.server.ts
Handles the server-side part of the Auth.js integration. It defines the authConfig, including custom profile mapping to strip large image data from the token (to keep cookie size under 4KB) and the JWT callback for handling token expiration.
Sources: packages/web/src/lib/auth.server.ts:52-125
auth-client.ts
Provides client-side utilities for the React application, including the signInWithMicrosoft function and the useSession React hook for accessing the current user's state.
Sources: packages/web/src/lib/auth-client.ts:38-42, packages/web/src/lib/auth-client.ts:51-72
Conclusion
The Authentication system provides a robust integration with Microsoft Entra ID, balancing security with user experience. By utilizing Auth.js on the frontend and standard middleware on the backend, it achieves a clean separation of concerns while ensuring that identity is verified across every layer of the application.