OAuth 2.0 Single-use Access Token for unauthenticated user via IdentityServer4 - oauth-2.0

I apologies in advance for incorrect use of oauth terms.
I have 4 "parties" as follows (intentionally not using oauth terms where possible):
End-user in a browser (javascript)
Our website (aspnet)
Our web api (aspnet)
Our auth server (aspnet utilising identityserver 4)
My usage scenario is that we only want the API to be called by a browser that has requested a page from the website first. Whilst the API doesn't release sensitive information, we would like to introduce a layer of complexity with regards to the API being spammed.
Our end user's will not be logged in.
I imagine such a flow being akin:
Browser requests a certain page from the website (one that will likely lead to js making an api call)
Website requests token from auth server
Auth server verifies token request came from website (the server itself)
Auth server returns a token to the website
Website returns page including the access token
Browser is able to make a request to api using token
Although convoluted, I believe this is at least similar to the Client Access Grant flow?
These tokens could then be throttled either by website or auth server.
Yes, I'm aware that this doesn't protect the api from numerous other vectors, but it does eliminate the simplest of cases which is all we're looking to achieve for now. I'll add, I didn't define this requirement, I'm simply trying to find a way to achieve it utilising techs out there instead of making the mistake of rolling anything of my own.
Could someone confirm/deny that there is an oauth flow I could use here? Any sample projects using the given flow and IdentityServer?
IdentityServer3 / non-aspnet[core/5] examples are fine, I can translate.

What you describe is the Client Credentials Grant where your website (client) gets an access token from identityserver (auth server). That access token can then be used to call endpoints on your web API (resource server).
The token is a bearer token and can be used by anyone who has it, so if you are comfortable with your website passing it back to a browser on an HTTP response, then it will work just fine.
I'm not sure what you mean by throttling the tokens - once minted they are valid for their lifetime. I guess you can keep the time-to-live very short to achieve the single usage you want though.

Related

Implementing PKCE for Authorizing Backend Requests with OAuth

Yohoho! I am building an application that leverages OAuth to pull user data from provider APIs, and am wondering about the RFC compliance of the flow I have chosen.
Currently, the user signs into the authorization server which sends an auth code to my frontend client. The frontend then passes the auth code to my backend, which exchanges it for an auth token and then makes calls to the provider to pull data.
In this best practices document, it states:
Note: although PKCE so far was recommended as a mechanism to protect
native apps, this advice applies to all kinds of OAuth clients,
including web applications.
To my understanding, PKCE is designed to ensure the token is granted to the same entity that requested the auth code, in order to prevent attackers from using stolen auth codes to execute unwarranted requests.
Now, it makes sense to me why this is important even if the backend keeps the client secret unexposed, since the attacker can make requests to the backend with the intercepted auth code to receive the token. However in my flow, since I am not creating an authentication scheme and rather trying to authorize premeditated requests, the token stays with the backend.
So why is PKCE recommended here? It seems to me the most a stolen auth code can do is initiate an API request from the backend, with no token or data being returned to the attacker. And assuming a PKCE implementation is the way to go, how exactly would it work? The frontend requesting the auth code and the backend trading it for a token aren't exactly the same, so would it be as simple as passing the code_verifier to the backend to make the call?
Some clarification would be greatly appreciated.
PKCE ensures that the party who started the login is also completing it, and there are two main variations that I'll summarise below in terms of Single Page Apps (SPA).
PUBLIC CLIENTS
Consider a Single Page App that runs a code flow implemented only in Javascript. This would store a code verifier in session storage during the OpenID Connect redirect. Upon return to the app after login, this would be sent, along with the authorization code and state to the Authorization Server.
This would return tokens to the browser. If there was a Cross Site Scripting vulnerability, the flow could be abused. In particular the malicious code could spin up a hidden iframe and use prompt=none to get tokens silently.
CONFIDENTIAL CLIENTS
Therefore the current best practice for Single Page Apps is to use a Backend for Frontend (BFF), and never return tokens to the browser. In this model it is more natural for the BFF to operate like a traditional OpenID Connect website, where both the state and code_verifier are stored in a login cookie that lasts for the duration of the sign-in process.
If there was a Cross Site Scripting vulnerability, then session riding is possible by the malicious code, to send the authorization code to the BFF and complete a login. However, this would just result in writing secure cookies that the browser cannot access. Similarly, the hidden iframe hack would also only rewrite cookies.
The code_verifier could alternatively be stored in session storage and sent from the browser to the BFF, but it would be easy enough for malicious code to grab it and also send it to the server. This does not really change the risks, and the key point is that no tokens should be returned to the browser. It is OK to use secondary security values in the browser, as long as you can justify them, eg for security reviewers. Generally though it is easier to explain if secure values are in secure cookies and less visible to Javascript.
FURTHER INFO
Best practices often vary depending on the customer use case, and at Curity we provide resources for customers (and general readers) to explain secure design patterns. These are based on security standards and we translate them to customer use cases. You may
find our recent SPA Security Whitepaper useful.

