How To
ForgeRock Identity Platform
Does not apply to Identity Cloud

How do I troubleshoot issues with the CORS filter in AM (All versions)?

Last updated Aug 9, 2021

The purpose of this article is to provide pointers on how to troubleshoot and resolve issues with the Cross-origin resource sharing (CORS) filter in AM.


2 readers recommend this article

Troubleshooting techniques

You should use the following approach to troubleshoot issues with the CORS filter:

  1. Check that all headers included in the CORS request have been whitelisted otherwise the browser will block the request. You can whitelist the headers by ensuring they are included in the Access-Control-Allow-Headers header. See Configuring CORS Support for further information.
  2. Make a direct curl call to the required endpoint to check that the CORS request headers come back as expected. This will help you verify that CORS is set up correctly for a particular endpoint. See Check CORS is set up correctly for an endpoint for examples.
  3. Set debug logging level to Message or Warning level, and grep for "WARNING: CORS Fail" in the CoreSystem log. Then find the corresponding section in this article to resolve your issue. You can enable message level debugging as described in Debug Logging (AM 7 and later) or How do I enable Message level debugging in AM (All versions) debug files?
  4. Obtain an HTTP Trace of the failing flow in your browser. You can do this by capturing a HAR file as described in How do I create a HAR file for troubleshooting AM (All versions)?
    • If the issue happens in some browsers (for example, Chrome™), but not in others (for example, Firefox®), obtain an HTTP Trace from the working flow to allow comparison.

The following issues are detailed in this article:

Check CORS is set up correctly for an endpoint

You can check that CORS is set up correctly for a particular endpoint by making a direct curl call. The following examples show a working versus a couple of non-working setups for comparison.

Working setup (json)

This example demonstrates a working setup, where a direct call to the json endpoint brings back all the expected CORS response headers.

Example call:

$ curl -v -X OPTIONS -H "Origin: http://other.origin.example.com" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: X-Requested-With" http://host1.example.com:8080/openam/json/authenticate

Example response:

