UPS API CORS header problem, ‘Access-Control-Allow-Origin’ missing. Can I do it from user’s browser?

Alright, I’ve read a LOT about this issue now from many StackOverflow posts. But I still have concerns about the solutions.

Here’s a bit about my project:

I have a web app that runs Java server code, and of course some Javascript on the browser side. I am beginning to integrate functions of the UPS API, newly requiring the OAuth authentication setup.

I’m using UPS’s examples at https://developer.ups.com/api/reference?loc=en_US#operation/GenerateToken . I’ve been able to have my Java server code making requests and getting responses OK… so it gets an access token and it validates an address for me.

However I think I want to do this in the web browser’s Javascript because it will greatly cut down on the amount of requests flying around, and like be a little quicker.

With OAuth-

Java servlet communication with UPS API to validate an address:

  • Button hit by user
  • -> browser Javascript sends address to Java servlet
  • -> Java servlet sends request for access token to UPS API server
  • -> UPS API server sends access token response to Java servlet
  • -> Java servlet sends address validation request to UPS API server
  • -> UPS API server sends address validation result response to Java servlet
  • -> Java servlet sends address validation result to browser Javascript

Now the access token may be saved from a previous request, and I implement it that way, but this is where I’m starting. I have this working.

Here it is relying more on communication with the UPS API by the user’s web browser:

  • Button hit by user
  • -> browser Javascript sends request for access token to UPS API server
  • -> UPS API server sends access token response to browser Javascript
  • -> browser Javascript sends address validation request to UPS API server
  • -> UPS API server sends address validation result response to browser Javascript

This way requires two less transits between the user’s browser and the Java servlet.

So I’m trying to implement UPS’s example at the link above for Javascript, and I get the CORS errors in my browser.

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://onlinetools.ups.com/security/1/oauth/token. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 403.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://onlinetools.ups.com/security/1/oauth/token. (Reason: CORS request did not succeed). Status code: (null).

One of the best descriptions I’ve read of the problem is here https://stackoverflow.com/a/43268098/620054

From what I read, the solutions are to either have my server do it, like the top situation, or to have a proxy server running that will basically just add on the Access-Control-Allow-Origin header to the response so that the browser does not complain. This is UPS so I don’t have control of the API server. I don’t want to rely on client browser configuration. Is this the best there is? People have Javascript making requests to APIs from the client’s web browser, right? What am I missing?

Here is my Javascript code below for attempting to get an access token. But it’s nearly the same as the UPS example at the first link.

async function upsApiGetAccessToken() {

    var version = "1";
    var requestPathname = "/security/" + version + "/oauth/token";
    var requestUri = UPS_API_HOST + requestPathname;

    const requestParams = {
        code: 'string',
        redirect_uri: 'string',
        grant_type: 'client_credentials'
    };

    const resp = await fetch(
        requestUri,
        {
            mode: 'cors',
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                Authorization: 'Basic ' + btoa(UPS_API_CLIENT_ID + ':' + UPS_API_CLIENT_SECRET)
            },
            body: new URLSearchParams(requestParams).toString()
        }
    );

    const data = await resp.text();
    console.log(data);

}