APIs, Authentication, Authorization, and Accounting

Microservices and APIs

Microservices enable agility when working in cross-functional teams, building independently deployable services. These services are exposed as publicly accessible APIs, and are fundamental to a suitably structured hybrid integration.

The API assembly in a hybrid reference architecture is typically composed of new and existing microservices likely to communicate using REST (Representational State Transfer protocol). Together they form a system of engagement that consumers outside the assembly can self-subscribe to with proper security credentials.

From a consumer perspective, authorization using API keys is simple, as they are passed as an opaque string in the authorization header. But that is "all-or-nothing" access. It is not possible to revoke these keys unless you change the API subscription as a whole. So, it is only theoretically safe for consumers/client applications to use a client secret for authorized use of services.

Client secrets protect a service where the identity of the client is trusted. But there is always an overhead to sharing and managing client identities using client secrets. If the secret is compromised, a new set has to be generated, and all authorized clients will have to be updated to use the new client secret. Because of the sensitive nature of a client secret, a preferred solution is to use authorization and authentication in the same context. This can be achieved by using OAuth specifications.

OAuth specifications

In OAuth, a client application is authorized by a user to access service resources on their behalf. But to do so, the user must first authenticate with their credentials, and then grant full or restricted privileges to the client application.

You shouldn’t confuse authentication with authorization here—a user is authenticated as the resource owner, and an application is authorized by the authenticated user to access service resources. The client application now has a trusted identity assured by the user, and it is able to identify itself without knowing the details of that identity (i.e. the user credentials).

Adding an OAuth2 consent step to your API instantly provides finer-grained control to access. Additionally, with OAuth, it is simple to define allowed scopes of access, token expirations, and use cookies and JWT identity tokens.

We illustrate here an easy way to build public APIs that are OAuth compliant. You can use your own OAuth provider with an Authentication URL or LDAP registry or integrate with a third-party OAuth provider such as Facebook, Google, or Twitter.

In either case, it is possible to handle authentication, authorization, and accounting independently for the exposed APIs. To implement this, we have chosen a LoopBack application, and used the Facebook OAuth 2.0 login as an example.

Context Diagram

Authentication, Authorization and Accounting (AAA)

[1] Handle Authentication – Implemented using third-party user login.

[2] Handle Authorization – Implemented by mapping third-party user identity to access permissions defined in LoopBack ACL policies.

[3] Handle Accounting – Implemented as method hooks for Loopback CRUD operations.

Build Checklist

Authentication

  • Create a LoopBack application.
  • Install required npm modules for loopback-component-passport.
  • Define the resource* models:

[* sample resource models]

  • userCredential: Base model - UserCredential
  • userIdentity: Base model - UserIdentity
  • user: Base model - User
  • item: Base model – PersistedModel
  • Update \server\model- config.json alongside user and role. Also add “./node_modules/loopback-component-passport/lib/models” to the sources and mixins list inside “model-config.json”. This tells LoopBack where to find the UserCredential and UserIdentity base models.
  • Next, add a boot script to \server\boot folder called setup-auth.js. (In server\boot, we can specify any script which should be run at server startup.) In our example, we use the boot script to primarily set up the third-party login with Facebook using loopback-component-passport - PassportConfigurator.
  • Add the following lines from setup-auth.js to your \server\server.js al well. Otherwise, you will see the Error: Model not found: UserCredential during API Connect API Connect start. We add this to server.js as this part of the code needs to run before boot.

var loopbackPassport = require('loopback-component-passport');
var PassportConfigurator = loopbackPassport.PassportConfigurator;
var passportConfigurator = new PassportConfigurator(app);

  • You’ll need to use two middleware modules in your setup-auth.js:
  • A middleware that parses cookies.
  • A middleware that uses cookies to track the currently logged in user via sessions.
  • Specify the parameters for Facebook login using PassportConfigurator in a json file called providers.json.
  • Make sure to register your application with Facebook and get the App ID and App Secret. You will need to use these in your providers.json.
  • Add your views that allow the user to login with Facebook.

 

Authorization

  • Define relationships* for your PersistedModels:

[* sample relationships]

  • An Item belongs to a User.
  • A User can have many Items.
  • Define ACLs* on resource models:

[*sample ACLs for Item]

  • Access to all operations on the ‘Item’ model is denied.

$everyone – DENY *

  • A user can do whatever they want to an ‘Item’ instance that they own.

$owner - ALLOW *

  • An authenticated user can create a new ‘Item’ instance.

$authenticated – ALLOW create

  • At the moment, any authenticated user can create an item for any other user, which is not correct. We will restrict this using a remote-hook;-

Item.beforeRemote('create', function(context, modelInstance, next)

 

[*sample ACLs for User]

  • By default, access to all operations on an ‘Item’ related to a User is denied. The built-in User model has a DENY ALL permission. So, even if Item has its ACLs defined, it will still not be accessible through the User model.
  • A user can do whatever they want to an ‘Item’ instance that they own.

$owner – ALLOW"   [“__create__items","__get__items","__delete__items",…]

  • An authenticated user can create a new ‘Item’ instance.

$authenticated – ALLOW __create__items

  • Set up a middleware in setup-auth.js to access an item for the currently authenticated user. This is done using the snippet:
  • app.middleware('auth', loopback.token({ model: app.models.accessToken}));
  • Now we should be able to access an item owned by a user using a REST call or a model query.
  • REST call:

/api/users/:id/items => /api/users/1/items

  • Model query:

User.find({where:{id:userId},include:{relation:"items"}},function(err, user)

        Accounting

  • Define remote hooks or operation hooks to add customized logging/accounting of user actions.

 

Next Steps

Once you have a basic idea of how the AAA principle works with LoopBack, you can start looking at creating and securing APIs with an OAuth provider API instead of in API Connect, or defining JWT policies for transporting identity payloads as JSON Web Tokens across microservices.

 

Prolifics recommends this technique, which has been successfully deployed and tested. We believe it provides an excellent, reliable, and secure solution to an apparently complex problem.

 

Sabari Mukherjee
Senior Consultant in Prolifics’ Smarter Process

Sabari Mukherjee is a Senior Consultant in Prolifics’ Smarter Process practice with over 12 years’ experience in the IT industry. She is an expert on cloud computing and specializes in building scalable integration patterns in the cloud, business process automation in application integration, and data analytics in systems design. She also possesses several certifications in SoA, WebSphere Integration development, and WebSphere MQ system administration.