How can I replicate user roles from an Authorization Server to downstream microservices?

Juan Vega Source

I need to implement an application where I am going to use an Authorization Server generating a JWT token. These token will include the roles a user is granted to then authorize the user access to different resources. There will also be a gateway where this security will be added.

My question is regarding the user roles and the security between internal microservices.

When the user is created, he should be granted a set of roles and he may be granted different ones at a later point or maybe new roles will be added later. All this information should be stored in the Authorization Server. But how is this information replicated to other microservices? If I use a framework like Spring Security to secure my endpoints, where I add the roles needed for the different URLs, do I need to hardcode the user roles into my security configuration in the downstream microservices or is there any other way to find them from the Authorization Server?

The architecture is going to use an API gateway in a public network that then communicates with a service discovery in an internal one to find the different microservices. These also find each other through the service discovery. I use Zuul for routing. In this situation, do I need to also secure the communication within the internal network? I understand that to use Spring Security for authorization I would need to pass the JWT token anyway to get the user roles. But would it be necessary otherwise? Would it be enough to use HTTPS from the client to the gateway and unsafe HTTP within the private network?

securityspring-securityjwtmicroservicesspring-cloud

Answers

answered 1 year ago Lachezar Balev #1

There are many options here.

One of these is that you may use spring-security-oauth2 in combination with spring security. In this setup you will distinguish two kind of applications:

  • Authorization service (AS) - this service issues and verifies access tokens for authenticating clients (e.g. using password grants or authorization codes);
  • Resource service (RS) - it exposes a REST API for CRUD operations on resources, for example. The endpoints are protected. The RS communicates with the AS in order to grant access;

In a resource server you will use and configure the Spring Security as you would normally do in a stand alone application. Below is one very simple example.

Here is the code in a REST controller with protected endpoints:

@PreAuthorize("hasRole('READ_BOOK')")
@GetMapping(value = "/books/{id}")
public ResponseEntity<Book> getBook(@PathVariable("id") String id) {
    ...
    //retrieves book details if you have role READ_BOOK
}

@PreAuthorize("hasRole('WRITE_BOOK')")
@PostMapping(value = "/books")
public Book createBook(@RequestParam("title") String title) {
    ...
    //creates a book if you have role WRITE_BOOK
}

The security configuration will look just as if you are writing a monolithic application with the exception that:

  • you will add an @EnableResourceServer annotation on your configurations;
  • you will configure an instance of RemoteTokenServices - the task of this service is to verify the provided tokens against the authorization server and fetch user roles;

The AS will issue access tokens based on some OAuth2 workflow. These tokens will be used by the client to access the protected endpoints.

I've made a small PoC (proof of concept) setup in which I created two simple apps showing the whole thing in action. Please find it here and feel free to submit questions, proposals and PRs. The complete source code is included bundled with more explanations.

Please note though that this setup in certain cases may cause too much inter-service communication. I have seen a more complicated setup in which the API gateway acts as a resource server and if the user has enough credentials it enriches the request with the necessary details and passes the request to downstream services which basically trust the gateway.

comments powered by Disqus