Search code examples
angularjsangular-ui-routergoogle-oauth

Parsing Oauth 2.0 return parameters in angular-ui-router


I'm attempting to authenticate a user using Google's Oauth 2.0 API. When my app HREF's to the Google authentication page, it successfully passes information back to my AngularJS app. However, I'm not sure how best to handle the returned URL-encoded data.

This is the format it is returned as:

#access_token=...
&token_type=Bearer
&expires_in=3600

My main problem is that this string begins with # instead of ? as is traditionally done with URL encoded parameters.

In my stateProvider config, I've implemented the callback state as such:

.state 'auth.googlecallback',
    url: '/googlecallback/#{accessToken}&token_type={tokenType}&expires_in={expiresIn}'
    templateUrl: 'views/auth/googlecallback.html'
    controller: 'GoogleCallbackCtrl as gVm'

The above URL is an example of what I have tried. When the url is simply /googlecallback/, the page loads successfully, even when navigated to using the Google Oauth link. But the moment I had the # symbol, the state breaks and I can't parse the state params for the data inside.

I've looked into using the angular-oauth library on GitHub, but it hasn't been updated in 2 years, and it doesn't appear to allow Oauth authentication for more than just Google (I want to use Facebook and Google).

What is the correct way to handle the the Oauth URL data in angular-ui-router?


Solution

  • To be frank, I don't think this will actually answer your question, but I was helping some friends with this earlier today. They were unable to handle the URI via the ui-router. Instead, they had to delegate parsing the parameters and making the appropriate request to their view controller. Using the Angular $location service and some remapping functions, we were able to get the parameters out of the # query syntax into a hash that he was able to push back to the server in his request. The code looked similarly to the following:

    var paramsArray = $location.hash().split('&')
    var payload = {};
    angular.forEach(paramsArray, function (param) {
      var arr = param.split('='),
          key = param[0],
          value = param[1];
      payload[key] = value;
    });
    

    This could absolutely be simplified but this was what he was trying to accomplish for his strategy.

    That all being said, I'm personally not a fan of trying to accomplish OAuth strategy on the client. You have private keys that usually need to get exchanged to complete the full handshake. If possible, it would be best if you did the following:

    1. Redirect the client to the appropriate OAuth path
    2. Have the redirect go to a server endpoint that can process the oauth request and complete the handshake.
    3. Have the server endpoint that the oauth request redirected to, redirect to your success landing page with any additional response objects required by your application.

    Doing this would protect your private keys and most web frameworks have modules/packages/gems/plugins/etc. for implementing oauth for all the mainstream providers. Hope this helps you in the right direction.