I'll have to frame challenge this. Your code inherently has super-user/god/system-level/call-it-what-you-want privileges. Your code decides what happens. If your code is buggy, no permission system will save you!.
But let me address two actual approaches first:
1. Put the authentication token into the Message
If you do this, service B can use the token for all its actions. All actions can be properly secured. But what do you do when that token expires before your message is consumed? In that case you're totally out of luck. For that reason i'd discourage this approach.
2. Put the user id into the message
This way, service B still has the context information. It can now obtain a token for itself with permission scope of that user; the token gets granted to service B (and you can verify that only service B can make requests with it) but the token has the permission scope of the user, so all actions can be properly secured.
Further upside is that you can track in your logs that some actions were not performed directly by a user but rather by one of your services on behalf of the user.
This requires service B to have that impersonation privilege, though. I'd say this is perfectly acceptable.
But this one also has a problem: what if service B has to perform an action that an end-user should never be allowed to do themselves, but can reasonably result from one of their actions? Then this doesn't help, either.
So, here comes a little frame challenge:
3. God privileges and code review
Give service B god privileges. You can still use tokens that encode the "service XY acts on behalf of user Z" information for audit and debugging purposes.
Then, use code reviews to make sure
- all user-reachable endpoints have proper and correct permission checks on them
- your code doesn't do sh*tty things!!, especially code that reacts to MQ messages.
Here is an example of one such situation where you need god privileges. Say you're working on a car sharing software. You have a rental service. It that handles ending the rent with the user and then publishes a
CarRentalEndedMessage. Your cleaning-planning service will want to listen for this message and maybe enlist the car for cleaning. That is 100% reasonable. But do you want your end users to be able to enlist vehicles for cleaning?