1

I'm absolutely certain that I am missing something fundamental here but I am lost as to what to try next.

I have built an express application using passport-twitchtv based on the sample application here: https://github.com/johnkernke/passport-twitchtv/tree/master/examples/login

When I use my browser and browse to http://localhost:3000/auth/twitchtv I get successfully redirected to Twitch to perform a login, here's the snippet from the express code:

app.get('/auth/twitchtv', 
  passport.authenticate('twitchtv', {scope: [ 'user_read' ]}), 
  function(req, res){

  });

app.get('/auth/twitchtv/callback', 
  passport.authenticate('twitchtv', { failureRedirect: "/" }), 
  function(req, res) {
    // Successful authentication, redirect home.
    //DEBUG 
    console.log('Hit the auth callback');
    res.redirect("/");
});

My actual problem is that I am trying to perform the login from an angularjs application served from the express server, I have a button which I want to press to allow the login however it does not work, here's some code:

Login view:

<!-- login.html -->
    <div class="jumbotron text-center">
        <h1>Login</h1>

        <p>{{ message }}</p>
    </div>
    <div class="container-fluid">
        <div ng-controller="twitchLoginController" class="row">
        <button ng-click="twitchLogin()" class="btn btn-default mybutton" >
            <img src="images/twitchconnect.png" img-responsive />
        </button>
        </div>
    </div>

Controller Code:

myApp.controller('twitchLoginController', function($scope, $http, $location) {

        $scope.twitchLogin = function() {
            console.log("in the login call");
            var response = $http.get('/auth/twitchtv');
            //$location.url('/auth/twitchtv');
            console.log(response);
            response.success(function(data, status, headers, config) {
                $scope.message = 'ok';
            });

            response.error(function(data, status, headers, config) {
                $scope.message = status;
            })
        }
    });

As you can see here I am trying to do a GET to the url which is what I think I need to do but whenever I click the button I get an error in the browser:

XMLHttpRequest cannot load https (removed://) api.twitch.tv/kraken/oauth2/authorize?response_type=code&redirect_u…tchtv%2Fcallback&scope=user_read&client_id=ire1vyl32phgrfofwab5uebs3er8htr. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http (removed://) localhost:3000' is therefore not allowed access.

As you can see from my code I just tried setting the url to be /auth/twitch using $location but when I do that nothing happens at all, no error, no login either.

So I am stuck and I don't know whether it's because my code is wrong or whether I have a fundamental misunderstanding of what it is I am trying to achieve, I at least know that my server code is working and so I have been concentrating on the angular piece.

I have tried the following in my angular code:

$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];

To enable CORS but that doesn't seem to have helped.

Any ideas?

EDIT

I added this to my Login view:

<!-- login.html -->
    <div class="jumbotron text-center">
        <h1>Login</h1>

        <p>{{ message }}</p>
    </div>
    <div class="container-fluid">
        <div ng-controller="twitchLoginController" class="row">
        <button ng-click="twitchLogin()" class="btn btn-default mybutton" >
            <img src="images/twitchconnect.png" img-responsive />
        </button>

-------><a target="_self" href="/auth/twitchtv">Login</a>
        </div>
    </div>

And when I click on the link the login is performed, only works with _self enabled. So this seems like the only solution, from my point of view this is OK but can someone confirm that this is how you are supposed to get this to work so I know I'm not doing something stupid or worse insecure :-)

Thanks Adrian

1 Answers1

0

Short answer: Redirecting your client to /auth/twitchtv is the right solution. You should be able to achieve this with your button by simply adding:

$scope.twitchLogin = function() {
    $window.location.href = '/auth/twitchtv';
    // inject $window    
}

As this answer describes $location.url('/auth/twitchtv'); does not work here as it is used to stay inside an SPA.

The problem with your original GET request was the following:

Your express route /auth/twitchtv responded with a redirect response to Twitch. When angular's $http receives such a response it automatically starts a new GET request to the url provided in the response (so far so good).

However Twitch does not allow accessing this resource like this, it wants you to redirect the web browser to this url not to start an XMLHttpRequest behind the scenes (which makes sense if you keep in mind that Twitch has to respond with its authentication page).

This is also the reason why CORS was not working even after enabling it from your side - Twitch was the one prohibiting this kind of access.

Hope this helps!

Community
  • 1
  • 1
Jonas Bürkel
  • 708
  • 5
  • 16
  • Thanks very much for the feedback and helping me understand a bit more widely what is happening, it's really appreciated and of course now my button works :-) – Adrian Schofield Aug 05 '16 at 05:16