Authentication and authorisation in microservice architecture - authentication

I have multiple services:
User
Post
Comment
Authentication
GraphQL endpoint
And let's say they are connected together like this:
All services are communicating through gRPC on a closed nettwork and the Authorization is done using jwt tokens
Approach 1:
The graphql service is responsible for user authentication and making sure that the user is authorized to run the specified procedure. There is no user authentication between the services, but there is TLS authentication. There are no authorization checks done by the services.
Approach 2:
Each individual service makes sure that the user is authorized to run a specific procedure. An example could be voting on a post where you would need to be signed in and have over 15 in reputation. Here it would be the Post service's responsibility to check whether the user is signed in or not (authenticated) and whether it's authorized to vote. This will result in large overhead since every procedure call needs to check user authentication and authorisation through the Auth service.
Is there a better approach that still preserves the security of approach 2, but creates a small overhead like approach 1?
-----Update-----
Approach 3:
Same as approach 2, but user authentication is only done in the GraphQL service using the Auth service. The authorization is done by checking metadata passed around. And there is TLS authentication between the services.

Let's consider a request that travels from the authenticated user to service A and on to service B. The JWT should be passed on each of these calls.
Both services would first authenticate the user which is simply done by validating the JWT. Then each service would extract all information necessary to authorize the user from the user, for example the sub claim. It would use this information to decide if the user is authorized with respect to the operation that the service shall perform on behalf of the user. Only after successful authorization would the service actually do anything.
This would not be overhead but necessary to allow service B to both authenticate and authorize the user. Not passing the JWT from sercice A to service B would make it impossible for service B to know anything about the user.

Related

Authentication with multiple services: Only one REST-call or multiple calls?

