Search code examples
windows-servicesmicroservicesmessage-queueopenid-connectidentityserver3

How should a message queue consumer impersonate a user in Identity Server 3 in a microservices environment?


We have a microservices environment using Identity Server 3. Identity is provided to http microservices via bearer tokens in the authorisation http header, where the token is a JWT. That JWT usually represents a logged in end user, but it can also sometimes represent a system user that has authenticated via client credentials flow.

Messages are published on a queue (RabbitMQ) by these microservices, to be processed asynchronously. Currently, we have a windows service which consumes those messages. It authenticates as a system user with client credentials, and sends that JWT in the auth header to other http microservices.

We would like to maintain the identity of the user that publishes the messages throughout the flow, including within the machine-to-machine (m2m) communication when a message is consumed from the queue and when that consumer calls other microservices. Ie, when Service A (which was provided with a JWT) publishes a message to the queue, then the windows service should be able to impersonate the user represented in Service A's JWT, and should be able to provide a JWT representing that same user when calling Service B.

Service A (running as alice) --> RMQ 
RMQ <-- Win Service (running as alice) --> Service B (running as alice)

Only clients with the correct claim should be able to impersonate a user in this way.

Which flow should I use in order to return the JWT to the Windows Service and how should this be achieved in Identity Server 3? I've managed to generate the JWT using Resource Owner flow, passing in a dummy username and password (overriding AuthenticateLocalAsync), although I've not yet attempted to check that the Win Service's client has a valid claim to impersonate. Or should this be a custom flow, implementing ICustomGrantValidator? Perhaps client credentials flow can be used?

Note that the original JWT can be provided with the message, or just the user id itself. The original JWT may have expired, which is why the windows service has to re-authenticate in some way.


Solution

  • I think the best answer that I've heard to this is to avoid the problem in the first place. Once a request has been authenticated for the first time and entered your ecosystem, you can dispense with the JWT entirely. Eg, authenticate the JWT at the API Gateway level, and then dispense with it. Once the request is inside the platform, there is no longer any need to use JWT tokens - they are an implementation detail after all. Instead, translate them into a custom domain-specific authorisation model, which can be passed around in custom http headers or message queue headers. This allows you to move between authorisation providers (who may provide different levels of JWT customisation) with less disruption.

    This obviously doesn't help much if you're services are already authorising JWT tokens inside your platform; however, it could be gradually introduced for messaging first, running in parallel with the existing JWT authorisation for http endpoints.