I'm creating an online store REST API that will mainly be used by a mobile app. The plan is for a microservices architecture using the Spring Cloud framework and Spring Cloud OAuth for security.
My question is really on best practices for communication between microservices: Should I have each service register for their own token, or should they just pass the user's token around?
For example, I have 3 services: user-service, account-service, order-service.
I've been able to implement two procedures for creating an order: One passes the user's token around, and in the other each service gets their own token. I use Feign for both approaches.
So for option 1: order-service -> GET account-service/account/current
order-service calls the account-service which returns the account based on a userId in the token. Then the order-service creates an order for the account.
Or for option 2: order-service -> GET account-service/account/user-id/{userId}
order-service gets the userId from the sent token, calls the account-service with it's own token, then creates the order with the retrieved account.
I'm really not sure which option is best to use. One better separates information but then requires two Feign Clients. However the other doesn't require the 2 clients and it becomes easier to block off end certain endpoints to outside clients, however it requires extra endpoints to be created and almost every service to go digging into the Authentication object.
What are all your thoughts? Has anyone implemented their system in one way or another way entirely? Or perhaps I've got the completely wrong idea.
Any help is appreciated.
I have found below 3 options:
If each microservice is verifying the token then we can pass the same token. But the problem is - in between same token can be expired.
If we use client_credentials grant then there we are having two issues: one is, we need to send the username/id in next microservice. Another one is, we need to request two times - first for getting the access token, next for actual call.
If we do the token verification in API gateway only (not in microservices) then from the API gateway we need to send the username in every microservices. And microservices implementation needs to be changed to accept that param/header.
When you do server to server communication, you're not really acting on behalf of a user, but you're acting on behalf of the server itself. For that client credentials are used.
Using curl for exemple :
curl acme:acmesecret#localhost:9999/oauth/token -d grant_type=client_credentials
You should do the same with your http client and you will get the access token. use it to call other services.
You should use client tokens using the client_credentials flow for interservice communication. This flow is exposed by default on the /oauth/token endpoint in spring security oauth.
In addition to this, you could use private apis that are not exposed to the internet and are secured with a role that can only be given to oauth clients. This way, you can expose privileged apis that are maybe less restrictive and have less validation since you control the data passed to it.
In your example, you could expose an public endpoint GET account-service/account/current (no harm in getting information about yourself) and a private api GET account-service/internal/account/user-id/{userId} that could be used exclusively by oauth clients to query any existing user.
Related
I am working on microservices application where the client application sends the access token to orders microservice with the POST call. When saving the order, the inventory micro-service should be called to update the inventory. The Inventory microservice updateIntentory method should also be protected.
In this use case, should I be propagate the same access token to the inventory microservice and restrict the api access to update inventory or should I make use of client-credentials grant flow to allow saveOrder method in the order microservice to invoke the updateInventory method in the inventory microservice.
Note: Both the order and inventory microservices are acting as resource servers.
What is the right approach.
Good question:
BOUNDARIES
If you were calling an external API belonging to someone else you would definitely use client credentials to get a token that entitles you to call that API.
MICROSERVICES
If the data owner is the same then you should simply forward the access token. This is how OAuth is meant to work: a scalable architecture that only requires simple code:
Client gets an access token with scopes for multiple APIs
Each API validates the JWT
Each API verifies its own scopes
Each API trusts the claims in the JWT and uses them for authorization
The Scope Best Practices article explains this for a real world system.
HIGH PRIVILEGE OPERATIONS
It is common to get a fresh token for high security operations, such as redirecting the user with a payment scope. This should be the exception rather than the rule though.
I have an OAuth2 server that is able to give me an access token based on my client ID & secret.
I have a microservice where other servers can perform actions respective to its job.
However, I need to authorize the token to ensure it has the permissions to do that.
Is it common for the server to forward the access token to the auth server and get a response back that includes the details such as scope? etc.
Yes and no.
For the entry point, you definitely need to check the access token's scope by asking it to oauth2 provider, but you probably don't want to do it everytime it's following code to call the provider whenever it requires scope check.
In Spring framework, that authorized information is stored in SecurityContext, and any code in the same VM can access it by calling SecurityContextHolder.getContext().getAuthentication(). Probably you can implement similar thing with your language and platform you are using, so that authorized information can be shared by others, with thread-safe way.
However, in microservice world, each microservice could or could not have the scope its client used. For example, let's say there is client A, calling microservice B's C method, and B's C calls another microservice's H's I method.
Depends on what scope is required for the method B.c() and H.i(), even if your code can propagate the OAuth2 scope to the following microservice, client A's call could end up having insufficient scope exception and fails.
If you are lucky, then yeah client's call will succeed.
I had the same issue, and there wasn't any clear silver bullet or best practice for what to do with OAuth2 scope in Microservice world. I feel like it just all depends on what's your service topology look like and how it is designed.
I have a DashboardApi and an EnterpriseApi on my system. May be one more later.
I am new at IdentityServer3 and I wonder solve my problem.
IdentityServer saves client applications that will use an api. So I have 2 or 3 api. Will I create IdentityServer for all api? Because DashboardApi will consume EnterpriseApi. EnterpriseApi will consume another api.
And users will login to Dashboard application. I could not imagine the organisation.
To answer the question: you may have one instance of IdentityServer being your identity provider/authority across different "resource" APIs as long as they all point back to that same authority when it comes to token validation.
Then an access token used for "DashboardApi" can be used by "EnterpriseApi". It is important to proxy the token properly and in my experience it would be advantageous to create different scopes for each API to have better access as to which calls may be used to proxy into the second API through the first (especially if user consent is a concern).
I am currently thinking about building an application following the microservice architecture. To authorize the user I was thinking of using the OAuth protocol. Now the question is where/when to validate the Access Token.
I basically see two possibilities:
Each microservice is doing it on it's own (meaning one call that might involve 10 microservices would result in 10 token validations)
Introduce an API gateway (which needs to be there anyways I guess) which does the token validation and passes on the user ID, scopes, ... that the other microservices trust and use (which also means that some kind of authentication between the API gateway and the microservice must be there, e.g. client secret!?)
As you probably have already guessed, I tend to go with the second approach. Is that a valid one? Do you have some practical experiece with one of those approaches? Or yould you suggest another approach?
I'm looking forward to your comments/remarks on that!
Thanks and regards!
You almost definitely want a public/private split in your microservices architecture. The public side should be authenticating the token, and the private side is used to service calls from other API calls. This way you are only authenticating once per call.
You can accomplish this by, as you said, creating a gateway service, which dispatches those calls to the private services. This is a very common pattern. We have found it useful to authenticate the gateway side to the private API with client certificate authentication, sometimes referred to as two-way SSL. This is a little more secure than a shared-secret (which can easily leak).
I am learning oAuth2 for the first time. I am going to use it to provide authentication for some simple web services using a two-legged approach.
According to what I have read, the flow should go like this: the web service client supplies some kind of credential to the oAuth server (I'm thinking of using JWT). If the credentials are valid, the oAuth server returns an access token. The web service client then supplies the access token when attempting to use the web service end point.
Here is my question, why not just supply the JWT when making a request to the end point? Why is oAuth's flow conceived this way. Why not just supply to JTW to the end point and use that for authentication? What is the advantage of having the extra step of getting an access token?
Thanks!
You can certainly supply the JWT directly to the web service. The questions is how do you generate it in a way that the service trusts.
A JWT is and access_token, but not all access_tokens are JWTs.
Your client can issue a JWT, sign it with a key (or a cert) and then send it to the API. The advantage of having a 3rd party (an Issuer) is that you can separate authentication from issuing tokens. Clients can authenticate in multiple ways (e.g. usr/pwd, certs, keys, whatever) and then use the JWT to call your API.
The additional abstraction gives you more flexibility and management scalability. For example: if you have 1 consumer of your API, then you are probably ok with a single credential (or JWT, or whatever). If you plan your APIs to be consumed by many clients, then handing that responsibility to a specialized component (e.g. the the issuer) makes more sense.
OAuth BTW, was designed for a specific use case: delegate access to an API to another system on your behalf. You grant access to system-A to access resources on system-B on your behalf with a permission scope.