Authenticate Angular js module for Apigility Authenticate Angular js module for Apigility angularjs angularjs

Authenticate Angular js module for Apigility


I will try to give a complete method of how I have made ng-token-auth work with ZF2. Primarily, ng-token-auth works fine with ruby module. So to make it work with ZF2 :

Resolve the CORS problem with these lines of code :

//HttpProvider$httpProvider.defaults.useXDomain = true;$httpProvider.defaults.headers.common['Access-Control-Request-Method'] = "POST, GET, PUT, DELETE";$httpProvider.defaults.headers.common['Origin'] = "http://xxxxxxxxxxxxxxx";$httpProvider.defaults.headers.common['Accept'] = "application/json";$httpProvider.defaults.headers.common['Content-Type'] = "application/json; text/html";delete $httpProvider.defaults.headers.common['X-Requested-With'];

Resolve the problem of CORS on ZF2 using ZFCORS as pointed in @josilber and @sven-lauterbach answer

Format response sent by ZF2 to make it work with ng-token-auth using these lines of codes

$http.defaults.transformResponse = function(value, headerGetters){    var response_header = headerGetters(),    response_data   = JsonHelper.IsJsonString(value) ? JSON.parse(value) : value;    if(response_data){        if(response_data.access_token)            response_header['access_token']  = response_data.access_token;        if(response_data.expires_in){            var now = new Date().getTime();            response_header['expires_in']    = now + ( parseInt(response_data.expires_in, 10) * 1000 );        }         if(response_data.token_type)            response_header['token_type']    = response_data.token_type;        if(response_data.refresh_token)            response_header['refresh_token'] = response_data.refresh_token;        if(response_data.scope)            response_header['scope']         = response_data.scope;        return response_data;    }};

May be this is not the best way to transform response in AngularJS but it resolves the problem of formatting OAuth2 response which works with ng-token-auth

Finally, to send request to the server using auth token and refresh the token automatically, it was necessary to change some behavior of ng-token-auth. I have used decorate pattern on AngularJS to solve this issue with these snippets of code :

In app.js

//Change behavior of oauth2 module $provide.decorator("$auth", function($delegate, ApiAuthService){    return ApiAuthService($delegate);}); 

Where ApiAuthService is a factory defined by this snippet of code :

