Blog Archives

APIs have become more and more popular due to increasing demand for development of mobile and single page apps, and so the need of sessionless server-side applications, being those that are token-based the most popular ones now days due to their relative easy implementation. Here you have a great example that uses JWT to secure a microservice-based application.

JWT (or jot) stands for JSON Web Token and as it states it is a web token structured in a JSON format. JWTs are composed of 3 parts: the header, the payload, and the signature. In short, the header contains the type of token and the algorithm for the cryptographic signing; the payload (or claim) contains the information wanted to securely send to the server, and the signature which contains the secret key known only by the server and that is used to decrypt the data contained in the payload. It is not the primary objective of this post to explain in detail what JWT is, so if you want to know more about it you can do it here.

JWTs are used in the next way:

The API server generates the JWT.

The JWT is sent to the client.

The client saves the JWT (i.e. in LocalStorage).

The client sends the JWT back –we’ll send it on a request’s header– to the server.

The server uses the JWT’s payload data for X or Y purpose. In our case to identify the user that is performing the request.

Besides JWT, we need an authentication strategy to actually identify users. We’ll use Sorcery for this purpose; I recommend you to go ahead and read the documentation if you haven’t done so. You can implement any other authentication library –or build your own– but for this particular case I personally like Sorcery because it offers all basic authentication features and it is not as overkilling as other libraries.

This is how the general authentication flow looks like:

Fig. 1 JWT Flow

Conveniently there is a jwt library that we can use to generate user’s token, so go ahead, read its documentation and install it in your project.

Next, we’ll create a service to provide the JWT, another one to validate it, and a last one to authenticate the user.

app/services/jwt/token_provider.rb

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

moduleJwt::TokenProvider

extendself

defcall(payload)

issue_token(payload)

end

private

defissue_token(payload)

JWT.encode(payload,Rails.application.secrets.secret_key_base)

end

end

app/services/jwt/token_decriptor.rb

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

moduleJwt::TokenDecryptor

extendself

defcall(token)

decrypt(token)

end

private

defdecrypt(token)

begin

JWT.decode(token,Rails.application.secrets.secret_key_base)

rescue

raiseInvalidTokenError

end

end

end

classInvalidTokenError<StandardError;end;

app/services/jwt/user_authenticator.rb

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

moduleJwt::UserAuthenticator

extendself

defcall(request_headers)

@request_headers=request_headers

begin

payload,header=Jwt::TokenDecryptor.(token)

returnUser.find(payload['user_id'])

rescue=>e

# log error here

returnnil

end

end

deftoken

@request_headers['Authorization'].split(' ').last

end

end

NOTE: In this case we are assuming that JWT is in ‘Authorization’ header with format ‘Bearer xxxx.yyyy.zzzz’, that’s why we are splitting @request_headers['Authorization'].

Implementing our services

We need to generate the JWT after user has successfully logged in:

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

classSessionController<ApplicationController

defcreate

user=User.authenticate(params[:email],params[:password])# This method comes from Sorcery

ifuser

token=Jwt::TokenProvider.(user_id:user.id)

renderjson:{user:user,token:token}# As an extra security metric, you might want to make sure you don’t send user’s encrypted password in `user: user` ;)

else

renderjson:{error:'Error description'},status:422

end

end

end

Or signed up:

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

13

classUsersController<ApplicationController

defcreate

user=User.new(user_params)

ifuser.save

token=Jwt::TokenProvider.(user_id:user.id)

renderjson:{user:user,token:token}

else

renderjson:{error:'Error description'},status:422

end

end

end

The token returned in the response should be properly saved in the client so it is sent back to the server in subsequent requests’ headers.

Then we need to authenticate user on future requests. Adding an authentication method on ApplicationController will let us use it on ApplicationController’s children controllers to protect our private endpoints:

Ruby

1

2

3

4

5

6

7

8

9

10

11

12

13

classApplicationController<ActionController::Base

defauthenticate

renderjson:{errors:'Unauthorized'},status:401unlesscurrent_user

end

defcurrent_user

@current_user||=Jwt::UserAuthenticator.(request.headers)

end

end

classAnotherController<ApplicationController

before_filter:authenticate

end

And that’s it, our API is now secured using a sessionless approach. From this point on you can add more complexity using jwt and Sorcery‘s methods to, for instance, make token expire after 1 hour or reset user’s password.