* About to connect() to host1.example.com port 8080 (#0) * Trying 198.51.100.0... * Connected to host1.example.com (198.51.100.0) port 8080 (#0) > OPTIONS /openam/json/authenticate HTTP/1.1 > User-Agent: curl/7.29.0 > Host: host1.example.com:8080 > Accept: */* > Origin: http://other.origin.example.com > Access-Control-Request-Method: POST > Access-Control-Request-Headers: X-Requested-With > < HTTP/1.1 200 OK HTTP/1.1 200 OK < Server: Apache-Coyote/1.1 Server: Apache-Coyote/1.1 < X-Frame-Options: SAMEORIGIN X-Frame-Options: SAMEORIGIN < Access-Control-Allow-Methods: POST,PUT,GET,DELETE,OPTIONS Access-Control-Allow-Methods: POST,PUT,GET,DELETE,OPTIONS < Access-Control-Allow-Headers: cookie,origin,accept,x-requested-with,authorization,accept-api-version,origin,accept,x-requested-with,content-type,access-control-request-method,access-control-request-headers,authorization,content-type,iplanetdirectorypro,x-openam-username,x-openam-password,accept,accept-encoding,connection,content-length,host,origin,user-agent,accept-language,referer,dnt,accept-api-version,if-none-match Access-Control-Allow-Headers: cookie,origin,accept,x-requested-with,authorization,accept-api-version,origin,accept,x-requested-with,content-type,access-control-request-method,access-control-request-headers,authorization,content-type,iplanetdirectorypro,x-openam-username,x-openam-password,accept,accept-encoding,connection,content-length,host,origin,user-agent,accept-language,referer,dnt,accept-api-version,if-none-match < Access-Control-Max-Age: 600 Access-Control-Max-Age: 600 < Access-Control-Allow-Origin: http://other.origin.example.com Access-Control-Allow-Origin: http://other.origin.example.com < Content-Length: 0 Content-Length: 0 < Date: Wed, 16 Jan 2019 16:29:14 GMT Date: Wed, 16 Jan 2019 16:29:14 GMT < * Connection #0 to host host1.example.com left intact

Non-working setup (json) 

This example demonstrates a non-working setup, where a direct curl call to the authenticate endpoint results in a 501: Not Implemented response.

Example call:

$ curl -v -X OPTIONS -H "Origin: http://other.origin.example.com" -H "Access-Control-Request-Method: OPTIONS" -H "Access-Control-Request-Headers: X-Requested-With" http://host1.example.com:8080/openam/json/authenticate

Example response:

* About to connect() to host1.example.com port 8080 (#0) * Trying 198.51.100.0... * Connected to host1.example.com (198.51.100.0) port 8080 (#0) > OPTIONS /openam/json/authenticate HTTP/1.1 > User-Agent: curl/7.29.0 > Host: host1.example.com:8080 > Accept: */* > Origin: http://other.origin.example.com > Access-Control-Request-Method: OPTIONS > Access-Control-Request-Headers: X-Requested-With > < HTTP/1.1 405 < Date: Mon, 10 May 2021 11:32:04 GMT < Content-Type: application/json;charset=UTF-8 < Content-Length: 67 < Connection: keep-alive < Set-Cookie: iPlanetDirectoryPro=AQIC5wM2LY4SfcxsuvGEjcsppDSFR8H8DYBSouTtz3m64PI.*AAJTSQACMDIAAlNLABQtNTQwMTU3NzgxODI0NzE3OTIwNAEwNDU2NjE0*; Expires=Mon, 17 May 2021 11:32:04 GMT; Path=/; SameSite=None; Secure < X-Frame-Options: SAMEORIGIN < Content-API-Version: resource=2.1 < * Connection #0 to host host1.example.com left intact {"code":501,"reason":"Not Implemented","message":"Not Implemented"}

This response indicates a misconfiguration issue, where the details in the curl command do not match what has been specified in the web.xml file. This can be something as simple as a typo in one of the headers or a mismatch between details in the curl command and the web.xml file. You should check your curl command and the web.xml file for any discrepancies. 

Common mismatches to check for are: 

  • The Origin specified in the curl call does not exactly match one of the origins in the web.xml file, including ports. You should check the origins section, for example:<param-name>origins</param-name> <param-value>http://other.origin.example.com,http://another.origin.com:8080</param-value>
  • The Access-Control-Request-Headers specified in the curl call includes a header, which is not allowed in the web.xml file. You should check the cors.allowed.headers section, for example:<param-name>cors.allowed.headers</param-name> <param-value>Authorization,Content-Type,X-Requested-With,...</param-value>

Non-working setup (oauth2) 

This example demonstrates a non-working setup, where a direct call to the oauth2 endpoint fails to bring back the expected CORS response headers.

Example call:

$ curl -v -X OPTIONS -H "Origin: http://other.origin.example.com" -H "Access-Control-Request-Method: GET" -H "Access-Control-Request-Headers: X-Requested-With" http://host1.example.com:8080/openam/oauth2/authorize

Example response:

* About to connect() to host1.example.com port 8080 (#0) * Trying 198.51.100.0... * Connected to host1.example.com (198.51.100.0) port 8080 (#0) > OPTIONS /openam/oauth2/authorize HTTP/1.1 > User-Agent: curl/7.29.0 > Host: host1.example.com:8080 > Accept: */* > Origin: http://other.origin.example.com > Access-Control-Request-Method: GET > Access-Control-Request-Headers: X-Requested-With > < HTTP/1.1 405 Method Not Allowed HTTP/1.1 405 Method Not Allowed < Server: Apache-Coyote/1.1 Server: Apache-Coyote/1.1 < X-Frame-Options: SAMEORIGIN X-Frame-Options: SAMEORIGIN < Pragma: no-cache Pragma: no-cache < Cache-Control: no-store Cache-Control: no-store < Date: Wed, 16 Jan 2019 16:33:27 GMT Date: Wed, 16 Jan 2019 16:33:27 GMT < Accept-Ranges: bytes Accept-Ranges: bytes < Content-Type: application/json Content-Type: application/json < Transfer-Encoding: chunked Transfer-Encoding: chunked < * Connection #0 to host host1.example.com left intact {"error_description":"Required Method: GET or POST found: OPTIONS","error":"method_not_allowed"}

This response indicates that the CORSFilter has not been set up for the oauth2 flow. This can be resolved by adding oauth2 to the CORSFilter filter-mapping in the web.xml, for example:

<filter-mapping>        <filter-name>CORSFilter</filter-name>         <url-pattern>/json/*</url-pattern>         <url-pattern>/oauth2/*</url-pattern>     </filter-mapping>

Issue with the Origin

The following warning is displayed in the CoreSystem log:

WARNING: CORS Fail - Requested origin comes from a location not whitelisted.

Troubleshooting

In the HTTP trace, search for a request that contains an Origin Header such as the following; the value of the header indicates where the cross-origin request or Preflight request originates from.

Origin:http://other.origin.example.com:8080

The response to such a request should contain the required Access-Control-Allow-Origin header such as the following; the value (URL's) indicates what origins are allowed when making a CORS request to access the resource.

Access-Control-Allow-Origin:http://other.origin.example.com:8080

Solution

  1. If the Response does not contain this header, check the Accepted Origins section of the CORS filter: <init-param>     <description>          Accepted Origins (Required):          A comma separated list of origins from which to accept CORS requests.      </description>      <param-name>origins</param-name>      <param-value>       http://openam.example.com:8080,https://lb.example.com:443      </param-value> </init-param>
  2. Add the missing origin to this section accordingly. You need to add the exact same value as displayed in the Origin header of the request. For example: <init-param>     <description>          Accepted Origins (Required):          A comma separated list of origins from which to accept CORS requests.      </description>      <param-name>origins</param-name>      <param-value>       http://openam.example.com:8080,https://lb.example.com:443,http://openam.dev.example.com:8080,http://www.example.org:80      </param-value> </init-param>
  3. Restart the web application container in which AM runs.
  4. Re-test the failing flow.

Issue with the Method

The following warning is displayed in the CoreSystem log:

WARNING: CORS Fail - Requested HTTP method has not been whitelisted.

Troubleshooting

In the HTTP trace, search for a request that contains an Origin Header, such as:

Origin:http://other.origin.example.com:8080

Find the corresponding HTTP method in the CORS requests to AM (Example: GET,POST,PUT,PATCH,OPTIONS,DELETE).

In the following example, the method is POST:

>Connected to host1.example.com (192.168.57.6) port 8080 (#0) > POST /openam/json/authenticate HTTP/1.1 > Host: host1.example.com:8080 > User-Agent: curl/7.43.0 > Accept: */* > cache-control: no-cache > content-type: application/json > Origin: http://other.origin.example.com:8080

Solution

  1. Check the Accepted Methods section of the CORS filter for each method highlighted above: <init-param>    <description>         Accepted Methods (Required):         A comma separated list of HTTP methods for which to accept CORS requests.     </description>     <param-name>methods</param-name>     <param-value>PUT</param-value> </init-param>
  2. Add the missing methods to this section accordingly: <init-param>    <description>         Accepted Methods (Required):         A comma separated list of HTTP methods for which to accept CORS requests.     </description>     <param-name>methods</param-name>     <param-value>POST,PUT</param-value> </init-param>
  3. Restart the web application container in which AM runs.
  4. Re-test the failing flow.

Issue with the hostname

The following warning is displayed in the CoreSystem log:

WARNING: CORS Fail - Expected hostname does not equal actual hostname.

Troubleshooting

In the HTTP trace, search for a request that contains an Origin Header, such as:

Origin:http://other.origin.example.com:8080

In the same request, check the Host header; the host is the domain the request is being sent to.

Host: host1.example.com:8080

Solution

  1. The exact hostname must be present in the CORS filter, in the Expected Hostname section: <init-param>   <description>        Expected Hostname (Optional):        The name of the host expected in the request Host header.    </description>    <param-name>expectedHostname</param-name>    <param-value>http://host1.example.com:8080</param-value> </init-param>
  2. Remove or comment out the Expected Hostname section in the CORS filter if you need more than one hostname (for example, if you use a load balancer) as AM does not accept lists of Expected Hostnames.
  3. Restart the web application container in which AM runs.
  4. Re-test the failing flow.

Issue with Request Headers

The following error can happen with Preflight requests. Such requests use the OPTIONS method:

WARNING: CORS Fail - Preflight request contained the Access-Control-Request-Headers headers with an invalid value.
Note

The OPTIONS method does not need to be added as an Accepted Method in the filter as it is accepted by default.

Troubleshooting

In the HTTP trace, search for a request that contains an Access Control Request Headers such as the following; this header is issued during the preflight request to indicate which HTTP headers will be used when the actual request is made.

Access-Control-Request-Headers:<header-name>, <header-name>, ...

The response to this preflight request should include the required Access-Control-Allow-Headers response header containing the header names that can be used in the actual request:

Access-Control-Allow-Headers:<header-name>[, <header-name>]*

If there is no header match the preflight will fail and you will not see the Access-Control-Allow-Headers.

Solution  

  1. Check the Allowed Headers section of the CORS filter if the Response does not contain the requested header: <init-param>   <description>        Allowed Headers (Optional):        A comma separated list of HTTP headers which can be included in the requests.    </description>    <param-name>headers</param-name>    <param-value>header-name,header-name</param-value> </init-param>
  2. Add the missing header to this section accordingly, for example: <init-param>   <description>        Allowed Headers (Optional):        A comma separated list of HTTP headers which can be included in the requests.    </description>    <param-name>headers</param-name>    <param-value>iPlanetDirectoryPro,X-OpenAM-Username,X-OpenAM-Password,Accept-API-Version,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value> </init-param>
  3. Restart the web application container in which AM runs.
  4. Re-test the failing flow.

Issue with 302 returned on /UI/Login URL (AM 5, 5.5, 5.5.1, 6.0.0.x and 6.5.0.x)

The redirect to the login page fails; you get a 302 response for an OPTIONS request (Preflight request) when attempting to access a /UI/Login URL. This scenario typically occurs when you have a web agent configured in your deployment.

The following error is shown in the console logs:

Response for preflight is invalid (redirect)

Troubleshooting

The browser does not accept an HTTP 302 redirect as a response to a Preflight request, which is why you see the console error.

When you attempt to access the /UI/Login URL, AM tries to redirect you to the XUI equivalent ( /XUI/#login) based on the XUIFilter filter-mapping. If a Web Agent is used where the old /UI/Login (login URL) is used to generate the OAuth2 based login then the ordering matters as the CORS request may not be handled.

Solution

  1. Move the CORSFilter filter-mapping in the web.xml file to just before the XUIFilter filter-mapping, for example: <filter-mapping>        <filter-name>CORSFilter</filter-name>         <url-pattern>/*</url-pattern>     </filter-mapping>   <filter-mapping>     <filter-name>XUIFilter</filter-name>
  2. Restart the web application container in which AM runs.
  3. Re-test the failing flow.
Note

There is an RFE to move the CORSFilter filter-mapping position in the default web.xml file: OPENAM-11863 (CORSFilter position in web.xml should come before most filters), which is implemented in AM 5.5.2; AM 6.5.1 and later.

Issue with cookie missing in request header using Chrome

The cookie information is missing from the request in Chrome but is included in other browsers.

If you use XHR or Fetch API calls, and you're using a Web Agent with CORS (or same-origin limitation) you need to ensure your client code sends the "same-origin" cookie in the request. For example, if you have a Web Agent configured, the agent needs the Agent SSO cookie to be present in the request for permitting access to the protected application.

In Chrome 67 and earlier, the Fetch API does not send cookies to the Web server by default. Chrome 68 and later introduced changes to send these cookies by default. See Fetch API: Credentials mode default to "same-origin" and Fetch Standard for further information.

Solution (for Chrome 67 and earlier)

  1. Update your scripts to change the credentials setting for the Fetch API from 'omit' to 'same-origin'. For example: "credentials: 'same-origin'"
  2. Restart the web application container in which AM runs.
  3. Re-test the failing flow.

See Also

Login page in AM (All versions) hangs on Loading when CORS is enabled

SameSite cookie support in AM and IG

Configuring CORS Support

About IG As an UMA Resource Server

Related Training

N/A

Related Issue Tracker IDs

OPENAM-11863 (CORSFilter position in web.xml should come before most filters)

OPENAM-9890 (Allow list in expected Hostname section of CORS Filter)

OPENAM-8811 (allow wildcarding for origins in CORSFilter)

OPENAM-5984 (The XUI is unhappy when the CORS filter is enabled)


Copyright and Trademarks Copyright © 2021 ForgeRock, all rights reserved.