CORS error when initiating silent auth requests

Problem statement

The silent authentication call succeeds from the root URL of our app but keeps failing when called from an API route.

Cause

The ./authorize request should be a regular interactive navigation, not done from JavaScript.
The most likely problem here is that an API is redirecting to authorize and the JavaScript doing the request is following that redirection.

Solution

Usually, people code API services so that they return 401 errors when an authorization is missing or invalid. Redirection to authorize should only happen on requests that are meant to be driven by the browser, not by JavaScript (i.e. where the content type is HTML, images, and so on). JavaScript should not make an ./authorize request.

What’s a cross-origin request?
When a page from one origin (e.g. https://myapp.com) makes a request to another origin (e.g. https://otherorigin.com).

What is CORS (Cross-origin resource sharing)?
CORS is a technique/protocol that allows a server to indicate what cross-origin requests are allowed.

Javascript requests made from one origin are subjected to the Same Origin Policy: the browser will block requests to other origins when made from JavaScript unless there’s a CORS policy defined (i.e. the server says “it’s okay to receive requests from this other origin”).

So if your SPA at https://myspa.com wants to make a Javascript request to https://yourtenant.auth0.com/oauth/token, that endpoint needs to be OK with cross-origin requests. It does so by implementing CORS (returning the right headers that say “I can receive requests from the https://myspa.com origin”).

Now, all requests to /authorize are NOT Javascript requests, so the Same Origin Policy does not apply. Authorize requests are full-page navigations (or full-page IFRAME navigations), so no CORS is necessary.

The fact that you get a CORS error from the /authorize endpoint means that:

  • You tried to make a Javascript request to the /authorize endpoint which is a wrong implementation of it.
  • You tried to make a request to another endpoint (e.g. https://myapi.com) and that endpoint REDIRECTED to /authorize. The Javascript request followed that redirection and ended up trying to make a request to /authorize, ending in the CORS error. API endpoints, which will be called by Javascript, should Not redirect to /authorize.

Only interactive flows (e.g. a web page that returns HTML, one that a user visits) should redirect to /authorize. An API HTTP service is meant to be used by other code, not by users directly, so it should not return redirections to /authorize if the authorization fails. It should return 401.

For example, try making a request to https://yourtenant.auth0.com/api/v2/users without a token: it will return 401, but it won’t redirect you to https://auth0.auth0.com/authorize.
Try making a request to https://manage.auth0.com from an incognito window and it will redirect you to https://auth0.auth0.com/authorize because it’s a web page, and wants you to be authenticated.


If I do:

const response = await request("https://mydomain.auth0.com/authorize[...]")

That’s a Javascript request. If it’s done from a different domain, that’s where CORS plays a role.

If I type https://mydomain.auth0.com/authorize[....] in the address bar. That’s a full-page navigation. No CORS. That’s how /authorize is supposed to be used.

If I type https://myapp.com and it redirects to /authorize, that’s still a full-page navigation. No CORS.

If I do:

const response = await request("https://myapiserver.com/api/users");

and the API server returns a 301 redirect to /authorize, that’s a wrong API design, and if request() follows that redirection, then that will be a cross-origin /authorize request, which is a wrong implementation.

1 Like