I'm developing an app with microservices and I don't know how to distribute microservices to allow auth.
I've read that each microservice should have its own database to avoid coupling.
The problem is that Authentication (via JWT) and Users Microservices must have access to the same database and table (Users). I suppose this problem has been solved before due to similar applications having to deal with the same issue.
How can I solve this?
JWS (the signed version of a JWT) is a perfect example as it was thought for similar scnearios:
signin.domain.com
), and once you verify the credentials of a user you issue the token, generated through private keys
service1.domain.com
, service2.domain.com
) can implement a middleware that instead does authorization: all your services will receive the public key and will be able to verify the authenticity of the token through that key. They don't need a DB since what they need to verify is that the token is valid, not that the user exists etc etc.To clarify my last statement: you should probably issue very short-lived tokens. At that point, say that:
service.domain.com
On service.domain.com
you will still consider him logged in until you, for example, need to interact with an API that actually hits the DB (ie. add a new user address). At that point the service that is responsible for writing into the DB will throw an exception saying the user doesnt exist and you can probably trap it and log the user out. All of this can be tweaked / fine-tuned but you get a rough idea of how it could work.
Getting back to JWTs and their usage, I don't know if you are familiar with PHP but this is a pretty straightforward example.
If you want to get fancy you could use nginx as a middleware and have something like the auth module doing authorization for you.
Last but not least, we've only covered authentication here: to do authorization you will probably either want to, in each service, either read the user's roles from the token (assuming you saved them there once the user logs in -- but this is a bit flawed as if a user loses a role then his token would still list it) or simply call signin.domain.com/users/me
from each service to retrieve an up-to-date list of user roles, and then check that he's allowed to perform certain operations on that specific service.
Oh, and remember that you should never put sensitive data in a JWT / JWS as they can be decoded. So yes, you can add user roles to a JWT but, for example, never save passwords or other plaintext tokens there.
Hope this helps!
We solve this by using composition of services to protect services that need authentication. A lot like the way you would approach it if it was a monolith.
As @odino mentioned:
Here's an example with StdLib (what we use in-house):
const lib = require('lib');
module.exports = function(params, callback) {
lib.user.isAuthenticated(params, (err, user) => {
if (err) return callback(err);
// We're authenticated – do the rest of the work.
});
}
The caveat to this is that if you're using HTTP as the protocol to communicate between your services, you're essentially adding a 200-300ms overhead to your authentication. You can solve for this by loading the services that need authentication within the same container (StdLib does this out of the box iirc)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With