Let me know in the comments section below what you think about this strategy.

Recently at Tangosource I was assigned to work on an internal project named Dev Jobs (see dev jobs on iOS and dev jobs on Android), where I had the chance to work next to great teammates and implement a microservice architecture with Ruby on Rails, nodeJS, JWT, Ionic, Docker, and several testing tools, including RSpec, Mocha, Frisby, and Protractor. In this first post, I’ll explain the basics of the microservice architecture.

What is a Microservice Architecture ?

Martin Fowler gives a great definition.

[1]“The microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.”

The Problem

Let’s have some context. We are building a server side application that must support different client side platforms such as:

Desktop browsers

Mobile browsers

Native mobile applications

Also, we need to consume an external API service. In our case, Linkedin through Oauth2 for authentication. And the ability for users to chat between each other.

On an architectural matter we still had to decide between monolithic or microservice. So let’s dig a little more on this two.

Monolithic vs MicroServices

Monolithic

If we take this approach, we need to keep the following in mind:

Build one application to rule them all.

Use one language ( Ruby, PHP, JavaScript, etc. ) we could not take any extra advantages from other programming languages.

The architecture needs to be flexible enough to support API through AJAX and render HTML.

The development team needs to feel comfortable with the language we picked.

I have seen great monolithic architectures that can support all of this. One of my favorites is RoR engines based or nodeJS services based applications.

MicroServices

In the other hand, if we go for MicroServices we must take in mind the following:

Delegate responsibilities in small applications.

We can use different languages per service. Which is the best choice per responsibility?

How are we going to communicate each service ? Normally with tcp/ssl.

How are we going to persist Data through services?

Security: Protect the services.

Testing: Test all microservices.

On a personal note, as a developer working on a microservice platform, I can focus only on the technical details wrapping a specific service. This does not mean I should not understand the whole set of services as a unit.

“Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure.”

— Melvyn Conway, 1967

Having this in mind, we had to start by making technical decisions, such as how to protect our API, how to manage RTCP, by nature HTTP is stateless which means is sessionless so for our case we had to maintain a session through tokens ( JWT ), at first we though maybe nodeJS for RTCP since nodeJS is strong for DIRT ( Data Intensive Real Time ) apps. But we had not only had to take care of the tech devs but also for dev resources, currently at TangoSource we have strong Ruby on Rails devs so we had to work all together and take advantage of the expertise of each team member, our best bet was to use RoR for business logic, and take advantage of nodeJS. So the combination of RoR and nodeJS makes the solution solid and strong.

Solution

For this particular project, we decided to go for the MicroService and have some fun! The first thing that we needed to figure out was defining the responsibilities per service. So we end up with 4 microservices.

Responsible for (a) providing identifiers for users looking to interact with a system, (b) asserting to such a system that such an identifier presented by a user is known to the provider (c) possibly providing other information about the user that is known to the provider.

This may be achieved via an authentication module, which verifies a security token, and that can be accepted as an alternative to repeatedly and explicitly authenticating a user within a security area.

Ionic admin panel, this panel allow us to configure GCM and APNS exposing a protected API.

IDP : This service is in charge of giving identity to a component/user. This service will expire a valid token with a component/user’s basic information on the JWT’s payload. Similar to memoization, this service will keep track of sessions using Redis on a basic TLS connection. Thanks to the RFC 7519 standard, this service can scale in other microservice based architectures and be reused.

SP : This is an API/Https service protected with JWT. This micro service is in charge of persisting all user’s interaction/information using MySQL with a standard TLS connection. It also manages the business logic.

Chat : This microservice will provide real-time communication between users. This RTCP (real time control protocol) is being protected with JWT on the handshake process, and persists the communication activity on MongoDB, a NoSQL database.

Conclusion

Taking these kind of decisions is not simple. It requires a lot of experience in order to compare libraries/languages, you must at least know how they work, and it’s even better if you have used them. Remember that you will not build this by yourself, you are part of a team. It’s smart to sit with your team and discuss each individual’s strengths and weaknesses in order to make the best tech decisions.

DO NOT mix responsibilities of the micro services, instead identify your services. Add all the needed documentation to help the team such as /*Comments */, READMEs, and Wikis.A microservice architecture is not always the best approach, and could be painful if you are not careful.