Authorization Code Grant blocked by CORS policy

I am trying to use the Authorization Code Grant with my site. I am able to get the code back from the oauth authorize redirect (i.e. login to Genesys Cloud). But when I make the post to https://login.mypurecloud.com/oauth/token I receive the following error:

Access to XMLHttpRequest at 'https://login.mypurecloud.com/oauth/token' from origin 'https://localhost:8081' 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.

I am using Vue for the site and Axios to make the requests to APIs. Here is my code:

const token = Buffer.from(`${client_id}:${client_secret}`, 'utf8').toString('base64')
    const getOAuthToken = () =>  axios({
        method: "post",
        url: "https://login.mypurecloud.com/oauth/token",
        data: {
            grant_type: "authorization_code",
            code: storedCode, //from the query string parameters sent to this url
            redirect_uri : "https://localhost:8081/login"
            },
        headers: {"Content-Type" : "application/x-www-form-urlencoded",
        "Authorization": `Basic ${token}`}
    });

    getOAuthToken()
        .then(response => {
            this.info = response;
            })
            .catch(error => {
                this.errormsg = error;
            console.log(error);
        })

I have posted this to httpbin and the headers look correct:

"headers": { "Accept": "application/json, text/plain, /", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en-US,en;q=0.9", "Authorization": "Basic NWQ4MzhhNWYtYmZjZS00NTRlLTg5ZWItYzgwNWFkYTMwZTQwOkNsQkxTdUZFQVRZQ2JQN2ZBajVoTUc4bl8wYk1YYjdWUmVNWjlCc2hQZUE=", "Content-Length": "134", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "Origin": "https://localhost:8081", "Referer": "https://localhost:8081/login", "Sec-Fetch-Dest": "empty", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Site": "cross-site", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36", "X-Amzn-Trace-Id": "Root=1-5ec987cd-81f44c7eab9d49e48e0850a5" }

Lastly, my redirect URIs in the OAuth Client are:
https://localhost:8081
https://localhost:8081/
https://localhost:8081/login

Hello,

You have something which appears to be incorrect in your axios request.

From axios on this page: https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format
By default, axios serializes JavaScript objects to JSON. To send data in the application/x-www-form-urlencoded format instead, you can use one of the following options.

I have tried the authorization code grant using the corresponding tutorial code and it worked for me.

I have then modified the code to make the request to https://login.mypurecloud.com/oauth/token (your getOAuthToken method) using axios.
AND I also modified the code as indicated by axios using querystring approach for the data parameter.
And this worked for me (running local web server on my computer using nodejs https).

data: querystring.stringify({
    grant_type: "authorization_code",
    code: storedCode,
    redirect_uri: "https://localhost:8081/login"
}),

My OAuth client (Authorization Code) references https://localhost:8081/login as Authorized Redirect Uri

Before making the modification to the data parameter (to use querystring to encode the form data - as it is application/x-www-form-urlencoded), I didn't have the type of error you have printed above. The error was simply a 400 - Bad Request.
So you may have other things to fix (maybe in the rest of your code) if using querystring to encode your form data is not enough.

Regards,

So, yes, I was able to re-do the example using Axios. However, through much googling and research I've found that the problem is not an Axios problem - it is a problem that will affect anyone using Vue, Angular, or React which are all front-end javascript application "languages" - They run in the browser and not on a server.

Browser security doesn't allow you to make cross-domain requests except if the HTTP(S) response from the server has a Control-Allow-Origin header with a * value or the domain of your client.

CORS (Cross-Origin Resource Sharing) is a way for the server to say “I will accept your request, even though you came from a different origin.” This requires cooperation from the server.

Best Explanation of how this works: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

How to fix it

Best: CORS header (requires server changes)
Modify the server to add the header Access-Control-Allow-Origin: * to enable cross-origin requests from anywhere (or specify a domain instead of * ).

2nd choice: Proxy Server
If you can’t modify the server, you can run your own proxy. And this proxy can return the Access-Control-Allow-Origin header if it’s not at the Same Origin as your page. Instead of sending API requests to some remote server, you’ll make requests to your proxy, which will forward them to the remote server.

You must not use the auth code grant for a front-end application. This would require the front-end application to know the client secret, which means it will be exposed to the website user; it is impossible for a browser app to handle a client secret securely. It is purposeful that responses for API requests made using an auth code grant do not have CORS headers because you must not use the auth code grant in a browser. Front-end applications must use the implicit grant. API responses for requests using the implicit grant will have CORS headers.

If your back-end server is going to be making the API requests, only then you would use the code grant.

Yes, okay, I had a feeling that that was the case. Thank you for the quick response and confirmation. One of the reasons I posted this was so that when other people try to do what I tried, they will finally find something that says "this can't and shouldn't be done so you can end your quest to find a solution to this."

In other words, if you are going to use Vue, React, or Angular and make front-end Genesys Cloud API requests, you must use Implicit Grant.

For info, it is mentioned in the following pages:
Create an OAuth client, Grant Implicit, Grant Authorization Code

For Implicit Grant:
"is ideal for client-side browser applications (i.e. JavaScript) and most desktop applications (e.g. .NET WPF/WinForms or Java desktop programs)."

For Authorization Code Grant:
"ideal for websites where API requests will be made server-side (e.g. ASP.NET or PHP) and some desktop applications where a thin client would authorize the user and pass the auth code to a back-end server to exchange for an auth token and make API requests."

1 Like

This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.