This chapter covers OAuth 2.0 and OpenID Connect (OIDC) as implemented in Azure AD (now Microsoft Entra ID), a core topic for the AZ-500 exam under Objective 1.1: 'Configure identity access in Azure AD.' Approximately 15-20% of exam questions touch on these protocols, either directly or in the context of securing applications, conditional access, and managed identities. You will learn the exact flows, token types, scopes, and configuration steps required to secure access to Azure resources and applications.
Jump to a section
Imagine you are a guest at a large hotel (the resource server) and you want to access the gym (a protected resource). You don't have a gym membership card, but the hotel offers a service: you present your room key (client credentials) to the front desk (authorization server). The front desk verifies you are a registered guest and then issues you a temporary gym access token—a small card with a barcode that expires in 2 hours. You take this token to the gym door, scan it, and enter. The gym attendant never sees your room key; they only validate the token's signature and expiration. The token also carries a scope: it says 'gym access only, no pool.' If you try to use the same token for the pool, the scanner will reject it because the scope doesn't match. When the token expires, you must go back to the front desk to get a new one. This mirrors OAuth 2.0: the client (guest) obtains an access token from the authorization server (front desk) with specific scopes (permissions) and presents it to the resource server (gym) without exposing the client's credentials. The token is a self-contained proof of authorization.
What Are OAuth 2.0 and OpenID Connect?
OAuth 2.0 (RFC 6749) is an authorization framework that enables a third-party application (client) to obtain limited access to an HTTP service (resource server) on behalf of a resource owner (user) or itself. It separates the role of the client from the resource owner, allowing the client to request access tokens without handling the user's credentials. OpenID Connect (OIDC) is an identity layer built on top of OAuth 2.0 (RFC 7519, 8252) that adds authentication and user profile information via an ID token (a JSON Web Token, JWT). While OAuth 2.0 provides delegated access, OIDC provides verifiable identity.
Why They Exist
Before OAuth 2.0, applications often asked for a user's password to access their data on another service (e.g., giving your email password to a third-party app). This was insecure and provided full access. OAuth 2.0 introduces a token-based system where the client receives a limited-scope, time-limited access token, reducing risk. OIDC adds a standardized way for clients to verify the identity of the end-user and obtain basic profile information.
How OAuth 2.0 Works Internally
The protocol involves four main roles: - Resource Owner: Typically the end-user who owns the data. - Client: The application requesting access (e.g., a web app, mobile app, or service). - Authorization Server (AS): The server that issues tokens after authenticating the resource owner and obtaining authorization (in Azure, this is Microsoft Entra ID). - Resource Server (RS): The server that hosts the protected resources (e.g., Microsoft Graph API, Azure Resource Manager).
A typical OAuth 2.0 authorization code flow (the most common and secure for web apps) proceeds as follows:
The client directs the user to the authorization server's /authorize endpoint with query parameters: response_type=code, client_id, redirect_uri, scope, and optionally state.
The AS authenticates the user (via cookies, MFA, etc.) and asks for consent to the requested scopes.
Upon consent, the AS redirects the user back to the client's redirect_uri with an authorization code in the query string.
The client sends a POST request to the AS's /token endpoint with the authorization code, client credentials (client_id and client_secret or certificate), and redirect_uri.
The AS validates the code and client credentials, then returns an access token (JWT), optionally a refresh token, and for OIDC, an ID token.
The client uses the access token in the Authorization: Bearer <token> header to call the resource server.
The resource server validates the token's signature (using public keys from the AS's /jwks endpoint), checks expiry (exp claim), and verifies scopes (scp claim) before granting access.
Key Components, Values, Defaults, and Timers
Access Token: A JWT with a default lifetime of 60–90 minutes for Azure AD tokens (configurable via token lifetime policies). Contains claims: aud (audience, e.g., https://graph.microsoft.com), iss (issuer, e.g., https://sts.windows.net/<tenant-id>/), iat, nbf, exp, scp (scopes), appid (client ID), tid (tenant ID).
Refresh Token: Opaque string, longer-lived (default 90 days of inactivity, then 14 days for mobile/desktop, 90 days for web apps). Used to obtain new access tokens without user interaction.
ID Token (OIDC): JWT containing identity claims: sub (subject, unique user ID), preferred_username, email, name, oid (object ID), tid. Signed and optionally encrypted.
Authorization Code: Short-lived (typically 5–10 minutes), single-use.
Scopes: Permissions requested (e.g., openid, profile, email, User.Read, Files.Read). For Azure AD, scopes are often API-specific like https://graph.microsoft.com/User.Read.
Client Credentials: Client ID (application ID) and either a client secret (string) or a certificate (public/private key pair). Secrets default to 1 year expiry (can be set to 6 months, 1 year, or never).
Redirect URI: Must be registered in the app registration; must be HTTPS (except for localhost in development).
State Parameter: Opaque value to prevent CSRF attacks; recommended by RFC 6749.
Configuration and Verification Commands (Azure AD / Microsoft Entra ID)
To configure OAuth 2.0 / OIDC in Azure:
Register an application in Azure AD (Entra ID) -> App registrations -> New registration.
Set redirect URIs under Authentication.
Configure client credentials under Certificates & secrets.
Define API permissions (scopes) under API permissions.
Expose an API (if your app is a resource server) under Expose an API.
To verify token issuance and validate tokens:
Use az rest or PowerShell to simulate token requests:
az account get-access-token --resource https://graph.microsoft.comDecode a JWT manually using https://jwt.ms or PowerShell:
$token = "..."
$parts = $token.Split('.')
$payload = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($parts[1]))
$payload | ConvertFrom-JsonValidate token signature using Azure AD's public keys from https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys.
How It Interacts with Related Technologies
Conditional Access: Policies can evaluate token issuance based on user risk, device compliance, location, etc. Tokens are only issued if conditions are met.
Managed Identities: Azure resources (VMs, Functions) can obtain tokens from the Azure Instance Metadata Service (IMDS) without managing secrets. The identity is assigned by Azure AD.
Microsoft Graph: The primary resource server for Azure AD; uses OAuth 2.0 tokens for all API calls.
Azure AD B2C: Extends OAuth 2.0/OIDC for customer-facing apps with custom user journeys.
API Management: Can validate tokens on behalf of backend APIs using policies like validate-jwt.
OAuth 2.0 Grant Types
Authorization Code Grant: For server-side web apps; most secure, supports PKCE for mobile/native apps.
Client Credentials Grant: For server-to-server scenarios (no user). Client authenticates directly and gets an access token for its own permissions (application permissions).
Device Authorization Grant: For devices without browsers (e.g., IoT). User visits a URL on another device to authenticate.
Implicit Grant (deprecated): Used for SPAs; now replaced by Authorization Code with PKCE.
On-Behalf-Of (OBO) Flow: Used when a service calls another service on behalf of the user. The first service's token is exchanged for a token to access the downstream API.
Security Considerations
Always use HTTPS for all endpoints.
Use PKCE (Proof Key for Code Exchange) for mobile and native apps to prevent authorization code interception.
Store client secrets in Azure Key Vault, not in code or config files.
Use certificates instead of secrets for higher security.
Validate all claims in tokens: audience, issuer, expiry, not-before, and signature.
Implement token refresh carefully; refresh tokens can be revoked if user changes password or admin revokes consent.
Client Registration in Azure AD
The first step is to register your application in Azure AD (Entra ID). Navigate to Azure Active Directory > App registrations > New registration. Provide a name, choose supported account types (e.g., single tenant, multi-tenant, or personal Microsoft accounts), and set a redirect URI (e.g., https://myapp.com/auth/callback). This registration generates a client ID (application ID) that uniquely identifies your app. For confidential clients, you also generate a client secret (a string) or upload a certificate. The client ID and secret are later used to authenticate the client to the authorization server during the token request. The redirect URI must exactly match the one used in the authorization request; otherwise, the AS will reject the request. The registration also defines the scopes (permissions) the app may request, such as 'User.Read' for Microsoft Graph.
Initiate Authorization Request
The client constructs a URL to the authorization server's /authorize endpoint (e.g., https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize). The URL includes query parameters: response_type=code (for authorization code flow), client_id, redirect_uri, scope (e.g., openid profile User.Read), and a state parameter (a random value for CSRF protection). The client redirects the user's browser to this URL. The authorization server authenticates the user (via cookies, MFA, etc.) and presents a consent screen if the user has not previously consented to the requested scopes. The user reviews the permissions and approves or denies. If approved, the AS redirects the user back to the redirect_uri with an authorization code in the query string (e.g., ?code=abc123&state=xyz). The state must match the original value; if not, the client aborts.
Exchange Code for Tokens
The client receives the authorization code and sends a POST request to the /token endpoint (https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token). The request body includes: grant_type=authorization_code, code (the authorization code), redirect_uri (must match the previous one), client_id, and client_secret (or client_assertion for certificate). The authorization server validates the code (single-use, not expired), the client credentials, and the redirect URI. If valid, it responds with a JSON object containing: access_token (JWT), token_type (Bearer), expires_in (seconds, default 3600 for many APIs), refresh_token (opaque string), id_token (if openid scope was requested), and scope (the granted scopes). The client must store these tokens securely. The access token is now ready to be used against the resource server.
Call Resource Server with Access Token
The client includes the access token in the Authorization header of HTTP requests to the resource server (e.g., Microsoft Graph API). The header format is: 'Authorization: Bearer <access_token>'. The resource server receives the request and first validates the token. It checks the signature using the public keys from the authorization server's JWKS endpoint. It verifies the token's expiry (exp claim) and that the current time is between nbf and exp. It checks the audience (aud claim) to ensure the token was intended for this resource server. It also checks the scopes (scp claim) to ensure the client has permission for the requested operation. If all checks pass, the resource server processes the request and returns the data. If the token is expired or invalid, it returns a 401 Unauthorized response, prompting the client to obtain a new token using the refresh token.
Refresh Token When Access Token Expires
When the access token expires, the client uses the refresh token to obtain a new access token without user interaction. The client sends a POST to the /token endpoint with grant_type=refresh_token, refresh_token, client_id, client_secret, and optionally scope (if you want to request different scopes). The authorization server validates the refresh token (not revoked, not expired) and issues a new access token (and optionally a new refresh token). The old refresh token is typically invalidated (rolling refresh). The client updates its stored tokens. Refresh tokens for Azure AD have a default lifetime of 90 days if used regularly; if inactive for 90 days, they expire. For mobile/desktop apps, the max inactivity period is 14 days. Refresh tokens can also be revoked by user password change, admin action, or token revocation event.
Enterprise Scenario 1: Service-to-Service Authentication with Managed Identities
A large enterprise runs a microservices architecture on Azure Kubernetes Service (AKS) where each microservice needs to access Azure Key Vault to retrieve secrets. Traditionally, developers would store service principal credentials in environment variables, leading to security risks. The solution uses managed identities: each pod is assigned an Azure AD managed identity (system-assigned or user-assigned). The pod requests a token from the Azure Instance Metadata Service (IMDS) endpoint at 169.254.169.254. The token is for the Key Vault resource (audience: https://vault.azure.net). The pod then uses this token to authenticate to Key Vault. No secrets are stored in the code or configuration. In production, this scales to thousands of pods. Common issues: misconfigured role assignments (the identity must have appropriate RBAC or access policy on Key Vault), and token caching (the token expires after 8 hours by default for IMDS, so code must handle refresh). When misconfigured, pods get 401 errors and fail to start.
Enterprise Scenario 2: Multi-Tenant SaaS Application with OIDC
A SaaS provider builds a multi-tenant application that needs to authenticate users from any Azure AD tenant. They register the app as multi-tenant in Azure AD and use the common endpoint (https://login.microsoftonline.com/common). When a user signs in, the app requests the openid, profile, and email scopes. The user consents, and the app receives an ID token containing the user's tenant ID (tid) and object ID (oid). The app uses these claims to map the user to a tenant-specific database. For authorization, the app uses access tokens to call Microsoft Graph to read the user's profile. Challenges: token validation must be tenant-aware (validate issuer against known tenants), and the app must handle incremental consent for new scopes. Performance: token issuance takes ~500ms-1s, so caching is critical. Common mistakes: not validating the issuer (allowing tokens from any tenant) or not handling token expiry properly.
Enterprise Scenario 3: On-Behalf-Of (OBO) Flow for Tiered APIs
A company has a web API (API A) that calls a downstream API (API B) on behalf of the user. API A receives an access token from the client (with audience for API A). API A then uses the OBO flow: it sends a POST to the /token endpoint with grant_type=on_behalf_of, assertion (the incoming token), and scope for API B (e.g., https://apiB.com/read). Azure AD validates the incoming token and issues a new token for API B. API A then calls API B with this new token. This is common in microservices where the user context must be preserved. Performance: each OBO exchange adds latency. Security: the incoming token must be valid and include the necessary scopes. Misconfiguration: the API A's app registration must have the 'oauth2AllowImplicitFlow' flag set and the 'knownClientApplications' property configured for proper consent.
What AZ-500 Tests on This Topic
AZ-500 objective 1.1 includes 'Configure Azure AD authentication and authorization' which encompasses OAuth 2.0 and OIDC. Specifically, you must understand: - Token types and their claims (access token, ID token, refresh token). - Grant types (authorization code, client credentials, device code, OBO). - Scopes and permissions (delegated vs. application permissions). - Token validation (signature, claims, expiry). - Integration with Conditional Access and Managed Identities.
Common Wrong Answers and Why Candidates Choose Them
'Implicit grant is recommended for SPAs' – Wrong. Implicit grant is deprecated. The correct answer is Authorization Code with PKCE. Candidates choose this because older documentation recommended it.
'Refresh tokens never expire' – Wrong. Refresh tokens have a maximum lifetime (90 days of inactivity) and can be revoked. Candidates think they are infinite because they are long-lived.
'Access tokens contain the user's password' – Wrong. Access tokens are JWTs containing claims, never passwords. Candidates confuse authentication with authorization.
'Client credentials flow requires a user to sign in' – Wrong. Client credentials flow is for server-to-server and does not involve a user. Candidates think all flows require user interaction.
Specific Numbers and Values on the Exam
Default access token lifetime: 60-90 minutes (configurable via token lifetime policy).
Default refresh token inactivity timeout: 90 days for web apps, 14 days for mobile/desktop.
Authorization code lifetime: 5-10 minutes.
State parameter: mandatory for CSRF protection.
Redirect URI: must be HTTPS (except localhost).
PKCE: required for mobile/native apps (code_challenge_method=S256).
Edge Cases and Exceptions
Multi-tenant apps: Tokens from other tenants must be validated against that tenant's keys, not the app's home tenant.
B2B collaboration: Guest users receive tokens with their home tenant's claims; the resource tenant must accept them.
Token caching: The exam may test that tokens should be cached until near expiry (e.g., within 5 minutes) to reduce latency.
Conditional Access: Token issuance can be blocked if policy conditions are not met; the error is 'interaction_required'.
How to Eliminate Wrong Answers
If a question says 'user authenticates' but the grant type is client credentials, eliminate it.
If a question mentions 'implicit flow' for a new SPA, eliminate it.
If a question says 'refresh token lasts forever', eliminate it.
Look for keywords: 'delegated permission' vs 'application permission' — the latter requires admin consent and is used for client credentials.
OAuth 2.0 is an authorization framework; OpenID Connect adds authentication via ID tokens.
The authorization code grant with PKCE is the recommended flow for web and mobile apps.
Access tokens are JWTs containing claims like aud, iss, exp, scp; they must be validated by the resource server.
Refresh tokens in Azure AD have a default inactivity timeout of 90 days (14 days for mobile/desktop).
Client credentials grant is for server-to-server scenarios and does not involve a user.
Managed identities use the client credentials grant internally to obtain tokens for Azure resources.
Token lifetime can be configured using Azure AD token lifetime policies (preview).
Always use the state parameter to prevent CSRF attacks in OAuth flows.
Conditional Access policies can block token issuance if conditions are not met.
The On-Behalf-Of (OBO) flow allows a service to obtain a token for a downstream API on behalf of the user.
These come up on the exam all the time. Here's how to tell them apart.
OAuth 2.0 Authorization Code Grant
Requires user interaction (login and consent).
Uses delegated permissions (user context).
Returns an authorization code first, then tokens.
Supports refresh tokens for long-lived access.
Suitable for apps that need to act on behalf of a user.
OAuth 2.0 Client Credentials Grant
No user interaction; client authenticates directly.
Uses application permissions (app context).
Directly returns tokens without an authorization code.
No refresh tokens (access token must be renewed by re-authenticating).
Suitable for background services, daemons, and server-to-server communication.
Mistake
OAuth 2.0 provides authentication.
Correct
OAuth 2.0 is an authorization framework, not an authentication protocol. It provides delegated access to resources. Authentication is provided by OpenID Connect (OIDC), which uses an ID token to verify user identity.
Mistake
Access tokens are opaque strings that cannot be decoded.
Correct
Access tokens in Azure AD are JSON Web Tokens (JWTs) that are base64url-encoded and can be decoded to view claims. However, clients should not rely on the contents for authorization decisions; validation should be done by the resource server.
Mistake
Refresh tokens never expire.
Correct
Refresh tokens have a maximum lifetime. In Azure AD, they expire after 90 days of inactivity (or 14 days for mobile/desktop apps) and can be revoked by user password change or admin action.
Mistake
The implicit grant flow is the best choice for single-page applications.
Correct
The implicit grant flow is deprecated due to security concerns (token leakage in URL). The recommended flow for SPAs is Authorization Code with PKCE (Proof Key for Code Exchange).
Mistake
Client credentials flow can be used to access resources on behalf of a user.
Correct
Client credentials flow is for server-to-server scenarios where no user is involved. It uses application permissions, not delegated permissions. To act on behalf of a user, use authorization code or OBO flow.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
An access token is used to authorize access to a resource (e.g., API), while an ID token is used to authenticate the user. The ID token contains claims about the user's identity (e.g., sub, email, name) and is a JWT that the client can decode to verify the user. The access token is sent to the resource server, which validates it. In Azure AD, both are issued together when the 'openid' scope is requested.
You must validate the token's signature using the public keys from Azure AD's JWKS endpoint (https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys). Check the 'aud' claim matches your API's client ID, the 'iss' claim matches your tenant's issuer URL, the 'exp' time is not past, and the 'nbf' time is in the past. Also, verify the 'scp' or 'roles' claim contains the required permission. Use a library like Microsoft.IdentityModel.Tokens for .NET or similar for other languages.
PKCE (Proof Key for Code Exchange) is an extension to the authorization code flow that prevents authorization code interception attacks. The client generates a random code_verifier and sends its SHA-256 hash (code_challenge) in the authorization request. When exchanging the code for tokens, the client sends the original code_verifier. The authorization server verifies the hash matches. This ensures that even if an attacker intercepts the authorization code, they cannot exchange it without the code_verifier. PKCE is required for mobile and native apps and recommended for all public clients.
No. OAuth 2.0 alone does not provide authentication. It only provides authorization. To authenticate a user, you need OpenID Connect, which adds an ID token that contains the user's identity. Without OIDC, you cannot verify who the user is, only that they authorized the client. In practice, most OAuth 2.0 implementations in Azure also use OIDC to obtain user identity.
Token lifetime policies can be configured via PowerShell or Microsoft Graph. For example, to set access token lifetime to 60 minutes: New-AzureADPolicy -Definition @('{"TokenLifetimePolicy":{"Version":1,"AccessTokenLifetime":"01:00:00"}}') -DisplayName "CustomTokenPolicy" -IsOrganizationDefault $false. Then assign the policy to a service principal or application. Note that token lifetime policies are in preview and may not apply to all scenarios.
When a refresh token expires, the client can no longer use it to obtain new access tokens. The user must re-authenticate to get a new refresh token. This can happen if the user has not used the app for 90 days (or 14 days for mobile/desktop). Also, refresh tokens are revoked if the user changes their password, if an admin revokes consent, or if the token is used after a long inactivity period.
Delegated permissions are used when the app acts on behalf of a signed-in user. They are requested in the scope parameter and require user consent (or admin consent for high-privilege). Application permissions are used when the app acts as itself (no user context). They are configured in the app registration under 'API permissions' and require admin consent. Application permissions are used in client credentials flow.
You've just covered OAuth 2.0 and OpenID Connect in Azure — now see how well it sticks with free AZ-500 practice questions. Full explanations included, no account needed.
Done with this chapter?