This chapter covers OAuth 2.0 and app consent in Microsoft 365, a critical security topic for the MS-900 exam. Understanding how Microsoft 365 uses OAuth to authorize third-party apps and how admins manage consent is essential, as approximately 10-15% of exam questions touch on app permissions, consent, and security. We will explore the OAuth flow in detail, the different types of permissions, admin consent, user consent, and how to audit and control app access.
Jump to a section
Imagine a hotel where guests need access to various rooms and facilities. The hotel has a front desk (the authorization server). A guest checks in and receives a key card (the access token) that grants access only to their assigned room and, say, the gym and pool, but not the staff offices or other guests' rooms. The key card has an expiration time printed on it, and it cannot be used after checkout. If the guest wants to access a restricted area like the business center, they must return to the front desk with proof of identity (a passport) and request a new key card with that additional permission. The front desk verifies their identity and issues a new key card with the updated scope. The hotel staff (resource servers) do not need to check the guest's identity each time; they simply scan the key card and check that it has the correct permissions and is not expired. This is exactly how OAuth 2.0 works: a client application (guest) obtains an access token (key card) from an authorization server (front desk) after the user (hotel guest) consents. The token is then presented to the resource server (hotel door) to access protected resources. The token contains scopes (permissions) and an expiration time. If the client needs additional permissions, it must go through a new consent flow.
What is OAuth 2.0 and Why Does Microsoft 365 Use It?
OAuth 2.0 (RFC 6749) is an open standard for token-based authorization. It allows third-party applications to access user data hosted on a resource server without exposing the user's credentials. In Microsoft 365, OAuth 2.0 is the foundation for all delegated access to Microsoft Graph, SharePoint, Exchange Online, and other services. Instead of sharing a password, the user authenticates once, and the app receives a limited-scope, time-limited token.
How OAuth 2.0 Works in Microsoft 365
The OAuth 2.0 flow involves four parties: - Resource Owner: The user who owns the data (e.g., a Microsoft 365 user). - Client: The application requesting access (e.g., a third-party app like a CRM tool). - Authorization Server: The Microsoft identity platform (Azure AD) that issues tokens after authentication and consent. - Resource Server: The API that hosts the data (e.g., Microsoft Graph).
The most common flow for delegated access is the Authorization Code Grant Flow (OAuth 2.0 authorization code grant). Step-by-step:
1. The client app redirects the user to the Azure AD authorize endpoint (https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize).
2. The user authenticates (if not already) and sees a consent prompt listing the permissions the app requests.
3. If the user consents, Azure AD sends an authorization code back to the client via a redirect URI.
4. The client exchanges that code for an access token (and optionally a refresh token) by calling the token endpoint (https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token).
5. The client uses the access token in the Authorization: Bearer header to call Microsoft Graph APIs.
Key Components: Permissions, Scopes, and Consent
Permissions are divided into two types:
- Delegated permissions: The app acts on behalf of a signed-in user. The app can only do what the user is allowed to do. Example: Mail.Read allows reading the signed-in user's mail.
- Application permissions: The app runs as a background service without a signed-in user. These require admin consent and are powerful (e.g., Mail.Read.All allows reading any user's mail in the organization).
Scopes are the specific permissions requested. For Microsoft Graph, scopes are strings like User.Read, Mail.Send, Files.ReadWrite.All. The client requests scopes in the authorization request.
Consent is the act of granting permission. There are two types:
- User consent: The user consents to delegated permissions on their own behalf. By default, users can consent to low-impact permissions (e.g., User.Read, openid, profile, email). Admins can control which permissions users are allowed to consent to via User consent settings in Azure AD.
- Admin consent: An administrator consents on behalf of the entire organization. Required for application permissions or high-risk delegated permissions (e.g., Mail.ReadWrite.All). Admin consent cannot be undone by individual users; only an admin can revoke it.
Default Values and Timers
Access token lifetime: By default, Microsoft identity platform access tokens are valid for 60-90 minutes (configurable via token lifetime policies). The actual value depends on the resource; Microsoft Graph tokens default to 60 minutes.
Refresh token lifetime: Refresh tokens are valid for 90 days by default. If the user does not use the app for 90 days, the refresh token expires and the user must re-authenticate. This can be configured up to a maximum of 365 days or set to never expire (not recommended).
ID token lifetime: ID tokens (OpenID Connect) are valid for 1 hour by default.
Configuration and Verification
Admins manage app permissions and consent in the Azure AD admin center under Enterprise applications > App registrations > select an app > API permissions. Here, you can add permissions and grant admin consent.
To audit consent grants, use the Microsoft Entra admin center > Identity > Applications > Enterprise applications > Consent and permissions > User consent settings and Admin consent settings. You can review all consent requests and revoke them.
Using PowerShell, you can list all OAuth2 permission grants with the Microsoft Graph PowerShell SDK:
Connect-MgGraph -Scopes "Directory.Read.All"
Get-MgOauth2PermissionGrant -AllTo revoke a specific grant:
Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId "<grant-id>"Interaction with Conditional Access
OAuth tokens are subject to Conditional Access policies. When a user authenticates, Azure AD evaluates policies based on the user, device, location, and app. If a policy requires multi-factor authentication (MFA), the token will only be issued after MFA is completed. The token itself contains claims about the authentication context (e.g., acr claim indicating MFA). Resource servers can validate these claims.
App Consent Policies
Admins can configure Admin consent workflows to allow users to request admin consent for permissions they cannot consent to themselves. This is set in Azure AD > Enterprise applications > Consent and permissions > Admin consent settings. When enabled, users see a prompt to request approval, and designated reviewers can approve or deny.
Microsoft Graph permissions are categorized into three tiers:
- Low: Basic profile, sign-in, openid, email, offline_access. Users can consent by default.
- Medium: Permissions that read or write user data but with limited scope (e.g., Calendars.Read, Mail.Read). Admins can allow user consent for these.
- High: Permissions with broad data access (e.g., Mail.ReadWrite.All, Directory.ReadWrite.All). These require admin consent.
Common Misconfiguration: Over-Permissioned Apps
A frequent security issue is granting excessive permissions to apps. For example, a simple note-taking app requesting Mail.ReadWrite.All (read and write all mail) instead of just Mail.Read. The principle of least privilege should be applied. Use the Permissions tab in Azure AD to review granted permissions and remove unnecessary ones.
Revoking Consent
Users can revoke consent for apps in the My Apps portal (https://myapps.microsoft.com) by selecting the app and clicking Remove. Admins can revoke consent for any app in the Azure AD portal under Enterprise applications > select app > Permissions > Revoke admin consent.
Summary of Exam-Relevant Points
OAuth 2.0 is used for delegated access; OpenID Connect is used for authentication (ID token).
Delegated permissions require a signed-in user; application permissions do not.
User consent is for low/medium delegated permissions; admin consent is required for high-risk delegated and all application permissions.
Default access token lifetime: 60-90 minutes (Microsoft Graph: 60 minutes).
Refresh token default: 90 days of inactivity.
Consent can be reviewed and revoked by users (self) and admins (all).
Conditional Access policies can enforce MFA and other controls at token issuance.
User Initiates App Login
The user navigates to the third-party app and clicks 'Sign in with Microsoft'. The app constructs an authorization request URL with parameters: client_id (app's ID), response_type=code, redirect_uri (where to send the auth code), scope (e.g., 'User.Read Mail.Read'), and state (a random value for CSRF protection). The user's browser is redirected to the Microsoft identity platform authorize endpoint.
User Authenticates
The user enters their credentials on the Microsoft login page. If multi-factor authentication is required by Conditional Access, the user completes that step. Upon successful authentication, the authorization server creates an authentication session. The user is then presented with a consent screen listing the requested permissions (scopes).
User Consents
The user reviews the permissions and clicks 'Accept'. This consent is recorded as an OAuth2PermissionGrant object in Azure AD. The authorization server generates an authorization code (short-lived, typically 10 minutes) and sends it to the redirect_uri as a query parameter. The code is single-use.
App Exchanges Code for Token
The app receives the authorization code and sends a POST request to the token endpoint with the code, client_id, client_secret (or certificate), redirect_uri, and grant_type=authorization_code. The authorization server validates the code and client credentials, then returns an access token (JWT), an ID token (if openid scope was requested), and a refresh token (if offline_access scope was requested). The access token contains claims such as aud (audience), iss (issuer), iat (issued at), exp (expiration), scp (scopes), and oid (object ID of the user).
App Calls Microsoft Graph
The app uses the access token to call Microsoft Graph APIs. It adds an HTTP header: 'Authorization: Bearer <access_token>'. Microsoft Graph validates the token signature, checks expiration, and verifies that the token's scopes include the required permissions. If valid, the API returns the requested data. If the token is expired, the app uses the refresh token to obtain a new access token without user interaction.
Scenario 1: Third-Party CRM Integration
A company uses a CRM application that needs to read users' calendars and send emails on their behalf. The admin registers the CRM app in Azure AD and requests delegated permissions Calendars.Read and Mail.Send. The admin grants admin consent so that all users in the organization can use the app without seeing a consent prompt. The app uses the OAuth authorization code flow. In production, the app handles token refresh automatically. A common issue is that the app's redirect URI is misconfigured (e.g., using HTTP instead of HTTPS), causing the authorization code to be intercepted. The admin must ensure the redirect URI is exactly as registered.
Scenario 2: Background Service for Mail Archiving
An organization deploys a mail archiving service that runs as a daemon and needs to read all users' mail. This requires application permission Mail.Read.All. The admin registers the app and grants admin consent for that permission. The app uses the client credentials grant flow, where it authenticates with its client ID and client secret (or certificate) to obtain an access token directly, without any user. The token is valid for 60 minutes. The service must handle token expiration by requesting a new token. A misconfiguration here is using a delegated permission instead of application permission, causing the service to fail when no user is signed in.
Scenario 3: User-Consented App Gone Rogue
An employee installs a free productivity app that requests Files.ReadWrite.All and Mail.ReadWrite. The user consents, not realizing the app can read and write all their files and emails. Later, the app exfiltrates data. The admin discovers the issue via the Azure AD audit logs (sign-in logs and consent events). The admin revokes the app's permissions globally. To prevent this, the admin should configure user consent settings to block high-risk permissions and enable the admin consent workflow. The admin also implements Conditional Access policies that require compliant devices for app access.
Performance and Scale
OAuth token issuance is handled by Azure AD, which is highly scalable. For large organizations with thousands of apps, the main challenge is managing consent and auditing. Azure AD can handle millions of token requests per day. The token size is typically 2-4 KB. The refresh token rotation (new refresh token issued with each refresh) is supported to improve security.
What MS-900 Tests
The MS-900 exam objective 3.3 covers 'Describe the security capabilities of Microsoft 365' and specifically includes app permissions and consent. Expect 3-5 questions on:
Distinguishing between delegated and application permissions.
Understanding when admin consent is required.
Knowing the default token lifetimes (access token 60-90 min, refresh token 90 days).
Recognizing the consent prompt and how users can review/revoke consent.
Identifying the correct flow for different scenarios (delegated vs. app-only).
Common Wrong Answers and Why
'Application permissions require user consent.' This is false. Application permissions are granted only by admin consent; there is no user involved.
'Access tokens are valid for 24 hours.' Wrong. The default is 60-90 minutes, not 24 hours. This is a trap because other systems may have longer lifetimes.
'Users can grant admin consent.' False. Only admins can grant admin consent. Users can only grant user consent for delegated permissions.
'Refresh tokens never expire.' Wrong. Default is 90 days of inactivity, configurable but not infinite.
Specific Numbers and Terms on the Exam
Delegated permission: User.Read (low), Mail.Read (medium), Mail.ReadWrite.All (high).
Application permission: Mail.Read.All, Directory.ReadWrite.All.
Token endpoint: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token.
Admin consent endpoint: https://login.microsoftonline.com/{tenant}/v2.0/adminconsent.
Default access token lifetime: 60 minutes for Microsoft Graph.
Default refresh token inactivity timeout: 90 days.
Edge Cases
Multi-tenant apps: An app registered in one tenant can request access to another tenant's data. The user in the target tenant must consent, or an admin must grant admin consent for the entire tenant.
Consent for personal Microsoft accounts: For Microsoft accounts (e.g., Outlook.com), consent is always user consent; there is no admin.
Incremental consent: Apps can request additional permissions dynamically (dynamic consent) by including new scopes in the authorization request. This prompts the user again.
How to Eliminate Wrong Answers
If the scenario describes an app running without a user (e.g., a service, daemon), the answer must involve application permissions and admin consent, not user consent.
If the question mentions 'on behalf of a user', it's delegated permissions.
If the question asks about the maximum time a token is valid, remember the default is 60 minutes (or 90 min for some resources), not hours or days.
For consent revocation, know that users can revoke in My Apps, admins in Azure AD.
OAuth 2.0 is for authorization; OpenID Connect is for authentication.
Delegated permissions require a user; application permissions do not.
Admin consent is mandatory for application permissions and high-risk delegated permissions.
Default access token lifetime for Microsoft Graph is 60 minutes.
Default refresh token inactivity timeout is 90 days.
Users can revoke consent via My Apps; admins can revoke via Azure AD.
Conditional Access policies are evaluated at token issuance, not at API call.
These come up on the exam all the time. Here's how to tell them apart.
Delegated Permissions
Requires a signed-in user.
App acts on behalf of the user.
User or admin can consent (depending on risk level).
Scopes are user-specific (e.g., Mail.Read).
Common for interactive apps.
Application Permissions
No signed-in user required.
App runs as a background service.
Only admin can consent.
Scopes are tenant-wide (e.g., Mail.Read.All).
Common for daemons and services.
Mistake
OAuth 2.0 is used for authentication.
Correct
OAuth 2.0 is for authorization only. OpenID Connect (OIDC) is the authentication layer built on top of OAuth 2.0. OAuth 2.0 provides access tokens; OIDC provides ID tokens for authentication.
Mistake
Application permissions can be granted by users.
Correct
Application permissions always require admin consent. Users cannot grant application permissions because they operate without a signed-in user and have broad access.
Mistake
Access tokens are valid indefinitely.
Correct
Access tokens have a limited lifetime, typically 60-90 minutes. They must be refreshed using a refresh token. Refresh tokens have a default inactivity timeout of 90 days.
Mistake
Once a user consents, the app can access data forever.
Correct
Consent can be revoked by the user or an admin. Also, refresh tokens expire after 90 days of inactivity, requiring the user to re-consent if the app is not used.
Mistake
All apps in Microsoft 365 use OAuth 2.0.
Correct
Legacy protocols like Basic authentication and Active Directory Authentication Library (ADAL) are deprecated. However, some older apps may still use them. Microsoft recommends OAuth 2.0 with Microsoft Authentication Library (MSAL).
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
Delegated permissions allow an app to act on behalf of a signed-in user, with access limited to what the user can do. Application permissions allow an app to access data without a signed-in user, typically with broader, tenant-wide access. Delegated permissions can be consented to by users (for low-risk) or admins; application permissions always require admin consent.
By default, access tokens issued by the Microsoft identity platform are valid for 60-90 minutes. For Microsoft Graph, the default is 60 minutes. This can be changed using token lifetime policies, but the default is what MS-900 tests.
No, by default users cannot consent to high-risk permissions like 'Mail.ReadWrite.All'. This permission requires admin consent. Admins can configure user consent settings to allow or block specific permissions, but the default blocks high-risk permissions.
Users can revoke consent by going to the My Apps portal (https://myapps.microsoft.com), selecting the app, and clicking 'Remove'. Admins can revoke consent for any app in the Azure AD admin center under Enterprise applications > select app > Permissions > Revoke admin consent. Admins can also revoke all consents for a user via PowerShell.
The refresh token allows an app to obtain a new access token without requiring the user to re-authenticate. It is issued along with the access token when the 'offline_access' scope is requested. The refresh token has a longer lifetime (default 90 days inactivity) and can be used to get new access tokens after the current one expires.
If the user denies consent, the authorization server does not issue an authorization code. The user is redirected back to the app with an error parameter (e.g., 'error=access_denied'). The app must handle this error gracefully, typically by showing a message that consent is required.
Yes, this is called incremental consent. The app can initiate a new authorization request with additional scopes. The user (or admin) must consent to the new permissions. This is useful for apps that need to expand functionality over time.
You've just covered Securing Microsoft 365 Apps: OAuth and App Consent — now see how well it sticks with free MS-900 practice questions. Full explanations included, no account needed.
Done with this chapter?