I am having a difficulty in terms of architecture and wondering if someone has some insights.
The plan
I will have multiple microservices (different laravel projects, catalog.microservice.com, billing.microservice.com) each providing an API.
On top of these will be an angular fronted consuming those APIs.
I will have another micro service (passport.microservice.com) for auth now thanks to laravel 5.3 passport this is even easier.
The flow:
User goes to catalog.microservice.com
user need to authenticate and provides a user and password
request is made by angular (aka client) to passport.microservice.com through password grand type to get an authorization token
now that I have a token I am authorized to call a resource from catalog.microservice.com
catalog.microservice.com needs to know if the token is valid and makes a request (some kind of middleware?) to passport.microservice.com
passport.microservice.com returns the user, scope etc.
Questions:
Is this a good approach?
The token validation in catalog.microservice.com can be a middleware?
The common approach in microservices architecture is to use a single authentication 'gateway', and usually it's a part of an API gateway.
So besides your passport.ms.com, you have somewhat of a proxy that will check access token from the header and if it's invalid - give an error. If the token is valid - proxy the request to corresponding microservice.
This way you don't have to repeat yourself - you don't have to implement authentication N times for each microservice.
Then, if you need more granular control - what exactly a user can access (usually called authorisation), then you traditionally implement it at each specific microservice.
In short, your microservices shouldn't care if the incoming request is authenticated - it's already been pre-filtered for them. Microservices only decide whether the user X can do action Y.
PS. You can combine API gateway with Passport/Oauth facility or you may run them separately - that's up to you. AWS already offers API gateway as a service (proving how trendy microservices are becoming) but I couldn't find any good open source analogues.
Your api should have a gateway that handles the Authentication and communicates to different micro-services.
Its makes sense to authenticate (or reject unauthorised) users at the top level, combine responses from different services and then your clients(Web or mobile) can consume that data.
An advantage of this is that your clients only need to remember just one url.
Example: Only microservice.com is needed and not catalog.microservice.com, users.microservice.com, passport.microservice.com etc.
A single endpoint address (URL) is much easier to remember and configure than many individual API addresses.
Here is a link to an image describing this architecture.
Api Architecture image
Related
I want to use auth from google firebase, and integrate it with spring boot.
I am not sure that I have good idea how to implement roles/authorities.
I have in mind this scenario:
On success authentication with firebase, frontend send request to secured spring backend endpoint, and data on this endpoint contains which roles should user have, so frontend use this data to set claims for user. Backend use claims to authorize user when accessing endpoints.
Is this okey, or is there faster/better solution?
That sounds like a good approach. Have a look at the Firebase documentation on verifying ID tokens as that'll be your starting point once your backend receives the token from the client.
The only addition I can make at this point is that many of Firebase's own backend services cache recently decoded tokens (with the undecoded token as the key) to allow subsequent requests to more quickly look up the information for that token. While this is not required, it's an easy speed up once you're ready for that.
There is a lot of good content on the internet that explains how to secure a Spring API with Keycloak: Create a Client that represents the API Service in Keycloak and use a link like the one below to get the access and refresh token:
<Domain>/auth/realms/<realm>/protocol/openid-connect/auth/{some parameters}
This yields both tokens. So far so good.
Now, however, I am not sure how the flow for the frontend accessing the API should look like.
Should the frontend directly access this endpoint and, therefore, obtain the access and refresh token? That would mean that the API can only have the access-type public because there is no way to store the client (the API) secret securely.
Or should there be a third server that somehow stores the refresh token for each user, that the user can call if his access token is no longer valid. This server would then use the client's refresh token (and the client secret that could be stored securely, since it would be in the backend) to get a new access token from Keycloak and would forward it to the user.
I guess the main question that I am asking is, whether the client/user should get the refresh token.
If one needs to implement a logic according to the second option, I would be interested in a link or description of how something like this can be done in Spring.
I think, in either case you need to use the Authorization Code Flow. The implicit flow, which was recommended for SPAs (frontends without a backend server) in former versions of OAuth2 must not be used anymore.
The best option is to have a backend server, so the user retrieves the auth code via redirection and the backend server exchanges this auth code with the access and refresh tokens (and keep them without forwarding them to the frontend).
If there is no backend in place and your frontend needs to retrieve and hold the tokens directly, I would recommend to use the Authorization Code Flow with a public client and the PKCE extension (which - put simply - ensures that the entity asking for the auth code is the same as the entity asking for the tokens and that the auth code was not stolen and used by a foreign entity). There are several sources with more detailed explanations, which might help you, for example: https://auth0.com/docs/flows/authorization-code-flow-with-proof-key-for-code-exchange-pkce
Hope this helps you with your architectural considerations.
I have developed a set of microservices (resource servers) using Spring Boot 1.5.x + OAuth2 with JWT. Right now each microservice is protected using Spring Security i.e. JWT access token is verified at individual resource server level. API Gateway does not have spring security in place, so it just routes the requests to appropriate server and propagates the authentication headers to downstream services.
I wanted to know if there are any disadvantages of this setup compared to the one where AccessToken is verified at API gateway level only. Or is it just a matter of opinion? Doesn't keeping security at API Gateway level breaks principle of loose coupling, because each microservice may better understand the role of a given user in its own context?
API management can do a small check on your JWT (fail early), BUT your microservices are the only one that can really manage all the security stuff !
If you set security only on api management it means that someone that can access your network will be able to push request to your API unauthenticated.
You will not be able to log who do what. And finally, if you need to set some kind of ACL, it will not be possible (When you ask to list orders, you can only list YOUR order).
Perhaps you will think of decoding your JWT on the api management layers and push a header with user name to your backend to prevent all the thing I spoke about above, but I think it is not really a good practice.
First, access to network will means I'm able to be anybody. Then JWT is much more than just a username. For instance, perhaps you use scope on your authentication layers. ( scope read orders / scope modify orders / scope delete orders). This is useful to restrict what an application can do (either at client_id level) or what a user accept to give to the application ( scope share email ...).
For this JWT on the backoffice is mandatory.
Ok you can do like username and extract data on api management and put specific headers to call backend, but really ? why do specific stuff ? oauth2 with JWT can do this for you.
Well this is an interesting question. In our team we discussed about this topic a lot. Basically you have some parameters affecting the individual answer to this question. But you should always decode and verify granted tokens on the microservice level, too. Because they contain relevant information for authentication and in some cases even for authorization. If your microservices run in a enclosed environment (e.g. on enclosed Kubernetes cluster, where only the API-Gateway is available to the outside) you could use this "mixed" solution.
You can really consider just to verify the AccessToken at the API-Gateway and let the other microservices rely on the API Gateway. The API Gateway could than exchange the AccessToken into another AuthToken, only valid in the microservice-context. This new generated AuthToken can for example contain more sensitive application-bound information, because it is not exposed to the client. The Client gets only a so called opaque token. See https://medium.com/tech-tajawal/microservice-authentication-and-authorization-solutions-e0e5e74b248a
I have a number of stateless Microservices behind API Gateway and I want to make sure that a user request containing valid Authorization JWT token cannot access resources of other users.
Currently, my API Gateway only validates if the JWT is not expired and is valid.
To prevent a user request with valid JWT access resources of other users, I was going to use Spring's Method Level Security and check if the principal user id matches the userId in the request URL path. But that means that, in each microservice, I need to add Spring Security, create an authorization filter, and create a security context based on the information I read from JWT. I will need to recreate the Spring Security Context in every single Microservice.
Is it a correct way to do it? If not, what is another way to prevent a user request containing valid JWT to access the resources of other users?
Please advise me.
How you’re handling it is usually the correct approach. In order for each service to remain de-coupled from others it’s important it is able to determine which methods/endpoints care about the user scope and which ones don’t. More rules and logic in the gateway means more restrictions on what individual services can do.
That being said, if you have globally predictable rules that apply to all services you have a case for putting the logic in the gateway. Something like JWT verification is an example of such a rule that is standardized enough that you can make assumptions about what underlying services would want to do with the token upon receiving it (verify it). If you have a rule you can safely apply globally, you can pull it out of the services and put it in the gateway. Otherwise, you’re better off with a bit of duplication so that you don’t create hurdles that would prevent services from handling input differently.
Application has front-end and back-end modules, front-end calls rest services from the backend written on Java/Spring.
Is there any best practices how to detect malicious request generated not by the front-end (if some user try to call service direcly from the back-end via rest client)?
Maybe generating some hash value for every request on front-end and decrypt this value on back-end validating this request?
What you need is authentication. The backend needs to authenticate either the frontend web app, or the user itself.
Probably the most common way is authenticating the frontend, which practically means that frontend and backend have a shared secret, authentication takes place upon each call, and the backend trusts the frontend. This can be achieved in countless ways from http basic auth (over https of course) to some kind of an api key mechanism (signing requests, etc.) You don't have to reinvent the wheel, depending on your usecase and threat model, http basic auth over https may very well be enough.
Another way to do things is to delegate user credentials to backend services. This is most often achieved by passing single sign-on tokens from the user to the backend, effectively impersonating the user when the frontend calls backend services. Arguably this is more secure, as for instance it does not need that level of trust between web and app, but services still need to trust the SSO component that issued the token. The point is that there is no secret for an adversary to steal (let alone from the frontend server, which may be an easier target), so it may be more difficult for an attacker to issue requests to backend services, even if some backend and/or frontend servers are already compromised.
So while I think an answer here is not the right format to go into details about how exactly to do this authentication (there really are multiple good solutions, and in every case, implementation details matter very much), at least conceptually these are your options I think.