Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for multiple APIs with unique scopes #885

Closed
adestis-ds opened this issue Oct 29, 2020 · 8 comments
Closed

Support for multiple APIs with unique scopes #885

adestis-ds opened this issue Oct 29, 2020 · 8 comments

Comments

@adestis-ds
Copy link

I am referring to issues #852 and #620.

I am trying to access multiple APIs from the same client (SPA). Each API requires a unique scope (e.g. api1 for the first API and api2 for the second). Currently just one AccessToken can exist so the proposed solution was to call the STS server and request both scopes at the same time. This would result in an Access-Token having both scopes presented in the aud claim. Technically this should work.

However I consider this to be a major security problem. Basically it would require that API1 trusts also API2, which is not always the case. Here an example to make it clearer:

Alice requests an Access-Token for a Weather-API (Scope weather.read) and for a Financial-API (Scope financial.data.read_write). Both should be called from the same SPA client. Both APIs trust tokens from our configured STS.
According to the currently proposed solution Alice would be presented with an Access-Token having the aud claim set to

"aud": [ "weather.read", "financial.data.read_write" ]

Both APIs would accept the Access-Token because each one would validate the aud claim whether it contains the correct scope according to the API.

But now also the Weather-API could access financial data from the Financial-API just by presenting the Access-Token it just received from Alice. Just because Alice is allowed to access the Weather-API and the Financial-API it must not allow the Weather-API to access the Financial-API by replaying the token! The whole reason for the existence of the aud claim is to prevent such situations.

From my point of view: when a client should be able to access safely multiple APIs it is absolutely necessary to store multiple Access-Tokens each with a unique scope (may be a single scope just intended to access a single API). Each AccessToken should be invalidated independently according to it's exp claim.

Any thoughts?

@damienbod
Copy link
Owner

damienbod commented Oct 31, 2020

@adestis-ds I think we need add support for this. Thanks for reporting. I'll free up some time and plan time and implement this. You might be able to to this yourself with the token endpoint of your STS, but nothing is built into the lib at present

@damienbod
Copy link
Owner

@adestis-ds Looking into this now and have a number of problems with multiple access tokens in the SPA browser application (security not technical). I believe the best way of solving this securely is to use a backend for the SPA and this handles the different APIs. The access token was created for the user and the SPA together. The security requirements of the different APIs should not be handled in the browser as this is very hard to protect. If you allow both APIs access the from the same public browser App, then you implicitly allow API 1 to access API 2.

This could be implemented in a secure way using a backend and each API then protected with a different certificate or a secret. The SPA only uses the backend API which was created for the API.

You could also use the OBO flow in an SPA backend API which solves this problem as well. Then you still use a delegated access tokens for the user.

As a rule, the SPA should have as few as possible security requirements/flows, move everything to your secure backend which can be moved.

Greetings Damien

@adestis-ds
Copy link
Author

@damienbod I could understand if you say it's challenging from a technical point of view. But I disagree when it comes to security.

  1. The browser trust problem: When I get a token from a STS then this token is for ME (and the target audience) and I use the browser because I trust the browser - otherwise I would have a more severe problem (in other words: I do not calculate hash-values for SSL connections with my pocket calculator just because I can not trust my browser). Trusting the browser is a rquirement when dealing with OIDC - I believe.

  2. Different tokens (for different security requirements) are hard to protect in a browser: I disagree because I don't think that it is harder to protect than a single token combining all those security requirements. I DO AGREE that it is harder from a technical point of view - of course!

  3. Different APIs can be handled very well via an backend (proxy) backend: I agree BUT only if you are involved in backend programming. I believe with the rapid spread of public APIs there will be more and more projects just developing a frontend by using different APIs rather than creating a fully fledged backend API as a proxy (usually called an API Gateway). All those projects would share API access tokens accross different audiences, first because they don't know that this might be insecure and second because they do not have another chance because no SPA technology is supporting them otherwise.

3a. Even IF YOU ARE envolved in API backend programming and would be able to create your own API gateway this might not be the best architecture in all cases. You might end up with APIs calling APIs calling APIs... You might have a dependency hell on API level (I remember the good old DLL hell)... You might have a project member problem (you need to trust the programmer of the API gateway more than the programmers of the financial API team because he could access ALL data)... Again, the token is for ME and the TARGET AUDIENCE. In an ideal world It should not be usable for any party in between (except the browser of course).

  1. STS and API are able to handle different audiences very well. It is not a problem to ask the STS for a separate token for different audiences and validate them in a secure way within the APIs. Just the "middleware", the UI part in form of SPA, mobile devices, CLIs, native applications are not able to store different tokens for different audiences. I don't see the security problem here. I DO SEE that this is technically challanging.

Just to make it clear: My point is NOT that adjusting the UI is the only possible way how to solve this problem. API gateways might be a good way too (there you make a point) - however NOT for all kind of projects!

Greetings, Dirk

@damienbod
Copy link
Owner

We support this using a backend implementation so not to handle multiple access tokens in the browser.

https://damienbod.com/2020/12/08/using-multiple-apis-in-angular-and-asp-net-core-with-azure-ad-authentication/

Greetings Damien

@GarethBlain
Copy link

We support this using a backend implementation so not to handle multiple access tokens in the browser.

This seems like moving the storage of multiple tokens from the front end to a single backend API and requiring further servers to handle that. Also you now have an extra server in the middle. Wouldn't it be easiler to just store the extra tokens client side with the url(s) they are for? You would already need this list for any auth interceptor you use so you don't sent the bearer token to every url that's hit.

@eastjie
Copy link

eastjie commented Jan 13, 2021

We have a use case, that client requests a single backend API and also REST API of Microsoft graph, e.g. "me/outlook/tasks", because Azure AD is used for identity server. but the format of token of Microsoft graph and token of our api is totally different. I see some technical difficulties in SPA. OBO flow is certain a good solution, but I consider in this use case that one token for all REST API in one SPA, is it really possible? Thanks.

@damienbod
Copy link
Owner

Hi @GarethBlain @eastjie thanks for your feedback.

My main reasoning for this is that handling multiple tokens in the browser increases the security risks. A full UI login is required to get a specific access token in the browser. (or a custom hack) Getting an access token in the broswer can be done in an iframe which has the same site problems, or in a hidden popup or with redirects, all solutions which have problems. Using a dedicated API and a single access token for the SPA reduces the security risks and the problems. It is not possible to use the OBO flow or to keep a secret in the browser. Every token stored in the browser is stored in session storage or local storage which has its problems. All tokens in the SPA are public tokens for public APIs. I don’t see the need for an extra server no matter what the solution. Most SPA applications require at least one backend, which can be re-used. Using multiple tokens in the client causes multiple problems compared with server rendered or protected access. Getting the token and storing the token are the main problems. I prefer not to make my graph API public and prefer to only allow as few as possible APIs in the public zone. The less, the better. Any app used directly by a SPA is public.

If iframe silent renew was supported long term, I would see multiple public access tokens in the browser as possible.

I see 3 possibilities for SPAs which can work:

  • Using a reverse proxy to handle requests and pass the token on to APIs or get new tokens and request the APIs OBO, etc
  • Use a BFF pattern with cookies
  • Use a dedicated API and access token for the SPA

I understand all of these have problems and none are perfect.

Hope this helps

Greetings Damien

@damienbod
Copy link
Owner

damienbod commented Jun 6, 2021

Implemented, will be released in V12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants