2

By running the code below, the authentication window pops-up and the user confirms the login. This part works. Once the authorize button is clicked, this redirects to the previous tab in the same window (in the pop-up not in the parent window). How I can close this pop-up window after authorization is confirmed by the user and how can I get back the authorization code from the url? For instance in the code below, the first "console.log(event.url);" is not executed.

    var redirectUri = "http://localhost:8100/callback";

    var ref = window.open('https://www.example.com/oauth/authorize?client_id=' + clientID + '&redirect_uri=' + redirectUri + '&scope=write&response_type=code&approval_prompt=force', '_blank', 'location=no,clearsessioncache=yes,clearcache=yes');

    ref.addEventListener('loadstart', function (event) { // THIS IS NOT TRIGGERED FOR SOME REASON

        console.log(event.url); 

        if ((event.url).indexOf(redirectUri) === 0) {
            requestToken = (event.url).split("code=")[1];

            $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
            $http({
                    method: "post",
                    url: "https://www.example.com/oauth/token",
                    data: "client_id=" + clientId + "&client_secret=" + clientSecret + "&code=" + requestToken
                })
                .success(function (data) {
                    $scope.data = data;
                    console.log(event.url);

                })
                .error(function (data, status) {
                    deferred.reject("Problem authenticating");
                });
        }
    });

Below are the tabs used in the application. How can I return to my tab.example after callback?

// setup an abstract state for the tabs directive
    .state('tab', {
    url: '/tab',
    abstract: true,
    templateUrl: 'templates/tabs.html'
})

.state('tab.example', {
        url: '/example',
        views: {
            'tab-example': {
                templateUrl: 'templates/tab-example.html',
                controller: 'ExampleAPICtrl'
            }
        }
    })
    .state('callback', {


    });

// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/');
Andrei
  • 7,509
  • 7
  • 32
  • 63
  • does not make sense that you `console.log` wasn't executed if the `http post` below it was. Sometimes a log is not shown in the console window b/c of context. But that doesn't mean it wasn't executed. try putting a break point at the `console.log` – Dave Alperovich Jul 23 '16 at 17:10
  • basically the window handler doesn't trigger, nothing is executed in that handler. I tried with multiple handlers, nothing is triggered/ – Andrei Jul 23 '16 at 17:11
  • there seems to be a lot missing from your code. I have trouble understanding what was done and why. For example, is why are you listening for `loadstart` event? Where will it be emitted from? Do you expect your app to pick up an event sent from a different window? – Dave Alperovich Jul 23 '16 at 17:29
  • In the popup, I have to authenticate an app with authenticates with one of the social networks. Once it retrieves the authentication from this social network, this app will give an authentication token which can be used to access its API. Now, when it return that authentication token, it returns it in the url of this popup. The trouble that I have is, from this popup window, how do I pass back this url back to my Angularjs app, so I can use the token from the url to access the API. – Andrei Jul 23 '16 at 17:40
  • Any links and examples are welcomed. I'm sure I'm not the first one doing this :-) – Andrei Jul 23 '16 at 17:47
  • your need is vague. The signature of your example matches only Twitter. Are you looking to integrate with a specific 3rd party which you don't want to name, or somehow find one solution for any and all oauth providers? I'm beginning to wonder if you even know what you want. – Dave Alperovich Jul 23 '16 at 21:18
  • I used some parts of your solution and I fixed it, however, after I make the second http request (the one inside the handler), I get the following error XMLHttpRequest cannot load https://www.example.com/oauth/token Response for preflight is invalid (redirect) http://stackoverflow.com/questions/38546358/xmlhttprequest-cannot-load-angularjs-post-request – Andrei Jul 23 '16 at 21:22
  • Please have a look at http://stackoverflow.com/questions/38546358/xmlhttprequest-cannot-load-angularjs-post-request – Andrei Jul 23 '16 at 21:23
  • Interesting redirect problem... will see what I can find... – Dave Alperovich Jul 24 '16 at 01:10
  • I tried to do the request from a local webserver (nodejs) and it works. When I point the client to this webserver, I still have the same problem (error). – Andrei Jul 24 '16 at 11:14
  • a 302 is a redirection. It's not often returned to client, rather the redirect result is. It's even less sensible when querying end points. Can you elaborate a little more... I gather you're query the token end point and are getting a 302 code returned. Do you get the token returned as well? – Dave Alperovich Jul 24 '16 at 20:13
  • not getting anything. I believe the request was cancelled by the browser (I could be wrong). However, I solved this by creating a backend webserver with NodeJs and use it as a proxy for all requests from my client. The issue that I have is this supposed to be a mobile app, and I don't think on the mobile I will have this backend webserver. Also, I read on other posts that once you deploy it, you don't have this problem on the mobile. But I need to find out how to get the client to know where is deployed. Any thoughts on this? – Andrei Jul 25 '16 at 07:07

2 Answers2

0

You need a service to wrap the 3rd party Provider so it can listen for the event Call back.

a great library implementation I've used:

mrzmyr Angular-Google-Plus

The heart of the librarie's approach is in the following code snippet:

      NgGooglePlus.prototype.login = function () {
          deferred = $q.defer();
          gapi.auth.authorize({
              client_id: options.clientId,
              scope: options.scopes,
              immediate: false,
              approval_prompt: "force",
              max_auth_age: 0
          }, this.handleAuthResult);
          return deferred.promise;
      };

Dave Alperovich
  • 32,320
  • 8
  • 79
  • 101
  • I'm not integrating google plus, what I'm looking at is a 3rd party app which it authenticates with whatever it wants (don't care about that part). – Andrei Jul 23 '16 at 18:09
  • Explanation is too vague. Is it your own 3rd party app? Whether it's yours or not, more explanation is needed. The specifics of the actual implementation. – Dave Alperovich Jul 23 '16 at 18:10
  • honestly, whether it's Google, FB, Twitter, or your own implementation, the approach is basically the same. You want to wrap the new window call in a service and capture a promise or callback. And the provider must have a call-back or promise to resolve. I'm not sure what else you want. – Dave Alperovich Jul 23 '16 at 18:15
  • Many thanks for suggestions. If you have any suggestions for how to overcome the 302 problem, please let me know. – Andrei Jul 24 '16 at 00:31
0

When you want to do login with 3rd party, i advice you to create a login service which will perform the login by sending the good information to the login system (other API, web application with url...). Like that, your service can emit event that can be used in your application to perform more action

$scope.$broadcast('loadstart', {
  someProp: 'send parameter to your event in the data object' 
});

$scope.$on('loadstart', function (event, data) {
  //your function the tretment of the reply
});

If you want to go forward with the event you can follow this link : https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

to return in your tab.example you can try the $state in the .success part of your http request. This service allow you to choose on which state you want to be :

$state.go('tab.example');
jeremy-denis
  • 6,368
  • 3
  • 18
  • 35