Authentication in microservices using jwt - authentication

I'm going to build micrservices using Laravel framework.
I have users microservice that processes clients credentials and authenticates them (creates JWT for clients).
Also, there are another microservices that require user authentication.
And the question is, how can i validate clients access tokens in microservices (except users microservice), if the secret access token key is only in users microservice? Or, should i keep the secret key in each microservice?

Instead of handing out the secret key to each service you might want to consider signing JWTs with private/public key pair using RSA. That way only one service has the ability to create/modify tokens and the others can only verify them. Public key should be stored in the services or requested from the authentication service in the backend.
More thoughts on SSO in microservices can be found here.

Related

Use JWT to authenticate separate API Microservice

I am developing an app using microservices in NodeJS. I have built an auth api which handles the usual registration login etc and it issues JWT's
How do I use these to protect routes in a separate API microservice written with Express?
Do I need to use JWT with the secret to decrypt the token in the API app?
You could write a library that you import into your other microservices that requires all routes by default to require authentication. This library could have a mechanism to validate JWT's at the microservice level, so you never need to talk to your auth api to see if a JWT is valid or not. See the description and diagram below:
Your auth server will will need to be the single issuer of JWTs to your microservices. So, when a user logs in and successfully authenticates, your auth server will issue a JWT signed with a private key (signing MUST be asymmetric - RS256 is one example) you keep on the auth server only; do not give this private key to other microservices that you wish to validate JWTs inside of. What you can do is derive a public key based on the private key you sign your tokens with and publish that to an endpoint on your auth server that requires no authentication - the public key will be represented in the form of a JWK (see link to spec). Google does something similar here. Then, in each of your microservices, your library will need to devise a way to make a GET request to the public key endpoint on your auth server every X minutes to see if there are any changes and cache the public key in each microservice. By having the public key cached in your microservice, you will be able to validate the requesting JWT inside the service that is being requested.
Then whenever a request comes into one of your microservices, the library you import will examine the requesting JWT, check its validity, and grant access/authorization if the token is valid. The beauty of using a private/public key pair and asymmetric key signing is that you can validate a token based on the public key alone, but not sign it. So as long as each service has the public key from your /cert endpoint, they can validate a token without ever needing to talk to the auth server or knowing the private key.
This will require a little more work up front, but will yield you massive amount of ease, flexibility, and peace of mind in the future knowing only one source knows your private key.
One common pattern here would be to use an API gateway as the entry point to your entire microservice architecture. Incoming requests for authentication would be routed to the appropriate microservice. If the credentials provided be correct, a new JWT would be returned to the gateway, which would then forward to the caller. For the actual microservice APIs which comprise your application, the gateway would check that the incoming JWT be valid before allowing the request to hit the microservice.
This answer leaves out a few things, for simplicity. For instance, often you would want to have an authorization microservice, which decides what a user is allowed to do. Also, implementing JWT can be involved. You might need a cache layer to keep track of whitelisted and/or blacklisted JWT.
Here is the solution I came up with, to handle user data we can implement an Identity Provider Service (IDP) which is responsible for signing JWTs with symmetrical keys (rs256) and storing user information. The Identity Provider also has an open endpoint which will expose the public key in the form of a JWK (JSON Web Key) which is used to sign the JWT, This endpoint can be used to validate issued keys by any other service (ideally the external service would cache the JWK to reduce traffic to the IDP).
But This also poses another issue, that is we will have to implement more code to validate the tokens with the JWK endpoint. This is where an API Gateway comes in, The API gateway sits between the frontend client and the API server acting as a checkpoint. The API Gateway caches the JWK using the IDP endpoint and validates all the incoming requests. This means we would only have to implement features like JWK validation, rate-limiting, and SSL only to the API Gateway and we will not have to rely on the internal services for implementing these. Plus another improvement to the API Gateway would be to write the decoded JWT data onto the headers so the API Gateway can pass the decoded data for example: x-jwt-email: person#email.com directly to the internal services.
I found inspiration for this implementation from various sources and this was one of the first system designs that have completed building so let me know if there are any loopholes or improvements that could be implemented.
The code for the above implementation can be found here:
Identity Provider
API Gateway

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.