I have a question about using JWT in a webapp: An auth-service provides a JWT which gives me the information whether the user is known or not. Then another service will be called to check the user roles based on the JWT. It appends an API-key, the user roles and will call the real API.
Now my question: What ist the best auth flow?
Should the webapp do only one call: Calling the JWT-service which proxies the request to the auth service and this service proxies it to the real backend and all the way back?
Or should it look like this: Webapp calls JWT-service. The JWT-service returns the JWT to the webapp and then the webapp will call the auth-service in a second request.
Unfortunately the JWT-service cannot check the userroles :(
Are there any advantages/disadvantages or BestPatterns?
I hope that is not too confusing:D
Best
Lukas
I think you should consider using an API Gateway between your frontend and the underlying microservices. That Gateway will take care of forwarding all the calls.
For example, it will call the auth-provider which will build the JWT.
This token, in turn, should contain all the relevant roles for the logged-in user, exposed as claims.
JWT validation doesn't necessarily require a service call.
I wrote a blog post a while ago explaining the flow more in details: https://www.davideguida.com/handling-authentication-and-authorization-in-microservices-part-2/

identityserver4 protect public api

I am using identity server 4, I followed the tutorial, so I have an api, mvc client, console client, and js client.
I saw this blog too, which is probably close to what I need:
https://medium.com/all-technology-feeds/testing-your-asp-net-core-webapi-secured-with-identityserver4-in-postman-97eee976aa16
what I need is an api, where clients can access data, but first, they need authenticate.
we also have the console client, which is also close to what I need.
The only issue with this examples is that in both cases client knows the secret. But in our case multiple clients should use the same api, and if they all have the same secret, they can log in on behalf of each other, but I don't want to have different secrets.
So what I think I could do is to create an api which takes username and password, and returns the token. But I am not sure if this is the right way to do things? This feels like a resource owner flow, which is not supposed to be used for client facing APIs if I am correct. But in that case, how should I go it?
thanks
It seems that there is some confusion. Allow me to give a short summary. First the terminology:
A user is a human that is using a registered client to access resources.
A client is a piece of software that requests tokens from IdentityServer - either for authenticating a user (requesting an identity token) or for accessing a resource (requesting an access token). A client must be first registered with IdentityServer before it can request tokens.
Resources are something you want to protect with IdentityServer - either identity data of your users, or APIs.
Client credentials: The simplest grant type and is used for server to server communication - tokens are always requested on behalf of a client, not a user.
Now about authentication. The client requests tokens at the IdentityServer endpoint. When you use a client in combination with the client credentials flow, then you'll need a clientid + secret. Where secret is really secret and should be known to the client only. You can't use the same secret here. Seems logical when compared to users, they don't share the same password either.
This is close to the resource owner flow, however a client cannot login as a user. For that you'll need another flow, like the hybrid flow. In that case the client logs in on behalf of the user. The difference is the presence of the "sub" claim (the id of the user) in the token.
The client in this case is your app: console or mvc. The first only supports client credentials where the secret is mandatory, the second supports a hybrid flow, where secret may be omitted:
In certain situations, clients need to authenticate with
identityserver, e.g.
confidential applications (aka clients) requesting tokens at the token endpoint
APIs validating reference tokens at the introspection endpoint
The Api is your resource, that you want to protect. The Api never authenticates a user or client. This is done by IdentityServer. It only verifies the token (using the IdentityServer4.AccessTokenValidation package). For that it has its own secret that should only be known to the Api.
In order to grant the client access to the resource you'll need to add the scope to the client in the configuration of IdentityServer. The client is then allowed, not required, to request a token that grants access to the resource.
Again, the Api has nothing to do with authentication. It is also not bound to one client. Multiple clients can access the resource. All you have to do is add the scope to each client that should have access to the resource.
So there is really nothing against it that clients and resources know their secret. You don't have to change anything. All you have to do is choose the appropriate flow.

Authentication between microservice approach

I am currently building an API based around a microservices architecture.
I am using JWT to authenticate users. I understand that when a user sends a login request a JWT containing the users identity and their roles/permissions etc is returned. This token is then sent with the users subsequent requests to tell the server who is sending the request. I think this is the correct understanding.
In a normal monolithic architecture this works well as explained. How can I transfer this to a microservices architecture to establish trust between microservices.
I could forward the users JWT to downstream microservices simply but this doesn't allow the downstream microservice to know who/which upstream microservice is sending the request.
An example would be I have a location microservice. I want to allow the restaurant microservice to make calls to the location microservice. But I also have a product microservice that I do not want to be able to call the location microservice.
Obviously I could just not code the product microservice to call the location microservice but this doesn't stop someone else from doing so.
Any suggestions?
You can make the communication between microservices secure atleast by following two methodologies :
JWt token : Let assume micro service A wants to communicate with micro service B, then the token issued by A and the audience of the token is B. In that case the token is signed by micro service A with its private key. The aud field in JWT will represents the audience, it can be a single service or a set of services. The value of aud parameter should be a pre agreed value between the services. In micro services you can use the regular expression to validate the audience. For example aud can be *.samplemicroservice.com. Audience service B can check whether token is intended for it or not by checking the aud field. Once confirmed it can use issuer's public key to verify it.
Mutual SSL : The straight forward way to achieve it is to use mutual ssl between services. Each service should have SSL enabled and should presents its certificate to the the other service and other service should check the validity of the certificate with a trust store. This should be validated at both microservice A and microservice B to reach a mutual agreement. A self signed certificate can be used as root CA for all services certificates and can be accessed through a trust store.
There can be many variations of these mechanism. Specifically in case of JWT token. For example, You can delegate the token issuing responsibility to one service and can validate token in each of the service using public key of issuer service.
Here you have two different problems to solve!
1) User authentication/authorization:
Yours downstream services services should pass the user JWT token to services upstream (dowstream depends on upstream, the downstream is more near of the frontend). This way all services can validate the JWT token, and we can garantee that the token is unchanged.
2) Micro services authorizarion:
This is the second scenario you have, you need to garantee the trust relation between microservices and the authorizations to access a resource. In this case, ever microservices do you have shoul be a client (act as user), in a auth service (key cloak, Authservice...) and before send a request to any upstream dependecy, it should be authenticated, and send his own JWT token, in this way the destination microserveice (the called one) can validate and alow or not alow the caller to access the resource, and later, check the end user credentials.
This kind of approuch can be achieved using the client credentias autorization flow (https://oauth.net/2/grant-types/client-credentials).
See this article: https://developer.okta.com/blog/2018/04/02/client-creds-with-spring-boot
I guess this solution to this should be that JWT should be passed to the gateway layer / Aggregator / Facade layer.
At this layer, just decode the JWT and set the data in the DTO(any Java Class), so that same is accessible easily.
Now, when this information needs to be passed to any service, these should be passed as params as anyhow API at the service layer should be generic.
Now if you want to establish trust b/w services, you can simply check the parameters as the services are anyhow should not be exposed outside apart from aggregators.
Hope I am making sense.

Authentication and Services

I am designing a service oriented application where the communication to the database is distributed across multiple services (Authentication service, some service for auditing and other for accessing the db and doing CRUD operation ... etc).
Say a user login to the app using his id and password, the app then talk to the auth service and find out if the information are correct, once done the user want to insert some data, now the app use another service to fulfil the user request. How can the other service now that the user is an authorized user to use the service.
Your use-case seems very similar to what SAML addresses.
Also look at OAuth.
If these standard mechanisms don't work for you, you can at least develop a mechanism where:
The authentication service returns a token on successful login. The
caller app should then be able to use this token to access the data
service and other services.
The data service should be able to independently validate the token (possibly with the authentication service).
You might want to ensure that the tokens remain valid only for a certain duration or certain number of invocations
What this avoids is the need for every back-end service to allow access to the app without using your login details.
Also see: What is token based authentication?

Microservices user's access credentials

We are building a web application in microservices architecture.
We have a service that handles the authorization (i.e user's privileges, access credentials, roles etc...) and we are considering how to pass on these credentials in the system.
We have 2 option:
1. Sign those credentials in the gateway (auth and proxy service) using JWT and pass on all the information so every service could verify it (with its public key) and read the user's info.
2. Every service should make a request to the authorization service for querying the user's access on every action.
We are having difficulties on deciding which way is better in terms of high cohesion and loose coupling and of course making it easy for service development.
You have some other options: instead of reinventing the wheel, you can use an OAuth 2.0 identity provider/broker out of the box.
Keycloak is a free open source identity provider and broker that provides all these functionalities.
Auth0 is a managed commercial service that provides all these functionalities too.
And I'm sure there are many other services exist for OAuth 2.0 protocol.
As for your 2 options:
You can extend the JWT with your custom authorisation claims (roles or permissions) and since the JWT will be signed, then it is safe to assume the data is correct by your service. Give that the JWT is a short lived token that need to renew every few minutes.