This chapter covers Microsoft Entra ID (formerly Azure Active Directory) authentication from a developer's perspective, focusing on how to integrate identity management into applications using OAuth 2.0 and OpenID Connect. For the AZ-204 exam, authentication and authorization topics account for approximately 15-20% of the questions, with Entra ID being the core identity service. You will learn how to register applications, configure permissions, acquire tokens, and handle authentication flows securely.
Jump to a section
Imagine a large embassy building with multiple entrances. Each visitor must first present their passport at the main gate (Microsoft Entra ID). The security officer checks the passport against a global database of approved visitors. If the passport is valid, the officer issues a temporary badge with a photo, expiration time, and allowed zones (access token). The visitor then enters the embassy and can access only the rooms listed on the badge. If they try to enter a restricted area, a guard at that door scans the badge and denies entry unless the badge explicitly includes that zone. The badge expires after a set number of hours, so the visitor must return to the main gate to get a new one (token refresh). If the passport itself is revoked (user disabled), the main gate will refuse to issue any new badges, but existing badges remain valid until they expire. This is why tokens have short lifetimes—to ensure revocation is enforced quickly. The embassy also has a separate process for visitors who need to enter multiple times without re-authentication: they get a long-term pass (refresh token) that can be exchanged for a new temporary badge without re-presenting the passport. However, if the long-term pass is stolen, it can be revoked centrally, preventing further badge issuance.
What is Microsoft Entra ID and Why Does It Exist?
Microsoft Entra ID is a cloud-based identity and access management service that provides authentication and authorization for applications, devices, and users. It evolved from on-premises Active Directory to address the needs of modern, cloud-first applications. Instead of each application managing its own user database and password hashing, Entra ID acts as a centralized identity provider (IdP). This allows users to sign in once (Single Sign-On) and access multiple applications without re-entering credentials.
For developers, Entra ID provides: - Authentication: Verifying who the user is via protocols like OAuth 2.0 and OpenID Connect. - Authorization: Determining what the user can do via tokens that contain claims. - Application Registration: Registering apps to obtain client IDs and secrets. - Token Management: Issuing access tokens, ID tokens, and refresh tokens.
How Authentication Works Internally – The OAuth 2.0 Authorization Code Flow
The most common flow for server-side applications is the Authorization Code Flow with PKCE (Proof Key for Code Exchange). Here is the step-by-step mechanism:
User initiates sign-in: The client app redirects the user to Entra ID's /authorize endpoint with parameters including client_id, response_type=code, redirect_uri, scope, and code_challenge (for PKCE).
User authenticates: Entra ID displays the sign-in page. The user enters credentials. If multi-factor authentication is required, the user completes that step.
Authorization code returned: After successful authentication, Entra ID redirects the browser back to the redirect_uri with an authorization code in the query string.
Client exchanges code for tokens: The client sends a POST request to /token endpoint with the authorization code, client_id, client_secret (if confidential client), redirect_uri, and code_verifier (the original secret from PKCE).
Tokens issued: Entra ID validates the code and verifier, then returns an access token, an ID token (JWT), and optionally a refresh token.
Client uses access token: The client includes the access token in the Authorization header of API requests. The resource API validates the token's signature, issuer, audience, and expiration.
Token expiration and refresh: When the access token expires (default 60-90 minutes), the client uses the refresh token to get a new access token without user interaction.
Key Components, Values, Defaults, and Timers
Access Token: A JWT that contains claims about the user and the application. Default lifetime: 60-90 minutes (configurable via conditional access policies).
ID Token: A JWT that contains identity claims about the user (sub, name, email, etc.). Used by the client to identify the user.
Refresh Token: Opaque string (not JWT) used to obtain new access tokens. Default lifetime: 14 days for single-page apps, up to 90 days for native apps (configurable). Refresh tokens can be revoked.
Client ID: A GUID that identifies your application to Entra ID.
Client Secret: A string used by confidential clients to prove their identity. Should be stored securely (e.g., Azure Key Vault).
Redirect URI: The endpoint where Entra ID sends the authorization code or tokens. Must be registered in the app registration.
Scopes: Permissions the application requests (e.g., User.Read, Mail.Send). For Microsoft Graph, scopes are like https://graph.microsoft.com/User.Read.
PKCE: Required for public clients (mobile, SPA) to prevent authorization code interception attacks. Uses SHA-256 hash of a random string.
Token Endpoint: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Authorize Endpoint: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
Configuration and Verification Commands
Using Azure CLI, you can register an application:
az ad app create --display-name "MyApp" --identifier-uris "api://myapp" --required-resource-access "[{\"resourceAppId\":\"00000003-0000-0000-c000-000000000000\",\"resourceAccess\":[{\"id\":\"e1fe6dd8-ba31-4d61-89e7-88639da4923c\",\"type\":\"Scope\"}]}]"To generate a client secret:
az ad app credential reset --id <app-id> --years 2To verify token issuance, decode the JWT using a tool like jwt.ms. The token will contain:
- iss: Issuer (e.g., https://login.microsoftonline.com/{tenant}/v2.0)
- aud: Audience (the app ID URI)
- exp: Expiration timestamp
- scp: Scopes (e.g., User.Read)
- tid: Tenant ID
How Entra ID Interacts with Related Technologies
Microsoft Graph: The API gateway for Microsoft 365 data. Access tokens are issued for scopes like User.Read to call Graph API endpoints.
Azure AD B2C: A separate service for customer-facing identity, using the same underlying protocols but with customizable user journeys.
Managed Identities: For Azure resources (e.g., VMs, App Services) that need to authenticate to other Azure services without storing credentials. Managed identities obtain tokens from the Azure Instance Metadata Service (IMDS) endpoint at 169.254.169.254.
Conditional Access: Policies that evaluate risk before issuing tokens. For example, require MFA from untrusted locations. This affects token issuance but not token validation.
Azure AD Application Proxy: Allows on-premises apps to use Entra ID authentication by acting as a reverse proxy.
Register Application in Entra ID
First, you must register your application in the Azure portal under Entra ID > App registrations. Provide a name, select supported account types (e.g., single tenant, multi-tenant), and specify a redirect URI (e.g., `https://localhost:44321/callback`). After registration, note the Application (client) ID (a GUID). For a confidential client (web app), you also generate a client secret or upload a certificate. This registration establishes the identity of your app with Entra ID, allowing it to request tokens.
Configure API Permissions
In the app registration, go to API Permissions and add permissions for Microsoft Graph or your own API. For example, add `User.Read` (delegated) to read the signed-in user's profile. For an API that you own, expose scopes under Expose an API. The admin must grant consent for these permissions (admin consent) or users can consent if the permission is not high-privilege. This step defines what the app can do on behalf of the user.
Initiate Authentication Request
When a user clicks 'Sign In', the client app redirects the browser to the Entra ID authorize endpoint with query parameters: `client_id`, `response_type=code`, `redirect_uri`, `scope` (e.g., `openid profile email User.Read`), `state` (anti-CSRF token), and `code_challenge` (SHA-256 of `code_verifier`). The `state` parameter is important to prevent cross-site request forgery. The user is presented with the Microsoft sign-in page.
User Authenticates and Consents
The user enters their username and password. If MFA is required, they complete that step. If the app requires permissions that need user consent, the user sees a consent screen listing the requested permissions. After consent, Entra ID authenticates the user and generates an authorization code. The code is short-lived (typically 10 minutes). The browser is redirected to the `redirect_uri` with the `code` and `state` appended.
Exchange Code for Tokens
The client app receives the authorization code from the query string. It sends a POST request to the token endpoint with `grant_type=authorization_code`, `client_id`, `client_secret` (if confidential), `code`, `redirect_uri`, and `code_verifier`. Entra ID validates the code, verifier, and client credentials. If valid, it returns a JSON response containing `access_token`, `id_token`, `refresh_token`, and `expires_in` (seconds).
Use Access Token for API Calls
The client app stores the access token (in memory, not local storage for security) and includes it in the `Authorization: Bearer <token>` header of HTTP requests to the protected resource API. The resource API validates the token by checking the signature using the JWKS endpoint, verifying the `iss` and `aud` claims, and ensuring `exp` has not passed. If valid, the API processes the request based on the `scp` claim.
Refresh Token When Expired
When the access token expires (e.g., after 60 minutes), the client app receives a 401 Unauthorized response. It then uses the refresh token to obtain a new access token by sending a POST to the token endpoint with `grant_type=refresh_token`, `refresh_token`, `client_id`, and `client_secret` (if applicable). Entra ID returns a new access token and possibly a new refresh token. Refresh tokens can be revoked by user password change or admin action.
Enterprise Scenario 1: Multi-Tenant SaaS Application
A SaaS company builds a web application that needs to authenticate users from any Microsoft 365 tenant. They register a multi-tenant application in Entra ID. When a user from Contoso signs in, they consent to the required permissions (e.g., read their profile, send email on their behalf). The application receives tokens with the user's tenant ID. The app must handle tokens from different issuers (different tenants) by validating the iss claim against a list of allowed tenants or using the tid claim. In production, the app uses the Microsoft Authentication Library (MSAL) for Node.js to handle the OAuth flow. Common issues: The app must ensure that the redirect URI is registered exactly (including trailing slashes) and that the client secret is rotated regularly. Performance considerations: Token validation involves downloading JWKS keys from the well-known endpoint, which can be cached for 24 hours. Misconfiguration: If the app incorrectly validates the aud claim, tokens meant for another application could be accepted, leading to unauthorized access.
Enterprise Scenario 2: On-Premises API Exposed via Azure AD Application Proxy
A company has an internal HR API that runs on-premises behind a firewall. They want to expose it to cloud-based applications using Azure AD Application Proxy. The API is registered in Entra ID as an enterprise application. Application Proxy connectors installed on-premises handle the communication. When a cloud app calls the API, it first gets an access token from Entra ID for the API's scope. The token is presented to the Application Proxy service, which validates it and forwards the request to the on-premises connector. The connector then calls the internal API. This setup allows the on-premises API to benefit from Entra ID authentication without exposing it directly to the internet. Common pitfalls: The connector must have network access to the internal API and to Azure. If the token expires during a long-running request, the proxy will reject it. Misconfiguration of the redirect URI or secret can cause authentication failures.
Enterprise Scenario 3: Server-to-Server Authentication with Managed Identity
An Azure Function needs to read blobs from an Azure Storage account. Instead of storing a connection string, the function uses a managed identity. When the function runs, it requests a token from the Azure Instance Metadata Service (IMDS) endpoint at http://169.254.169.254/metadata/identity/oauth2/token. The request includes the resource URI (e.g., https://storage.azure.com). IMDS returns an access token that the function uses to authenticate to Storage. This approach eliminates credential management. Scale considerations: IMDS throttles requests; a single VM can handle many token requests, but excessive retries can cause delays. Misconfiguration: If the managed identity is not assigned the proper RBAC role on the storage account, the token will be issued but the API call will fail with 403.
What AZ-204 Tests on This Topic
Objective 3.1: Implement authentication using Microsoft Entra ID. The exam focuses on: - App registration: Understand how to register apps, generate secrets, and configure redirect URIs. - Authentication flows: Specifically the Authorization Code Flow with PKCE for web apps and the Client Credentials Flow for daemon apps. The exam does NOT test implicit grant flow (deprecated). - Token handling: Know the difference between access tokens, ID tokens, and refresh tokens. You must know that ID tokens are for the client to identify the user, while access tokens are for APIs. - Permissions: Understand delegated vs. application permissions. Delegated permissions require a signed-in user; application permissions are for background services. - Microsoft Authentication Library (MSAL): You should know how to use MSAL to acquire tokens programmatically. The exam may ask about token cache serialization for confidential clients.
Common Wrong Answers and Why Candidates Choose Them
Using the implicit grant flow: Candidates often choose this because it is simpler (tokens returned directly in the URL). However, the exam expects the Authorization Code Flow with PKCE for security reasons. Implicit flow is deprecated and should not be used for new apps.
Storing access tokens in local storage: For single-page applications, candidates might think local storage is acceptable. However, the exam emphasizes that tokens should be stored in memory (or session storage) to avoid XSS attacks. Local storage is vulnerable.
Confusing ID token with access token: Candidates may think the ID token can be used to call an API. In reality, the ID token is only for the client to identify the user; the access token is for API authorization.
Using client secret in public clients: Mobile or SPA apps are public clients; they cannot securely store secrets. The exam expects that public clients use PKCE, not client secrets.
Specific Numbers, Values, and Terms
Token lifetimes: Access token default 60 minutes, refresh token 14-90 days.
Authorization code lifetime: 10 minutes.
PKCE uses SHA-256 hash of a 43-character code verifier.
The /authorize endpoint uses HTTP 302 redirect; the /token endpoint uses POST.
The openid scope must be included to receive an ID token.
The offline_access scope is required to receive a refresh token.
Edge Cases and Exam Favorites
Token validation: The exam may test that the iss claim must match the issuer URL for the tenant. For multi-tenant apps, the issuer varies per user.
Admin consent: If an app requires application permissions, admin consent is mandatory. The exam may ask which endpoint to use for admin consent (e.g., /adminconsent).
Conditional Access: Policies can block token issuance even if credentials are correct. The exam may ask how to handle claims challenges (e.g., claims parameter in the error response).
Managed Identity: The exam may ask about the IMDS endpoint IP (169.254.169.254) and that it is non-routable.
How to Eliminate Wrong Answers
If a question mentions a web app, look for Authorization Code Flow with PKCE. If it says 'daemon' or 'background service', use Client Credentials Flow.
If a question asks about 'identifying the user', the answer is ID token. If 'calling an API', it's access token.
If a question involves a mobile app, remember that client secrets are not secure; use PKCE.
If the question mentions 'on-premises' and 'cloud authentication', think Azure AD Application Proxy.
Register your app in Entra ID to get a client ID; for confidential clients, also generate a client secret or certificate.
Use the Authorization Code Flow with PKCE for web and mobile apps; use Client Credentials Flow for daemon apps.
Access tokens are for APIs; ID tokens are for the client to identify the user. Never use an ID token to call an API.
Refresh tokens have a default lifetime of 14-90 days and can be revoked; they are used to get new access tokens without user interaction.
Public clients (mobile, SPA) must use PKCE and cannot use client secrets; confidential clients (web app, daemon) can use secrets or certificates.
Managed identities eliminate credential storage for Azure resources; tokens are obtained from the IMDS endpoint at 169.254.169.254.
Always validate tokens in your API: check signature, issuer (iss), audience (aud), and expiration (exp).
The openid scope is required for ID tokens; offline_access scope is required for refresh tokens.
These come up on the exam all the time. Here's how to tell them apart.
Authorization Code Flow with PKCE
Used for apps with a signed-in user (delegated permissions).
Involves user interaction for authentication and consent.
Returns an authorization code then tokens.
Supports refresh tokens for long-lived access.
Suitable for web apps, mobile apps, and SPAs.
Client Credentials Flow
Used for server-to-server authentication (application permissions).
No user interaction; uses client credentials (secret or certificate).
Directly requests tokens from the token endpoint.
Does not return refresh tokens; access tokens have a fixed lifetime.
Suitable for daemons, background services, and APIs calling other APIs.
Mistake
Access tokens and ID tokens are interchangeable.
Correct
Access tokens are for authorizing access to APIs; they contain scopes and are opaque to the client (though they are JWT). ID tokens are for identifying the user; they contain identity claims like name and email. Using an ID token to call an API will fail because the audience (aud) is the client app, not the API.
Mistake
Refresh tokens never expire.
Correct
Refresh tokens have a configurable lifetime. Default is 14 days for single-page apps and up to 90 days for native apps. They can also be revoked by user password change, admin action, or if the token is idle for a period.
Mistake
Client secrets are safe to use in mobile apps.
Correct
Mobile apps are public clients and cannot securely store secrets. Any secret embedded in the app can be extracted by decompilation. Use PKCE instead of client secrets for public clients.
Mistake
The implicit grant flow is the best choice for single-page apps.
Correct
The implicit flow is deprecated because tokens are exposed in the URL fragment and cannot be securely stored. The recommended flow for SPAs is Authorization Code Flow with PKCE, which uses a backend or service worker to exchange the code.
Mistake
Managed identities require storing credentials.
Correct
Managed identities are credentials-free. Azure automatically rotates the identity's service principal credentials. The application requests a token from the local IMDS endpoint without any stored secrets.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
Delegated permissions are used when the app acts on behalf of a signed-in user. The app can only do what the user is allowed to do. Application permissions are used when the app runs without a user (e.g., background service). The app gets the permissions itself, which must be granted by an administrator. For example, 'User.Read' as delegated allows reading the signed-in user's profile; 'User.Read.All' as application allows reading any user's profile in the organization.
You must include the 'offline_access' scope in your authentication request. This scope is requested during the authorization code flow. The token endpoint will then return a refresh token along with the access token. Without this scope, no refresh token is issued.
PKCE (Proof Key for Code Exchange) is an extension to the Authorization Code Flow designed to prevent authorization code interception attacks. It is required for public clients (mobile apps, SPAs) because they cannot securely store a client secret. The client generates a random code_verifier, hashes it to create a code_challenge, and sends the challenge during the authorization request. When exchanging the code, the client sends the original verifier, which Entra ID matches against the challenge. This ensures that even if the authorization code is intercepted, it cannot be exchanged without the verifier.
Your API must validate the token's signature using the JSON Web Key Set (JWKS) from the issuer's well-known endpoint (e.g., https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration). Then verify the 'iss' claim matches your tenant's issuer, the 'aud' claim matches your API's application ID URI, and the 'exp' claim is not expired. Also check the 'scp' claim for required scopes. Libraries like Microsoft.Identity.Web simplify this for .NET.
A single-tenant app can only be used by users in the tenant where it is registered. A multi-tenant app can be used by users from any Azure AD tenant. For multi-tenant apps, you must handle the 'iss' claim being different per tenant and ensure your app can accept tokens from multiple issuers. Multi-tenant apps require admin consent for application permissions.
Use the refresh token to silently acquire a new access token before it expires. MSAL libraries handle this automatically if you use the token cache. If the refresh token fails (e.g., revoked), prompt the user to sign in again. For daemon apps, simply request a new token using client credentials when the old one expires.
IMDS is a REST endpoint at http://169.254.169.254 accessible only from within an Azure VM or resource. It provides metadata about the VM and can issue tokens for managed identities. To get a token, send a GET request to /metadata/identity/oauth2/token?resource={resource}&api-version=2018-02-01 with a Metadata header set to 'true'.
You've just covered Entra ID Authentication for Developers — now see how well it sticks with free AZ-204 practice questions. Full explanations included, no account needed.
Done with this chapter?