Authorization and Authentication in microservices - the good way

I'm considering a microservice architecture and I'm struggle with authorization and authentication. I found a lot of resources about oauth2 and openid connect that claim they solve the issue but it is not clear enough for me.
Let's consider we have a following architecture:
In my system I want to add a feature only for a certain group of users defined by role. I want to also know the name of the user, their email and id.
After my research I find the following solution to be a good start:
SPA application displays login form.
User fills in the form and sends POST request to authN&authZ server.
The server replies with access token (being a JWT) that contains name, email, id and role of the user. The response contains a refresh token as well.
SPA application stores the token and attaches it to every request it makes.
Microservice 1 and Microservice 2 check if the token is valid. If so, they check if the role is correct. If so, they take user info and process the request.
How far away from the good solution I am? The login flow looks like Implicit flow with form post described here but with implicit consents and I'm not sure if it's fine.
Moving forward, I find passing user data in JWT (such as name, email) to be not a good solution as it exposes sensitive data. I found resources that say it is recommended to expose only a reference to a user in token (such as ID) and replace such token with a classic access_token in reverser-proxy/api gateway when sending a request to a microservice. Considering such solution I think that following scenario is a good start:
SPA application displays login form.
User fills in the form and sends POST request to authN&authZ server.
The server replies with access token and refresh token. API gateway (in middle) replaces access token with ID token and stores claims from access token within its cache.
SPA application stores the token and attaches it to every request it makes.
Handling a request, API Gateway takes ID Token and based on the user ID generates a new access token. The access token is send to microservice 1 or microservice 2 that validate it as previous.
How do you find such solutions? Is this a secure approach? What should I improve proposed flow?
Thanks in advance!
You are on the right tracks:
ZERO TRUST
This is an emerging trend, where each microservice validates a JWT using a library - see this article. JWT validation is fast and designed to scale.
CONFIDENTIAL TOKENS FOR CLIENTS
Internet clients should not be able to read claims that APIs use. The swapping tokens in a gateway concept is correct, but the usual approach is to issue opaque access tokens here, rather than using ID tokens. At Curity we call this the Phantom Token Approach.
SECURE COOKIES IN THE BROWSER
One area to be careful about is using tokens in the browser. These days SameSite=strict HTTP Only cookies are preferred. This requires a more complex flow though. See the SPA Best Practices for some recommendations on security.
SPAs should use the code flow by the way - aim to avoid the implicit flow, since it can leak tokens in the browser history or web server logs.
SUMMARY
All of the above are general security design patterns to aim for, regardless of your Authorization Server, though of course it is common to get there one step at a time.
Don't use your own login form. As Garry Archer wrote, use the auth code flow with PKCE which is the recomended flow for applications running in a browser.
If you don't want to get an ID token, don't ask for the openid scope in the initial auth request. The type of issued access tokens (JWT or opaque) can often be configured on your OAuth2 server. So I see no need to issue new tokens at your gateway. Having more token issuers opens more ways of attacking your system.
Your backend modules can use the userinfo endpoint, which will give them info about the user and validate the token. This way, if the token was invalidated (e.g. user logged out), the request processing will not proceed. If you validate just a JWT signature, you will not know about the token being invalidated.
If you plan to make requests between your backend modules as part of of a user request processing, you can use the original access token received from your SPA as long as your modules are in a safe environment (e.g. one Kubernates).

In Oauth OpenID - Authorization code grant type, where will we exchange the "code" for "access token" and why?

