Skip to content

Commit 033e770

Browse files
authored
Merge pull request #9282 from MicrosoftDocs/main
Auto push to live 2025-07-08 02:35:22
2 parents 6757d0b + 5a399ac commit 033e770

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
---
2+
title: Troubleshoot Cross-Origin Resource Sharing Issues
3+
description: Helps you troubleshoot and resolve Cross-Origin Resource Sharing issues when using Microsoft Entra ID.
4+
ms.service: entra-id
5+
ms.date: 07/08/2025
6+
ms.reviewer: willfid, v-weizhu
7+
ms.custom: sap:Developing or Registering apps with Microsoft identity platform
8+
---
9+
# Troubleshoot CORS issues with Microsoft Entra ID
10+
11+
This article provides guidance on troubleshooting and resolving Cross-Origin Resource Sharing (CORS) errors encountered when using Microsoft Entra ID.
12+
13+
## Understanding CORS
14+
15+
[Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/docs/Web/HTTP/Guides/CORS) is an [HTTP](https://developer.mozilla.org/docs/Glossary/HTTP)-header-based mechanism that allows a server to specify [origins](https://developer.mozilla.org/docs/Glossary/Origin)(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.
16+
17+
For detailed information about CORS headers, refer to [CORS headers](https://developer.mozilla.org/docs/Glossary/CORS).
18+
19+
### Key concepts
20+
21+
- Browsers block cross-origin requests if the resource lacks the supported headers.
22+
- Cross-origin requests usually originate from JavaScript XMLHttpRequest calls, such as a direct HTTP call with no user interaction or window.
23+
- 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.
24+
25+
## Symptoms
26+
27+
While developing an application, you might encounter the following CORS-related errors in the browser console logs:
28+
29+
- Example 1
30+
31+
> 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.
32+
33+
The URL starting with `https://login.microsoftonline.com/` indicates that you might have an Azure Active Directory B2C scenario.
34+
- Example 2
35+
36+
> 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.
37+
- Example 3
38+
39+
> CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present.
40+
41+
> [!NOTE]
42+
>
43+
> - These errors are generated by Microsoft Entra ID. Request URLs in these errors often begin with `https://login.microsoftonline.com` or `https://<your-domain>.b2clogin.com`. The latter typically points to an Azure Active Directory B2C scenario.
44+
> - 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.
45+
46+
## Cause
47+
48+
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/`.
49+
50+
### Example request and response
51+
52+
Request:
53+
54+
```http
55+
GET https://login.microsoftonline.com.com/domain.onmicrosoft.com/oauth2/v2.0/authorize?... HTTP/1.1
56+
Host: login.microsoftonline.com
57+
Connection: keep-alive
58+
Upgrade-Insecure-Requests: 1
59+
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
60+
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
61+
Accept-Encoding: gzip, deflate, br
62+
Accept-Language: en-US,en;q=0.9
63+
Origin: https://app.domain.com
64+
```
65+
66+
Response:
67+
68+
```http
69+
HTTP/1.1 200 OK
70+
Cache-Control: no-store, no-cache
71+
Pragma: no-cache
72+
Content-Type: text/html; charset=utf-8
73+
Expires: -1
74+
Vary: Accept-Encoding
75+
Strict-Transport-Security: max-age=31536000; includeSubDomains
76+
X-Content-Type-Options: nosniff
77+
X-Frame-Options: DENY
78+
X-DNS-Prefetch-Control: on
79+
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
80+
Set-Cookie: ...
81+
Referrer-Policy: strict-origin-when-cross-origin
82+
Date: Tue, 24 Nov 2020 19:08:05 GMT
83+
Content-Length: 194559
84+
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
85+
<!DOCTYPE html>
86+
<html dir="ltr" class="" lang="en">
87+
<head>
88+
```
89+
90+
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.
91+
92+
## General solution
93+
94+
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](/entra/identity-platform/sample-v2-code?tabs=apptype).
95+
96+
## Scenario-based solutions
97+
98+
Here are the most common scenarios. Not every scenario is listed in this article as every environment and app architecture is different.
99+
100+
### Scenario 1: Web app and Web API using authentication cookies
101+
102+
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:
103+
104+
```http
105+
GET https://app.domain.com/… HTTP/1.1
106+
107+
Host: login.microsoftonline.com
108+
Connection: keep-alive
109+
Upgrade-Insecure-Requests: 1
110+
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
111+
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
112+
Accept-Encoding: gzip, deflate, br
113+
Accept-Language: en-US,en;q=0.9
114+
Origin: https://app.domain.com
115+
Cookie: .AspNet.Cookies=xyz…
116+
```
117+
118+
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](customize-authentication-session-expiration.md). 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:
119+
120+
```csharp
121+
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
122+
{
123+
options.Events.OnRedirectToIdentityProvider = (context) =>
124+
{
125+
if (!context.Request.Headers["Origin"].IsNullOrEmpty())
126+
{
127+
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
128+
context.HandleResponse();
129+
}
130+
131+
return Task.FromResult(true);
132+
};
133+
}
134+
```
135+
136+
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:
137+
138+
```http
139+
client.onreadystatechange = () => {
140+
// API call failed (401) or there was a redirect
141+
if ((client.readyState === client.DONE && client.responseURL == "") || client.Status == 401) {
142+
// Handle error such as Refreshing page should allow user to re-authenticate
143+
window.location.reload(true)
144+
}
145+
};
146+
```
147+
148+
### Scenario 2: Standalone API using access tokens
149+
150+
Review the Fiddler capture and look at the XMLHttpRequest request, it might look like this (notice the Authorization header):
151+
152+
```http
153+
GET https://app.domain.com/… HTTP/1.1
154+
155+
Host: login.microsoftonline.com
156+
Connection: keep-alive
157+
Authorization: Bearer eyJ0
158+
Upgrade-Insecure-Requests: 1
159+
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
160+
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
161+
Accept-Encoding: gzip, deflate, br
162+
Accept-Language: en-US,en;q=0.9
163+
Origin: https://app.domain.com
164+
```
165+
166+
To resolve the issue in this scenario, use one of the following methods:
167+
168+
- [Send a valid token](#method-1-send-a-valid-token)
169+
- [Use JWT bearer authentication](#method-2-use-jwt-bearer-authentication)
170+
171+
#### Method 1: Send a valid token
172+
173+
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.
174+
175+
For more information, see [Single-page application: Acquire a token to call an API](/entra/identity-platform/scenario-spa-acquire-token).
176+
177+
Here's is an example of how it looks when passing a token to an API: [Single-page application: Call a web API](/entra/identity-platform/scenario-spa-call-api).
178+
179+
#### Method 2: Use JWT bearer authentication
180+
181+
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.
182+
183+
Here are a couple examples on how to set up JWT Bearer authentication: [Microsoft identity platform code samples for authentication and authorization](/entra/identity-platform/sample-v2-code#web-api).
184+
185+
### Scenario 3: Using MSAL.js with B2C or third-party IdP
186+
187+
Make sure you configure `authority`, `knownAuthorities`, and `protocolMode` correctly.
188+
189+
```http
190+
//…
191+
import { ProtocolMode } from '@azure/msal-common';
192+
//…
193+
function MSALInstanceFactory(): IPublicClientApplication {
194+
return new PublicClientApplication({
195+
auth: {
196+
authority: 'https://contoso.b2clogin.com/tfp/655e51e9-be5e-xxxx-xxxx-38aa6558xxxx/b2c_1_susi/v2.0/',
197+
clientId: 'fb2ad7b7-2032-4a66-8723-e993eb4b9004',
198+
redirectUri: 'http://localhost:4200',
199+
knownAuthorities: ['contoso.b2clogin.com'],
200+
protocolMode: ProtocolMode.OIDC
201+
},
202+
});
203+
}
204+
```
205+
206+
For more information, see [MSAL.js configuration options](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md).
207+
208+
### Scenario 4: App is behind a load balancer
209+
210+
If your application is behind a load balancer, check the session lifetime settings of your load balancer, such as **Session persistence** or session affinity.
211+
212+
### Scenario 5: CORS error on token endpoint
213+
214+
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.
215+
216+
Based on OAuth2 specs and Security best practices, don't use the following flows:
217+
218+
- Resource Owner Password Credential (ROPC)
219+
- Confidential Client flows, such as Client Credentials or On-behalf-of flows
220+
221+
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.
222+
223+
### Scenario 6: Using Microsoft Entra Application Proxy
224+
225+
If your app uses Microsoft Entra Application Proxy, see [Understand complex applications in Microsoft Entra application proxy](/entra/identity/app-proxy/application-proxy-configure-complex-application).
226+
227+
## References
228+
229+
- [Enable Cross-Origin Requests (CORS) in ASP.NET Core](/aspnet/core/security/cors)
230+
- [Enable Cross-Origin Requests in ASP.NET Web API 2](/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api)
231+
- [Azure App Service REST API tutorial](/azure/app-service/app-service-web-tutorial-rest-api)
232+
- [Azure API Management CORS policy](/azure/api-management/cors-policy)
233+
234+
[!INCLUDE [Azure Help Support](../../../includes/azure-help-support.md)]

support/entra/entra-id/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
href: app-integration/repeat-login-prompts-in-msal-ios-app.md
8080
- name: Sign out of OpenID Connect/OAuth2 applications without a user selection prompt
8181
href: app-integration/sign-out-of-openid-connect-oauth2-applications-without-user-selection-prompt.md
82+
- name: Troubleshoot Cross-Origin Resource Sharing issues
83+
href: app-integration/troubleshoot-cross-origin-resource-sharing-issues.md
8284
- name: Troubleshoot protected Web API authentication or authorization errors with Serilog
8385
href: app-integration/serilog-protected-web-api-authentication-authorization-errors.md
8486
- name: Troubleshoot ASP.NET OWIN and ASP.NET Core authentication sign-in failures

0 commit comments

Comments
 (0)