OAuth CORS issues w/ front-end react app

I am trying to authenticate my app against your SDK - I am working in the React framework using typescript.

I am using the OAuth2 PKCE route and I have managed the first step requesting a code using a popup window and the https://applications.frame.io/oauth2/auth endpoint.

From the token request response I can harvest the token value and I then attempt a POST request to get an authorization code. This goes to the https://applications.frame.io/oauth2/token endpoint but immediately fails because it does not pass the CORS preflight. As I understand it that means that your /oauth2/token endpoint does not permit connections from anywhere with a Access-Control-Allow-Origin: * header.

Without this in place it means that authentication can only ever be from server to server i.e. I have to create a proxy in order to access content from your site - surely that cannot be the intention?

Please let me know if I have this wrong, happy to be corrected as this is extremely frustrating. Also happy to share code if required.

Hi Alex, sorry you are running into this issue. Please pass an additional parameter: “allowed_cors_origins”: [“https://foo-bar.com/”] on your request.

Normally this is server to server ( even if it is on the node server ). So we do not have a good example, we will put this on our backlog. Our apologies.

Otherwise you could use the implicit grant which would get you the access token without having to make the second request. Although due to security concerns, this is undesirable.

Happy to work on code samples with you if these options are not working. This flow should definitely work without an intermediary proxy.

The reason the first request works is because the OAuth 2.0 Authorization Endpoint ( /oauth2/auth ) does not expose CORS by design. Since we don’t know where it is coming from.

Hope this helps.

Thanks for your response - I’ve tried adding the allowed_cors_origins parameter but I’m still getting blocked - debugging the popup window I can see that in the response from the consent_challenge request the client allowed cors origins list is not set. I’ve tried passing the parameter as a JSON formatted string and as a search parameter with no joy.

Here is a clip of the code sending the initial request:

    const handleLoginClick = () => {
        const width = 400;
        const height = 700;
        const left = window.screenX + (window.outerWidth - width) / 2;
        const top = window.screenY + (window.outerHeight - height) / 2.5;
        const features = `width=${width},height=${height},left=${left},top=${top}`;
        const origin = window.location.origin;
        const query = new URLSearchParams({
            response_type: "code",
            redirect_uri: origin,
            client_id: clientId,

        query.append("allowed_cors_origins", origin);
        const popup = window.open(`${url}?${query.toString()}`, title || "Authentication", features);


Following that I have an interval monitoring for a response in the popup and then with the code returned I then build a post request which is bouncing off the CORS limitation.

Hi Alex – sorry it wasn’t perfectly clear in my initial response. That parameter should be supplied on the post request following the redirect.

That is the request that is being blocked by CORS - Adding the parameter there is never going to get read - do you mean I have to pass it to a preflight request before sending the POST? I’ve tried it regardless and received this response:

Access to fetch at ‘https://applications.frame.io/oauth2/token’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: 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.

Hi Alex, sorry you have been unable to get this to work. Any reason to not just use the implicit flow?

Hi Austin, I’d rather not but I guess it sounds like I might have to - but without unlocking some mechanism for adding a CORS allowed host on your token endpoint you should really remove it from your help documentation - I’ve spent a day on this and got nowhere - probably the reason for a slightly spiky subject line in the forum :slight_smile:

So my app is on a single public page - using the React framework - it is not being built on a server so I have nowhere to keep my client secret private. I could work on a server proxy which can hold a secret but I’d rather keep it direct. Just so I am clear, as it stands your oauth2 token endpoint does not have anything set for Access-Control-Allow-Origin and you are not able or prepared to change this, is that correct?

I will try with the implicit flow instead - though obviously this is compromising security to an endpoint that has an inherent value so it’s not an attractive solution.


So I have had no success with implicit flow either and I wonder if I could just check the flow - your documentation only covers PKCE or using a client_secret which is not appropriate for a web page.

At the moment I start by opening a second (popup) window directed to https://applications.frame.io/oauth2/auth and send a GET request with these parameters set:
{response_type: "token", redirect_uri: "http://localhost:3000", client_id:<CLIENT_ID>, scope: "asset.read account.read offline", state: <GENERATED_HASH>}

From this request I successfully recover an access_token value from the redirected header and can then use that in a request for assets, which is another GET request, this time to https://api.frame.io/v2/projects/shared with the headers set to:
{Authorization: "Bearer <ACCESS_TOKEN>"}

What I get back is the response:
{"code":401,"errors":[{"code":401,"detail":"You are not allowed to access that resource","status":401,"title":"Not Authorized"}],"message":"Not Authorized"}

Where am I going wrong?

Glad to hear you made some progress!

The reason you can’t access the shared projects endpoint is because you didn’t request the correct permission: project.read.