In Oauth Open ID - Authorization Code grant type flow,
We will call the Oauth service provider with the client_id = '..', redirect_uri='...', response_type='code', scope='...', state='...'.
Then from Oauth Service Provider, we will get the authorization code instead of the token.
Q1. So what is the next step? Do we send the code to the back end where the token request will happen or will we call the Oauth service provider from the browser it self?
Q2. Why do we need this additional calls? what problem it is solving?
Q3 After the token is received, how we use it in a typical web application?
p.s: I have read lot of blogs, but unable to get the whole picture. Could you please help me?
Q1. In 2021 it is recommended to keep tokens out of the browser, so send the code to the back end, which will exchange it for tokens and issue secure SameSite HTTP Only cookies to the browser. The cookies can contain tokens if they are strongly encrypted.
Q2. The separation is to protect against browser attacks, where login redirects take place. An authorization code can only be used once but can potentially be intercepted - by a 'man in the browser' - eg some kind of plugin or malicious code. If this happens then the attacker cannot exchange it for tokens since a code_verifier and client_secret are also needed.
Q3. The token is sent from the browser to APIs, but the browser cannot store tokens securely. So it is recommended to unpack tokens from cookies in a server side component, such as a reverse proxy. This limits the scope for tokens to be intercepted in the browser, and also deals well with token renewal, page reloads and multi tab browsing.
APPROACHES
The above type of solution can be implemented in two different ways:
Use a website based technology that does OAuth work and also serves web content
Use an SPA and implement OAuth work in an API driven manner
Unfortunately OAuth / OpenID in the browser is difficult. At Curity we have provided some resources based on the benefit of our experience, and we hope that this provides a 'whole picture' view of overall behaviour for modern browser based apps:
Code
Docs

OpenID connect access token to authenticate my own REST api

If I authenticate with OpenID connect, I can authenticate my SPA ok.
How do I use the obtained access token now to access my own REST resources?
It's a simple question, but I don't find satisfactory answers.
A prominent answer I always find is 'use oidc when you don't have a backend'.
Now that makes me wonder if ever a webapp was created that didn't need a backend.
Oidc is almost always the answer when the question of storing a refresh token in the client pops up (like in 'use oidc, it's a better architecture and ditch the refresh token') but it doesn't really explain anything.
So when the user logs in with, say Google, he obtains an identity and an access token (to ensure that the user is who he claims he is).
So how do you use this to authenticate at your own REST service?
The only real way I see it as stateless is by sending another request at the server to the provider on every request to the REST api, to match the identity to the validity of the access token there.
If not, we fall back to the good 'ol session vs jwt discussion, which doesn't quite seem to click with the oidc because now we're duplicating authentication logic.
And the good 'ol refresh token in the browser is generally promoted as a bad idea, although you can keep access tokens in the browser session storage (according to the js oidc client library), autorefresh them with the provider and that's fine then (-.-).
I'm running again circles.
Anybody can lay this out for me and please break the loop?
Your SPA (frontend) needs to add an authorization header with access token to each API request. Frontend should implement the authorization code flow + PKCE (implicit flow is not recommended anymore) + it needs to refresh access token.
Your API (backend) needs to implement OIDC (or you can use "oidc auth" proxy in front of backend) - it just validates access token, eventually returns 401 (Unauthorized) for request with invalid/expired/... token. This token validation is stateless, because it needs only public key(s) to verify token signature + current timestamp. Public keys are usually downloaded when backends is starting from OIDC discovery URL, so they doesn't need to be redownloaded during every backend request.
BTW: refresh token in the browser is bad idea, because refresh token is equivalent of your own credentials

Can I use Oauth2 Authorization Code flow for a SPA (React app), if I have a server-side proxy?

After watching an obscene amount of tutorials on OAuth2, there is one best practice that everyone repeatedly states - if you have a React app (or Angular, or Ember) - you must use Implicit flow with it.
I understand that storing client credentials in publicly visible javascript would not work. However, my scenario is a bit different:
I'm only using Oauth2 for single sign on and token generation for microservices. I chose it instead of simply generating tokens, since well-supported third party libraries are built around the Oauth2 idea.
My idea is to have a React app, and a ASP.NET MVC app which serves the javascript and acts as a proxy for API requests. The user authenticates for the server-side app (by using Oauth2 authorization code flow).
Then if I need to retrieve data from an API, I call my ASP.NET MVC app from React (by sending a simple cookie). The MVC app holds the token without ever exposing it to the user's browser.
Obviously, when called, my MVC app then redirects the request to the necessary API, providing the bearer token.
To better understand why this is what I came up with, here are some requirements I've received that might be unusual:
I really don't want the access token to be shared - even if it's relatively short lived.
I also want to be able to limit each user account to 3 concurrent user sessions. Easy to do using cookies and server-side sessions.
I can't wrap my head around why this idea would be that bad. Is there any technical problem that might prevent this from working? Or maybe a security risk?
The authorization code flow returns an authorization code (like it says on the tin) that can then be exchanged for an ID token and access token. This requires client authentication using a client id and secret to retrieve the tokens from the back end and has the benefit of not exposing tokens to the User Agent.
This flow allows for long lived access (through the use of refresh tokens).
Clients using this flow must be able to maintain a secret.
Accordingly to your description, you have service-to-service authorization flow, and as your service are not exposing client secret key it is totally OK to use the Code flow. Moreover, you should use it to allow long lived tokens.

Resources