Is API key a way of Authorization or Authentication?

I am using API keys with my web service. I share a key with the client and they send it with every request.
Is this Authorization or Authentication?
An API key is a method of authentication. Using them for security purposes is often frowned upon. You can read more about them here

In a microservice environment, should any producer be able to verify JWT tokens?

I'm trying to figuring out how to manage authorization in a microservice environment.
This is my hypothetical scenario.
I have a service which provides authentication (using devise gem) and authorization via oauth2 (using doorkeeper gem). Once logged in, the service returns a JWT token to the user.
Now let's suppose I have two API servers. The user must provide the JWT token to these API servers in order to access to private resources.
Is it ok to share the JWT secret key I used to sign JWT token with my two API servers so they can decode the token and verify its validity? Or should my API servers forward the JWT token to the authorization service and ask it to verify it?
Pros of sharing JWT secret key with API servers:
no round trip to the authorization service
Cons of sharing JWT secret key with API servers:
if someone breaks in any of my API server, he/she have access to my JWT secret key
I am stuck. I don't even know if there is a third solution I didn't consider :)
Thanks!
You can use a PKI signing/verification system. In this approach, your authorization service will sign the JWT using a private key and all the consuming services will need the public key to use the JWT. The public key can be distributed easily - maybe through a config server if you have that in your architecture. Even if someone breaks into one of your services then he will only have a public key and not the private key.

Client authentication in microservices using JWT and OpenID Connect

I've some questions regarding authentication in a microservices architecture. I've right now a monolithic application and my goal is to split the application in small microservices.
My bigest problem is for authentication (for now). After reading a LOT a documentation, It seems that the best solution is to use OpenID Connect to authenticate an user to retrieve a JWT that can by passed with the request to the microservices.
Also, to avoid having multiple endpoints, you can deploy and API Gateway to have only one endpoint for the end user. Ok, so now I've two questions with this architecture.
The standard flow for authentication will be :
An user contact my identity server in OpenID Connect with the implicit flow and get the id_token (JWT) and also the access_token. The user can now contact my API with this access_token. The API Gateway will valide the access_token with the identity server and also retrieve the JWT to add it to the sub request to the microservice API.
1/ How the API Gateway can get the JWT from the access_token? From what I red from the documentation (http://openid.net/specs/openid-connect-core-1_0.html), It can contact the "/userinfo" endpoint but It will get just the JSON format not the JWT...
2/ I want to allow authenticated calls between my microservices. So each microservice needs to be able to generate a JWT to contact other microservices directly. My first thought was to contact the identity server. But with the OAuth2 Client Credentials flow, I don't retrieve a id_token or a JWT. Just a classic OAuth2 access token without JWT. My second thought was that the microservice can directly sign its own JWT with a certificate issued by the same PKI as the one used by the identity server. That mean that a JWT can be sign by several certificats but from the same private PKI. When a microservice receives a JWT, It needs to be able to identify witch certificat was used to sign the JWT. I don't find anything on the RFC regarding this problem. I can add my own private claim in the token to have the certificate but after several days of browsing the web without seeing this kind of solution, I'm wondering if I'm not on the wrong path... To sum up, how can i perfom "User to service" authentication AND alors "service to service" authentication in JWT?
Thank you very much!
I am implementing a similar solution. Not sure if it will address to your question completely, but, I hope it helps:
You can implement a new authentication micro-service to convert your oAuth2 access token to JWT token. This microservice will also sign this JWT token.
Your API gateway will route all client requests to authentication service, which will validate this token from IDM and will convert it to a signed JWT token.
API gateway will pass this JWT token to other microservices which will validate the signature from Authentication Service's public key. If the signature validates, roles can be extracted out of it for authorization.
Each microservice can have its own IDM credentials configured and when it wants to call any other microservice, it can generate an access token and call Authentication Service to get JWT which can be passed in call to other microservices.