AuthProviderService.factory('ApiAuthService', ['MeService', function( MeService ){    return function($delegate){        return {            initialize: function(){ return $delegate.initialize(); },            apiUrl: function(configName){ },            retrieveData: function(key){ return $delegate.retrieveData(key); },            getConfig: function(name){ return $delegate.getConfig(name); },            getExpiry: function(){  return $delegate.getExpiry(); },            setAuthHeaders: function(h){ return $delegate.setAuthHeaders(h); },            /*persistData: function(key, val, configName){ return $delegate.persistData(key, val, configName); },            retrieveData: function(key){ return $delegate.retrieveData(key); },*/            rejectDfd: function(reason){ $delegate.rejectDfd(reason); },            invalidateTokens: function(){ return $delegate.invalidateTokens(); },            submitLogin: function(params, opts){ return $delegate.submitLogin(params, opts); },            validateUser: function(opts){                  result = $delegate.validateUser(opts);                return result;            },            deleteData: function(key){                  return $delegate.deleteData(key);            }        };    };}]).config(['$httpProvider', function($httpProvider) {    $httpProvider.interceptors.push([         '$injector', function($injector) {           return {             request: function(req) {               $injector.invoke([                 '$http', '$auth', function($http, $auth) {                   var key,                        _ref,                        _results = [];                   if (req.url.match($auth.apiUrl())) {                     _ref = $auth.retrieveData('auth_headers');                     //Inject value into body of request                      for (key in _ref) {                         //Set Authorization request header.                         if(key.match('access_token')){                             if(req.headers){                                 req.headers['Authorization'] = 'Bearer ' + _ref[key];                              }else{                                 req.headers = {'Authorization': 'Bearer ' + _ref[key]};                             }                         }                         if(req.headers[key]){                             delete req.headers[key];                         }                     }                     return _results;                   }                 }               ]);               return req;             }           };         }       ]);}]);

Lastly my configuration of ng-token-auth was :

//OAuth2 Module configs$authProvider.configure([ {    "default": {        apiUrl:                  API_URL,        tokenValidationPath:     '/me',        signOutUrl:              '/oauth',        emailRegistrationPath:   '/oauth',        accountUpdatePath:       '/oauth',        accountDeletePath:       '/oauth',        confirmationSuccessUrl:  window.location.href,        passwordResetPath:       '/oauth',        passwordUpdatePath:      '/oauth',        passwordResetSuccessUrl: window.location.href,        emailSignInPath:         '/oauth',        forceHardRedirect: true,        storage:                 'localStorage',        proxyIf:                 function() { return false; },        proxyUrl:                'proxy',        authProviderPaths: {            github:   '/auth/github',            facebook: '/auth/facebook',            google:   '/auth/google'        },        tokenFormat: {            "access_token" : "{{ token }}",            "token_type"   : "Bearer",            "refresh_token": "{{ clientId }}",            "expires_in"   : "{{ expiry }}",            "scope"        : "{{ uid }}"        },        parseExpiry: function(headers) {            var expires_in = parseInt(headers['expires_in'], 10) || null;                return expires_in;            },            handleLoginResponse: function(response) {                //Patch for persistant data as library retreive auth data from header.                return response;            },            handleAccountResponse: function(response) {                return response;            },            handleTokenValidationResponse: function(response) {                return response;            }        }} ]);

@JerinKAlexander I hope these steps will help you to find your way to solve your question in a better way than what I have done.


You can actually get satellizer to work with Apigility using a rather simple but neat workaround. Take a look here :

http://adam.lundrigan.ca/2014/11/06/using-oauth2-jwt-with-apigility/

and here:

https://github.com/adamlundrigan/LdcOAuth2CryptoToken/blob/master/src/Factory/CryptoTokenServerFactory.php

Apigility defines service factories for all it's internal services. The basic idea here is to simply define a service manager delegator factory which injects the necessary configuration.

<?php  namespace LdcOAuth2CryptoToken\Factory;use Zend\ServiceManager\DelegatorFactoryInterface;  use Zend\ServiceManager\ServiceLocatorInterface;class CryptoTokenServerFactory implements DelegatorFactoryInterface  {    public function createDelegatorWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName, $callback)    {        $server = call_user_func($callback);        // do your thing to $server here        return $server;    }}

All thanks to Adam Lundrigan :)


You want to use Apigility as backend. You have a HTML App which runs on a different domain and this HTML App should call the Apigility backend with OAuth Authentication? If this is what you're trying to accomplish you have to setup Apigility to support CORS calls, take a look at https://apigility.org/documentation/recipes/allowing-request-from-other-domains

They use the "ZfrCors" module:

They use the following sample:

return array('zfr_cors' => array(     /**      * Set the list of allowed origins domain with protocol.      */     'allowed_origins' => array('http://www.sexywidgets.com'),     /**      * Set the list of HTTP verbs.      */     'allowed_methods' => array('GET', 'OPTIONS'),     /**      * Set the list of headers. This is returned in the preflight request to indicate      * which HTTP headers can be used when making the actual request      */     'allowed_headers' => array('Authorization', 'Content-Type'),     /**      * Set the max age of the preflight request in seconds. A non-zero max age means      * that the preflight will be cached during this amount of time      */     // 'max_age' => 120,     /**      * Set the list of exposed headers. This is a whitelist that authorize the browser      * to access to some headers using the getResponseHeader() JavaScript method. Please      * note that this feature is buggy and some browsers do not implement it correctly      */     // 'exposed_headers' => array(),     /**      * Standard CORS requests do not send or set any cookies by default. For this to work,      * the client must set the XMLHttpRequest's "withCredentials" property to "true". For      * this to work, you must set this option to true so that the server can serve      * the proper response header.      */     // 'allowed_credentials' => false,),);

All you have to to is to set the 'allowed_origins' option to the domain of your HTML App.

For the OAuth part you can get more information here: https://apigility.org/documentation/auth/authentication-oauth2

You should take a closer look at the "Browser-based applications" section, because you use an HTML app to access your apigility backend. With the information provided in this post you can use https://github.com/sahat/satellizer

If you need more informations let me know.