简体   繁体   中英

OAuth2 flow from resource server to another

Implementation agnostic discussion.

Assume the following diagram. 在此输入图像描述

  • Black lines show which services are protected by the auth server.
  • Green lines show interaction between services(Customer, and Orders services need to go through the Data service which will access the database. StandAlone service doesn't like other services)
  • Red line show a specific request flow
  • Data service is not exposed directly to the outside and can be accessed only by other services that are allowed to do so.

I make the assumption that the client has obtained an access token when the user authenticated with the auth server. Which flow was picked(implicit, authorization code, password) is irrelevant. I would like to start the discussion from the point where the client has already obtained the access token.

From that point on, it is clear to me what happens when the client needs to access a single resource server.

  1. Make request to resource server and pass acquired token
  2. Resource server validates the token (irrelevant how)
  3. If valid, serve request.

So in that diagram if the client was to access the "StandAlone Service"(which does not talk to any other resource server) the flow is clear to me.

I am having trouble when the client follows the red line in the diagram. So i need to access a service(resource server) which in order to reply needs to access another service(also resource server). How does the flow go in that case?

Scenario 1.

  1. The "Orders service" is setup both as a resource server and as a client.
  2. Client makes request with the access token but the "Orders service" will acquire another token with its own client credentials in order to talk to the "Data service".

The problem here as i see it is that i loose the user permissions. I will execute the request to the "Data service" with the "Order's service" permissions and not the user's permissions.

Scenario 2.

  1. The "Orders service" is setup only as a resource server.
  2. Client makes request with the user token and the "Orders service" will forward the same token down to the "Data service"

Here i execute with the user's permissions but now i see that my "Data service" is exposed and open to any other service. (Actually i don't know if oauth2 provides such limitation. Restrict a client only to specific resource servers)

Scenario 3.

Here i see a combination of the above scenarios where the "Orders service" will provide both tokens to the data service. The user access token so that request is executed with the right permissions and the "Order's service" client access token so that i know that the service is allowed to talk to the "Data service".

Implementation

I am using spring boot and spring security in order to setup my oauth2 components seen above. I already have an auth server, a resource server and a client. The client at the moment talks to a resource server without the request being delegated to another resource server.

Depending on the best approach how would i go on the implementation side? What changes do i need to make to my resource servers so that they can talk securely to each other?

Thank you for your time

From my understanding, first approach would seem the correct one, in the sense that "Orders Service" acts as a client to "Data Service" resource server. So it should use an access token provided to it as a client.

OIDC is specifically intended for clients (read here . also look on that page for "why-use-access-tokens-to-secure-apis"), no resource server should use that id_token for anything (but it's true that each implementor follows its own decisions on that matter so it's confusing. i recommend reading here ).

So, from my point of view, we have these alternatives to reach what you asked for:

  1. "Orders Service" to act as a client with full control under "Data Service" resources (or at least the 'resource type' you want to access to). If you need to provide to "Data Service" some info regarding who was the originator for "Orders Service" to request whatever, then this is part of the payload when requesting the resource (it's not part of the access_token).
  2. Resource Owner (User) to previously had granted specific access to "Orders Service" to his "Data Service" specific resources. Similar to previous point, but "Orders Service" does not have access to all "Data Service" resources. Info from originator still as part of the payload.
  3. To avoid passing originator info as part of the payload, i guess we would need to be able to generate "Orders Service" client credentials 'on demand' with some fields regarding resource owner they are linked to, or somehow user previously creating them and linking to his profile so that later could be retrieved by "Orders Service". That's where it starts to get messy to my undertanding, and documentation is not clear (OAuth2 RFC does not cover that).
  4. Look at the whole system as one, with only one client. access_token received from the front client (the one the user interacts with) contains all specific scopes needed. Both "client", "orders service", "customer service" share same client credentials and just forwards "access token" from one to the other (so it's not "client credentials grant" anymore). So they both have exactly same set of permissions. Resource owner will grant those permissions when it does the first login to authorization server, so it's not that bad. But obviously this means you cannot refine permissions from each 'submodule client' and resource servers will not be able to determine which 'submodule' was the request from based on access token userinfo request (if needed, it should be part of payload). this has security implications for sure .

I have only used alternative 4 so far (it was for internal network purposes). So cannot say much more about the other 3 in real world.

I am yet to see a concrete explanation based on 'community accepted standards' on how to reach what you asked for (and that does not directly contradict specifications).

You're mixing authorization and identity concepts.

oauth2 roles ( resource owner , resource server , authorization server and client ) are roles and not identities. Your order service has the resource server role in one scenario and client role in the other.

The scenario 1 is the right approach.

Oauth2 tokens are indeed tied to some resources identifiers and so restricting a client to a specific resource is a built-in feature.

Client related authorization set is handled using Oauth2 scope concept

If you want to propagate the end user identity across a request flow you have to propagate an identity token (for example a JWT one) across the flow (see OIDC ). However it may not be the data service responsibility to handle end user authorizations.

I am having same situation(we call it server-to-server call situation) and so far I've accessing it by setting service A as oauth2 client of Service B for service A -> service B call.

And when you set service A as oauth2 client of service B, it's nothing related to what oauth2 scope that User's original token has. since It's service A calling service B, so that A should be able to call B with A's own oauth2 access token that has all the oauth2 scope that A requires to call service B.

In order to do that, you can either 1) just use some kind of configuration in A's side and swapping OAuth2Authentication in the SecurityContextHolder while calling service B, and restore the original OAuth2Authentication when getting response from service B or 2) add logic in service A that request an access token with pre-configured oauth2 clientId and secrets and use it to call service B. ( same swapping logic need to be done as I mentioned in case #1.

If you don't treat service A as oauth2 client of service B but using same oauth2 scope of original user's token, then you will end up having problem with keep granting whatever oauth2 scope that downstream service call is going to be required to the user's oauth2 access token, and when there are multiple service-to-service calls made ( or when downstream call's oauth2 scope is added/modified ), you'll never able to track it down properly. By considering service A as oauth2 client of service B, you only need to take care between service A's oauth2 clientId(or access_token)'s granted scope.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM