3

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.

darasd
  • 2,899
  • 3
  • 26
  • 39

1 Answers1

0

My understanding is you want to propagate authenticated identities through a distributed architecture that includes async messaging via RabbitMQ message broker.

When you send/publish messages to RabbitMQ you might consider including the JWT in the message headers i.e. similar to how JWTs are included in HTTP headers for calls to protected HTTP routes. Alternatively if you're feeling a bit lazy, you could just have the JWT directly on the message payload. Your async (Windows service) consumer could validate the JWT on it's way through or it might just pass it through on the subsequent HTTP requests to protected routes of 'other http microservices'.

I'm not sure if you're question about 'which flow should I use' is relevant as presumably the user is already authenticated (via one of the OIDC/authN flows e.g. authentication code grant, implicit, ROPC...) and you're just looking to propagate the JWT through the distributed architecture for authZ purposes...

In terms of sending custom message headers, I have done this with RabbitMQ and MassTransit, but it was for (OpenTracing) trace Id propagation between asynchronous message broker operations. Repo is on GitHub here - might give you some ideas about how to achieve this...

[edit] following clarification below:

Below are some options I can think of - each one comes with some security implications:

  1. Give the async (windows service) consumer the JWT signing key. If you go down this path it probably makes more sense to use symmetric signing of JWTs - any service with the symmetric key would be able to re-create JWTs. You could probably still achieve the same result with asymmetric signing by sharing the private key, but (IMO) the private key should be only be known to the authorization server (when using asymmetric signing).
  2. When the user authenticates, request a refresh token by adding offline_access to the list of scopes specified on the /token endpoint. You could then pass the refresh token through to the async (windows service) consumer, which would be able to use the refresh token to obtain a new access token if the previous one has expired (or just get a new one each time). There's probably some security considerations that you'd need to think about before going down this path.
  3. Increase the timeout duration of the access tokens so that there's enough time for the async (windows service) consumer to handle the requests. Not sure if this is viable for your scenario, but would be the easiest option.
Ryan.Bartsch
  • 3,698
  • 1
  • 26
  • 52
  • Yes, propogating the jwt is the obvious solution, however, due to the async nature of queues, the jwt may well have expired; hence the need to re-authenticate somehow. i've updated to the question to make this clearere. – darasd Jan 08 '20 at 10:46
  • unfortunately we can't generate a refresh token as we are using implicit flow (the user's client is an SPA). and increasing the timeout is not going to be possible due to our security restrictions. – darasd Jan 13 '20 at 09:10
  • @darasd if you can't do refresh token, validate only issuer, signature, audience... and forget about expiration, just accept any – Francisco Cardoso Sep 21 '20 at 19:08