How do you handle validation in composite microservice request?
Asked Answered
E

3

8

Consider an application with two entities:

  • User (contains basic user data, such as name)
  • Passport (contains authentication credentials, i.e. password)

And two internal microservices:

  • UserService (responsible for creating and managing users and their basic data)
  • AuthService (responsible for user authentication and password handling)

The User entity belongs to the UserService and Passport entity belongs to the AuthService.

Those two services should be separated, because they solve very different tasks: profile data and authentication.

Also, consider we have a registration form with three fields:

  • E-Mail
  • Name
  • Password

This form will trigger HTTP-request to the GatewayService, which intercepts all requests to the application and routes them to internal microservices (or composes/aggregates them).

Now, when gateway service receives the request with all the form data it needs to do the following:

  1. Call UserService to create new user (it will respond with generated userId).
  2. Call AuthService to create a passport for newly created user. It will need the userId received in step #1 and a password field from the original request.

This looks pretty straightforward, but what will happen if AuthService is unavailable on step #2? We will need to somehow separate those requests!

The classic approach is to use the eventual consistency and to create Passport entity via asynchronous call (we can place this request to the queue and process it in separate service). In order to do this we will send an asynchronous request to the AuthService passing userId and password to it, instead of step #2, so the step #1 will immediately return response to the client.

However, what if password field is not properly formatted (breaks validation rules)? The validation logic is only present in the AuthService, so we can't know if password is correct until the call is made to it. And now, the request is processed asynchronously, so we can't get back to user and tell him to correct the password.

SO, how do you properly handle validation in distributed composite requests to microservice application?

  1. The naive solution is to move validation logic to the GatewayService itself, but it's a terrible idea, because it will make it fat and will leak business logic from AuthService.

  2. The other idea is to provide an additional method for password validation and to call it prior to steps #1 and #2. It looks like a viable solution, but it will force us to have two methods for each business method in our microservices, one for prior validation and one for actual operation. Also, there is a time space between validation and operation, so the earlier correct value could become incorrect when operation is actually performed.

  3. We could split the form in two to avoid composite requests and ask user for password after asking for personal data and creating an account for him. However, this could lead to security problems, where user account could be intercepted by some other party who could guess the next userId. We could, use some additional security token, but it will introduce odd functionality to services and will make the whole setup more complex.

    Also, this approach looks like an attempt to escape the problem, you can't always avoid composite requests.

  4. We could use full-scale distributed transactions, e.g. 2PC, but it will make the system dramatically complex and will mitigate the use of MSA in the first place.

  5. And the final idea is to merge those two services together, but it will make no sense in microservice architecture to do so.

Enloe answered 23/3, 2017 at 16:1 Comment(0)
S
1

Here is my thought

1.User Service - should be responsible for

Creation of user which includes user name ,password (hashed) , email and any other profile data

validation of input data against validation rules

validation of user using his password

pros

further adition of profile data is easy

finding and validatng user in single request

user related login in single place

2.Authentication Service should be responsible only to generate tokens based upon successful user validation via user service

these token should be used for further processing by all other services in ecosystem and will make sure proper authorisation

pros

future addition of services that will require user authentication and authorisation can work independently and will require only security token.

Generation of token based on previous token can be easy ,user will not need to enter his user name and password each time his token is about to expire.

Speedy answered 27/3, 2017 at 6:47 Comment(0)
B
0

Regarding #5, I really don't see that you are somehow committing a horrible violation of principles by merging into one service here (point 5), a kind of “UserManagementService” that takes care of both tasks; even if it can be argued that one MS should perform one task and do it well, these two are intimately related, IMHO.

Another option is to make UserService a sync client of AuthService (load balanced, with circuit breaker, whatever, to ensure availability of one instance), which would be basically the same as injecting the dependency for a password validation in "normal" code.

If this is a greenfield thing and you are not stuck with these two services, in general, I would go for a simpler first implementation, and resist the impulse for optimizations, as these tend to be premature, or a unwarranted commitment to the purity of principles/dogmas. You yourself are aware of the complexities you could introduce (2PC) plus you have your requirement there ("so we can't get back to user and tell him to correct the password").

Burgoo answered 23/3, 2017 at 17:15 Comment(0)
S
0

I agree with #5. The two services will have many dependencies since accessing UserService will always relate to AuthService, and they probably access related data. If you separate them you may need to separate their shared logic like generating the passport. It can be in a service that has an operation that receives a userID either from AuthService (after validating credentials) or from UserService (after registration).

Also handling the absence of AuthService will raise questions about other scenarios, like if the user already registered and cannot login, how do you handle it?.. If you're showing an error message, why not when they register?.. just a question for more thoughts about your requirements.

Cheers

Speller answered 5/4, 2017 at 18:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.