0

I need to allow a user to sign in with google on a TV, so I am using sign-in flow for TVs and Devices (https://developers.google.com/identity/sign-in/devices)

In Postman or with curl, it works fine. However, in my browser, I am getting this CORS error:

XMLHttpRequest cannot load https ://accounts.google.com/o/oauth2/device/code. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http: //localhost:81' is therefore not allowed access. The response had HTTP status code 400.

Here is my code:

var data = {
    client_id: '<my cliendId>',
    scope: 'email'
};
var r = new XMLHttpRequest();
r.open('POST', 'https://accounts.google.com/o/oauth2/device/code', true);
r.setRequestHeader("Content-type", "application/json");
r.onreadystatechange = function () {
    if (r.readyState === XMLHttpRequest.DONE) { 
        if (r.status === 200) {
           console.log('hooray!');
        }
        else {
            console.log('oh no');
        }
    }
};
r.send(JSON.stringify(data));

For web sign-in, it is necessary to redirect the user to google's page, which avoids the CORS issue. But, for TV/device sign-in, I should be getting a code back to display to the user, so that they can go to their computer and grant permission.

Incidentally, this code is in an iframe. I tested it outside of the iframe and had the same problem.

UPDATE I updated the setRequestHeader to 'r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");' and the send to "r.send("client_id=&scope=email");".

  • The console log is telling me "https ://accounts.google.com/o/oauth2/device/code. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:81' is therefore not allowed access.",
  • The Network tab in devtools is showing Status Code = 200 (still nothing in Response),
  • But in the code where I check for r.status, I am seeing status = 0.

Does anyone see an example of using google sign-in for TVs/devices in javascript?

  • 1
    *“The response had HTTP status code 400”* means Bad Request and typically indicates the server received a request in some form that it doesn’t expect. So you probably want to confirm, are you sending the right Content-Type header? If the payload you are sending in that POST is JSON data, then it seems you probably want to be sending a 'Content-Type: application/json' request header — which the code in the question is not doing. – sideshowbarker Sep 22 '17 at 17:49
  • I added 'r.setRequestHeader("Content-type", "application/json");' (reflected above), and my error has changed to: "XMLHttpRequest cannot load https://accounts.google.com/o/oauth2/device/code. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:81' is therefore not allowed access. The response had HTTP status code 405." It just doesn't make sense to me that this sign-in flow wouldn't allow cross-origin requests. – Cheryl Hoskins Sep 22 '17 at 18:20
  • *“The response had HTTP status code 405.”* for the preflight OPTIONS means the server doesn’t allow OPTIONS, at all. As far as, *“It just doesn't make sense to me that this sign-in flow wouldn't allow cross-origin requests.”*, the thing is, `https://accounts.google.com/o/oauth2/…` does very intentionally not allow cross-origin requests from *calls by frontend JS code (XHR or the Fetch API) running in browsers*. Instead they have a supported flow outlined in their docs, & that’s what you’re expected to use instead. It’s no mistake that their docs have no examples of using it with XHR or Fetch. – sideshowbarker Sep 22 '17 at 21:51
  • I'm sorry that I'm not figuring this out. Now that I changed the Content type from application/json to application/x-www-form-urlencoded, I am not getting the 405 any more (as noted in the Update). But I am still getting "No 'Access-Control-Allow-Origin' header is present on the requested resource." – Cheryl Hoskins Sep 22 '17 at 22:53
  • @sideshowbarker - Did you get a chance to look at the link I posted at the beginning to the google documentation? It is for client-side authorization. It is not the usual redirect-to-google flow (which avoids cross-origin requests), since this is for a TV and the user inputs are limited. I am just requesting a code from google that I will display to the user, and the user will then go to their computer and enter it. I can't find any working javascript examples. – Cheryl Hoskins Sep 22 '17 at 22:54
  • https://developers.google.com/identity/sign-in/devices has examples of making requests to that endpoint from outside a browser. (I think just examples of doing it with `curl`.) As far as I can see, the intention is to show you how you can make requests to it from *backend* code, on the server side. The reason you find no JS examples is that they intentionally don’t support a flow from frontend JavaScript running in a browser. That’s also the reason there’s no Access-Control-Allow-Origin response header; the lack of it means, “We don’t allow requests from frontend JS code from any origin.” – sideshowbarker Sep 22 '17 at 23:01
  • Well, the evidence certainly supports what you are saying. But what about the bottom of that document, where it talks about if you need to authenticate with a backend server (and provides a link to https://developers.google.com/identity/sign-in/web/backend-auth)? The linked doc talks about your front end sending the ID token to your backend, as if you had authenticated from the front end. That is my last hope before I give up and use my server. Thank you for your help. – Cheryl Hoskins Sep 22 '17 at 23:32
  • Sorry yeah that part that links to https://developers.google.com/identity/sign-in/web/backend-auth is beyond the limits of my own insight and experience with it, and I don’t see how that would work in practice, but regardless I do think that unfortunately it’s not going to work in a way that would address your need, and you almost certainly need to use your server (backend) – sideshowbarker Sep 22 '17 at 23:43

3 Answers3

0

The problem you have isn't CORS. You're getting an error response. The error response doesn't have Access-Control-Allow-Origin headers.

Use your browser's developer tools to inspect the HTTP response. With any luck, it will contain a real error message.

Brad
  • 159,648
  • 54
  • 349
  • 530
  • Dev Tools > Network > Response just says 'This request has no response data available'. Is that what you are referring to? – Cheryl Hoskins Sep 22 '17 at 18:30
  • @CherylHoskins Yep. In that case, you're going to have to debug this blind. :-/ I'm not familiar with this particular API... last time I used a Google auth API, it had some sort of debugging parameter I could add to get it to return an error message. Not sure if that's possible here. – Brad Sep 22 '17 at 18:33
  • Yeah. If I could just find a javascript example of this first step of google sign in with TVs, I think I'd be good to go. This just isn't the most common way to use google sign-in. – Cheryl Hoskins Sep 22 '17 at 18:37
  • @CherylHoskins If there's something else that uses that endpoint, you can always capture the data to figure out what it's doing differently. You can use a tool like Fiddler as a proxy server to hijack HTTPS sessions. (You'll have to install Fiddler's certificate on the device, if the device is doing HTTPS properly... but this is generally possible on most devices.) – Brad Sep 22 '17 at 18:39
0

I got this to work by using my backend server. So, to display the google signin code on the TV to the user: 1. the client (TV) makes an http request to my server, 2. my server queries google with my credentials, 3. google replies to my server, 4. my server responds to my client, where the code is displayed.

I still don't think this is how the docs describe it, but at least it is working now.

0

For future reference, I had the same issue:

The problem is that Chrome does not support localhost to go through the Access-Control-Allow-Origin. My solution was to install the Chrome extension mentioned here: No 'Access-Control-Allow-Origin' header is present on the requested resource error

That way you can do the request in the browser with superagent or fetch.

christianeide
  • 417
  • 2
  • 13