/ programming

Google Cloud Endpoints, AngularJS and Json Web Tokens

In my private project I decided to use Google Endpoints (with Google App Engine) on backend side and AngularJS on frontend. For authorization I've chosen JWT (Json Web Tokens). At the beginning I wanted to use Google API Client library for JavaScript but I encountered two problems. At first, I can't set own authorization header. I can set token but it is insert in Authorization header which create a little issue. I found angular project for GAPI, angular-google-gapi, using this here is an example of adding token:

var CLIENT = 'SECRET_KEY';
var BASE = 'https://myapp.appspot.com/_ah/api';
GAuth.setClient(CLIENT);
GAuth.setToken({
  access_token: 'JWT TOKEN'
});
GApi.load('myapp', 'v1', BASE);

It adds token, even I can retrieve it on backend side and everything works correctly. But.. Google App Engine tries every time to use this token as Oauth2 token, logs:

D 12:38:44.375 Checking for id_token.
D 12:38:44.376 id_token verification failed: Unexpected encryption algorithm: u'HS256'
D 12:38:44.376 Checking for oauth token.
D 12:38:44.384 Oauth framework user didn't match oauth token user.

Second problem, why do I need an additional javascript library to making request to API? I didn't find a good reason to stay with GAPI because I want use my API. I decided to write my own directive.

'use strict';

var servicesModule = require('./_index.js');

/**
 * @ngInject
 */
function MeetApiService($q, $http, AppSettings) {

  var service = {};

  var createEndpointUrl = function(endpoint, version) {
      version = version || AppSettings.defaultApiVersion;
      endpoint = endpoint.replace('.', '/');
      return [
        AppSettings.apiUrl,
        AppSettings.projectName,
        version,
        endpoint
      ].join('/');
  };

  service.get = function(endpoint, args, version) {
    var deferred = $q.defer();

    $http({url: createEndpointUrl(endpoint, version), method: "GET", params: args}).success(function(data) {
        deferred.resolve(data);
    }).error(function(err, status) {
        deferred.reject(err, status);
    });

    return deferred.promise;
  };

  service.post = function(endpoint, args, version) {
    var deferred = $q.defer();

    $http.post(createEndpointUrl(endpoint, version), args).success(function(data) {
        deferred.resolve(data);
    }).error(function(err, status) {
        deferred.reject(err, status);
    });

    return deferred.promise;
  };

  return service;
}

servicesModule.service('MeetApiService', MeetApiService);

AppSettings contains projects settings like API url, default version for endpoints, project name, etc. Using this service I can easily make a request to Google Endpoints.

MeetApiService.post('users.login', {'email': vm.email, 'password': vm.password})
.then(function(response) {
    // DONE!
}, function() {
  // ERROR!
});

MeetApiService.get('users.get', {})
.then(function(response) {
  // DONE!
});

What about authorization token? I'm using custom authorization field, something like:

$http.defaults.headers.common['X-MYPROJECT-Auth'] = 'TOKEN';

It adds X-MYPROJECT-Auth header with TOKEN value to every request. Works perfectly! It has two advantages for me, it doesn't create mess in logs and it gives me the possibility to use Authorization field for other Google APIs in the future.

https://stackoverflow.com/questions/31816453/google-cloud-endpoints-and-jwt