rethinkdb / horizon

Horizon is a realtime, open-source backend for JavaScript apps.
MIT License
6.78k stars 349 forks source link

horizon.authEndpoint('github').subscribe returns "Unexpected token <" #487

Closed jakobrosenberg closed 8 years ago

jakobrosenberg commented 8 years ago
horizon.authEndpoint('github').subscribe(endpoint => {})
e {isUnsubscribed: false, syncErrorValue: null, syncErrorThrown: false, syncErrorThrowable: false, isStopped: false…}
subscribeToResult.js:41 Uncaught SyntaxError: Unexpected token <

Facebook returns the same error.

Client served from server v1.0.2

deontologician commented 8 years ago

This is probably an issue with error reporting. @jakobrosenberg Which endpoints do you have configured in your config.toml?

jakobrosenberg commented 8 years ago

Just Facebook and Github. Added Github to see if the error was specific to Facebook.

Error persists in 1.0.3.

Mike-neti commented 8 years ago

same here

poznyakovskiy commented 8 years ago

Same for google. The function passed to .subscribe is also never entered.

deontologician commented 8 years ago

I would guess it's getting an error status code which is failing the observable, but the error handling code probably tries to deserialize from json which won't work if you don't receive json back

poznyakovskiy commented 8 years ago

@deontologician Yes, it's response.json() within fetchJSON(url) that triggers this error.

jordandenison commented 8 years ago

try running this inside the horizon.onReady callback

poznyakovskiy commented 8 years ago

@jordandenison If I understand correctly, horizon.onReady would only be triggered after a connection has been established. However, attempting to establish a connection with Horizon.connect() returns the error message "Attempting to authenticate with a token, but no token is present".

jordandenison commented 8 years ago

yeah that was my understanding as well, but it seemed to fix the issue - now I am on the same boat as you : ) "Attempting to authenticate with a token, but no token is present" - haven't had a chance to look into this much yet though (can't specify horizon server host in configure for now so leaving auth for now as I'm serving statics from another server)

deontologician commented 8 years ago

authEndpoint uses xhr/fetch under the hood, so it shouldn't have anything to do with the main horizon connection (which onReady is linked to).

jordandenison commented 8 years ago

yeah, so the error in my case is likely incorrect horizon host since the assets aren't served from it - strange that the error message changes when run inside onReady though (likely the Attempting to authenticate raises the first uncaught)

jordandenison commented 8 years ago

ah, "Attempting to authenticate with a token, but no token is present" is totally unrelated - this message gets thrown when there is no token (obviously) so should only get called after being redirected back to the app from oauth, but you must instantiate Horizon before your app can call hasAuthToken - catch 22

poznyakovskiy commented 8 years ago

This did not really fix the issue. From fetchJSON, I get the error text "Response was not json" and the content of my client-side index.html.

deontologician commented 8 years ago

Ok, so now we just have to find out why your index.html is being served from the auth_methods endpoint. What's your configuration like?

poznyakovskiy commented 8 years ago

config.toml

# This is a TOML file

###############################################################################
# IP options
# 'bind' controls which local interfaces will be listened on
# 'port' controls which port will be listened on
#------------------------------------------------------------------------------
# bind = [ "localhost" ]
# port = 8181

###############################################################################
# HTTPS Options
# 'secure' will disable HTTPS and use HTTP instead when set to 'false'
# 'key_file' and 'cert_file' are required for serving HTTPS
#------------------------------------------------------------------------------
# secure = false
# key_file = "horizon-key.pem"
# cert_file = "horizon-cert.pem"

###############################################################################
# App Options
# 'project_name' sets the name of the RethinkDB database used to store the
#                application state
# 'serve_static' will serve files from the given directory over HTTP/HTTPS
#------------------------------------------------------------------------------
project_name = "backend"
# serve_static = "dist"

###############################################################################
# Data Options
# WARNING: these should probably not be enabled on a publically accessible
# service.  Tables and indexes are not lightweight objects, and allowing them
# to be created like this could open the service up to denial-of-service
# attacks.
# 'auto_create_collection' creates a collection when one is needed but does not exist
# 'auto_create_index' creates an index when one is needed but does not exist
#------------------------------------------------------------------------------
# auto_create_collection = true
# auto_create_index = true

###############################################################################
# RethinkDB Options
# These options are mutually exclusive
# 'connect' will connect to an existing RethinkDB instance
# 'start_rethinkdb' will run an internal RethinkDB instance
#------------------------------------------------------------------------------
# connect = "localhost:28015"
start_rethinkdb = true

###############################################################################
# Debug Options
# 'debug' enables debug log statements
#------------------------------------------------------------------------------
# debug = true

###############################################################################
# Authentication Options
# Each auth subsection will add an endpoint for authenticating through the
# specified provider.
# 'token_secret' is the key used to sign jwts
# 'allow_anonymous' issues new accounts to users without an auth provider
# 'allow_unauthenticated' allows connections that are not tied to a user id
# 'auth_redirect' specifies where users will be redirected to after login
#------------------------------------------------------------------------------
token_secret = "very_secret"
# allow_anonymous = true
# allow_unauthenticated = true
# auth_redirect = "https://localhost:3000/"
#
# [auth.facebook]
# id = "000000000000000"
# secret = "00000000000000000000000000000000"
#
[auth.google]
id = "my_key.apps.googleusercontent.com"
secret = "my_key"
#
# [auth.twitter]
# id = "0000000000000000000000000"
# secret = "00000000000000000000000000000000000000000000000000"
#
[auth.github]
id = "my_key"
secret = "my_key"
#
# [auth.twitch]
# id = "0000000000000000000000000000000"
# secret = "0000000000000000000000000000000"

At the frontend:

this._backend = Horizon({
    host: 'localhost:8181',
    secure: true,
    authType: 'token'
});

if (!this._backend.hasAuthToken()) {
    this._backend.authEndpoint('github').subscribe(endpoint => {
        window.location.pathname = endpoint;
    },
    error => {
        debugger;
    })
} else {
    this.registerActions();
}

The frontend is an angular2 project built with webpack, runs on localhost:3000.

poznyakovskiy commented 8 years ago

We found out what the problem was. To have the issue fixed, you also need to include the "Access-Control-Allow-Origin" header on the server side:

server/src/server.js, line 143: res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });

Since this is a potential security issue, I was hesitant to include it into my pull request and would gladly wait for a more flexible solution, unless you would like to have this change included, too.