Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This article provides guidance on troubleshooting and resolving Cross-Origin Resource Sharing (CORS) errors encountered when using Microsoft Entra ID.
Understanding CORS
Cross-Origin Resource Sharing (CORS) is an HTTP-header-based mechanism that allows a server to specify origins(domains, schemes, ports) other than its own from which a browser should permit loading resources. CORS also relies on a mechanism by which browsers make a "preflight" request to the server hosting the cross-origin resource, in order to check whether the server permits the actual request. During this preflight, the browser sends headers that indicate the HTTP method and headers that are used in the actual request.
For detailed information about CORS headers, refer to CORS headers.
Key concepts
- Browsers block cross-origin requests if the resource lacks the supported headers.
- Cross-origin requests usually originate from JavaScript XMLHttpRequest calls, such as a direct HTTP call with no user interaction or window.
- Microsoft Entra ID doesn't have CORS enabled while performing an interactive sign-in, meaning CORS requests can't be directly sent to Microsoft Entra ID.
Symptoms
While developing an application, you might encounter the following CORS-related errors in the browser console logs:
Example 1
Access to XMLHttpRequest at 'https://login.microsoftonline.com/tenant_id/oauth2/v2.0/authorize?client_id=&redirect_uri=signin-oidc&response_type=id_token&scope=openid%20profile&response_mode=form_post&nonce=6370sdfj&state=sdfsdfds-sdfsdfsdf-sd-sdfsdf-T3qwNWW2jRHM&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=5.5.0.0' (redirected from 'xxx') from origin 'yyyy' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
The URL starting with
https://login.microsoftonline.com/indicates that you might have an Azure Active Directory B2C scenario.Example 2
Access to fetch at 'https://contosob2c.b2clogin.com/tfp/tenant_id/b2c_1_v2_susi_defaultpage/v2.0/.well-known/openid-configuration' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Example 3
CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present.
Note
- These errors are generated by Microsoft Entra ID. Request URLs in these errors often begin with
https://login.microsoftonline.comorhttps://<your-domain>.b2clogin.com. The latter typically points to an Azure Active Directory B2C scenario. - If the error doesn't originate from Microsoft Entra ID, it looks like "Access to XMLHttpRequest at
https://app.contoso.com." This article doesn't provide guidance on resolving external CORS issues. In such cases, you need to configure CORS in that environment.
Cause
To identify your scenario and the root cause, capture the failing request using Fiddler. Look for the XMLHttpRequest or AJAX request in the Fiddler capture and you see a 302 redirect occurs to https://login.microsoftonline.com/.
Example request and response
Request:
GET https://login.microsoftonline.com.com/domain.onmicrosoft.com/oauth2/v2.0/authorize?... HTTP/1.1
Host: login.microsoftonline.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Origin: https://app.domain.com
Response:
HTTP/1.1 200 OK
Cache-Control: no-store, no-cache
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Expires: -1
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-DNS-Prefetch-Control: on
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
Set-Cookie: ...
Referrer-Policy: strict-origin-when-cross-origin
Date: Tue, 24 Nov 2020 19:08:05 GMT
Content-Length: 194559
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
<!DOCTYPE html>
<html dir="ltr" class="" lang="en">
<head>
You can notice that the request contains an Origin header, but no Access-Control-Allow-Origin header is present in the response. When trying to pass an access token or authentication cookie via an XMLHttpRequest endpoint, the security token becomes invalid. Instead of returning a 401 HTTP status code, the API redirects to the Microsoft Entra ID sign-in page. Because of this redirect, and Microsoft Entra ID doesn't support CORS for interactive sign-ins, the web browser throws a CORS error.
General solution
Implement your application architecture to follow the OAuth2 and OIDC standards. This solution can ensure your front-end application acquires an access token and includes it in the Authorization header of the request when you make your XMLHttpRequest to the API. Here are some single-page application samples.
Scenario-based solutions
Here are the most common scenarios. Not every scenario is listed in this article as every environment and app architecture is different.
Scenario 1: Web app and Web API using authentication cookies
If your web app or framework makes XMLHttpRequest calls to its API endpoint and uses the Web Apps authentication cookies, examine the XMLHttpRequest request in the Fiddler capture. It might look like this:
GET https://app.domain.com/… HTTP/1.1
Host: login.microsoftonline.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Origin: https://app.domain.com
Cookie: .AspNet.Cookies=xyz…
If you use ASP.NET or ASP.NET Core, configure Microsoft Entra ID to avoid using token lifetime as the session lifetime. For more information, see Customize middleware authentication ticket to extend user sign-in duration. You can configure the API authentication to throw an error instead of performing a redirect. For ASP.NET Core, you can use the following code:
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Events.OnRedirectToIdentityProvider = (context) =>
{
if (!context.Request.Headers["Origin"].IsNullOrEmpty())
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.HandleResponse();
}
return Task.FromResult(true);
};
}
Then, implement extra XMLHttpRequest logic to check if the request is complete and it's a redirect or a 401 error. You must perform the action to tell the client to have the user sign-in again. In most cases, refreshing the page allows the user to reauthenticate. Here's a code exmaple:
client.onreadystatechange = () => {
// API call failed (401) or there was a redirect
if ((client.readyState === client.DONE && client.responseURL == "") || client.Status == 401) {
// Handle error such as Refreshing page should allow user to re-authenticate
window.location.reload(true)
}
};
Scenario 2: Standalone API using access tokens
Review the Fiddler capture and look at the XMLHttpRequest request, it might look like this (notice the Authorization header):
GET https://app.domain.com/… HTTP/1.1
Host: login.microsoftonline.com
Connection: keep-alive
Authorization: Bearer eyJ0…
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Origin: https://app.domain.com
To resolve the issue in this scenario, use one of the following methods:
Method 1: Send a valid token
If you pass an access token to your API resource, ensure the token is valid. Check if the token is expired. If it is, request a new access token. If you use Microsoft Authentication Library for JavaScript (MSAL.js), use acquireTokenSilent every time to acquire a new token before passing it to your API. Don't cache this token yourself. Always use acquireTokenSilent to get the cached token directly from MSAL.
For more information, see Single-page application: Acquire a token to call an API.
Here's is an example of how it looks when passing a token to an API: Single-page application: Call a web API.
Method 2: Use JWT bearer authentication
Use JWT Bearer authentication instead of Open ID Connect. This implementation depends on your authentication middleware, so review its documentation because each middleware has its own implementation strategy. JWT Bearer Authentication should throw a 401 error to the client if the token isn't valid. The client should handle the error and request a new token as needed. If Open ID Connect Authentication scheme is used, the API tries to redirect the request to Microsoft Entra ID or B2C, leading to CORS errors. It's difficult for the client to handle this scenario.
Here are a couple examples on how to set up JWT Bearer authentication: Microsoft identity platform code samples for authentication and authorization.
Scenario 3: Using MSAL.js with B2C or third-party IdP
Make sure you configure authority, knownAuthorities, and protocolMode correctly.
//…
import { ProtocolMode } from '@azure/msal-common';
//…
function MSALInstanceFactory(): IPublicClientApplication {
return new PublicClientApplication({
auth: {
authority: 'https://contoso.b2clogin.com/tfp/655e51e9-be5e-xxxx-xxxx-38aa6558xxxx/b2c_1_susi/v2.0/',
clientId: 'fb2ad7b7-2032-4a66-8723-e993eb4b9004',
redirectUri: 'http://localhost:4200',
knownAuthorities: ['contoso.b2clogin.com'],
protocolMode: ProtocolMode.OIDC
},
});
}
For more information, see MSAL.js configuration options.
Scenario 4: App is behind a load balancer
If your application is behind a load balancer, check the session lifetime settings of your load balancer, such as Session persistence or session affinity.
Scenario 5: CORS error on token endpoint
The only supported flow for Single Page Applications is Authorization Code Flow with Proof Key for Code Exchange (PKCE) and Refresh Token Flow while having the redirect address configured as a Single Page Application.
Based on OAuth2 specs and Security best practices, don't use the following flows:
- Resource Owner Password Credential (ROPC)
- Confidential Client flows, such as Client Credentials or On-behalf-of flows
All other flows aren't supported in Single Page Applications. Microsoft Entra ID and B2C don't add the CORS headers for the unsupported flows.
Scenario 6: Using Microsoft Entra Application Proxy
If your app uses Microsoft Entra Application Proxy, see Understand complex applications in Microsoft Entra application proxy.
References
- Enable Cross-Origin Requests (CORS) in ASP.NET Core
- Enable Cross-Origin Requests in ASP.NET Web API 2
- Azure App Service REST API tutorial
- Azure API Management CORS policy
Contact us for help
If you have questions, you can ask Azure community support. You can also submit product feedback to Azure feedback community.