|
|
|
|
|
by necovek
506 days ago
|
|
Formally proving that you can't be authenticated to a service without actually holding some type of authentication token is trivial. Whatever you replace it with (a short-lived access token, a session cookie, a JWT, or whatever else) becomes the authentication token — if you add other properties (like short expiry), you are mostly trading convenience for security (eg. people will get logged out, or you'll need to implement refresh token dance in your app). So it's really confusing to me how can someone pretend that there is something you can do on the unsafe client side, because you really can't (sure, there are obvious things you shouldn't do, like keep a plain text password in a cookie or localStorage, but an auth token is pretty much the same thing other than expiry). |
|
His mission statement up front is just... wrong (and as an aside, I like KeyCloak, there's nothing wrong with it, I auth several services I host with it). But to be exceptionally clear - the following is bullshit:
> Our goal? Design an application that never stores sensitive data in the browser.
Why bullshit? He then goes ahead and stores a cookie in the browser which his BFF happily upgrades to an access_token and makes requests with.
So his cookie is just his new token. Full fucking stop. Still sitting right there in the browser.
Are there reasons to prefer a cookie over doing something like keeping an access_token? Yes, although they're not as convincing as one might hope. They're certainly not as convincing as this article makes them out to be.
Generally speaking - the argument is that an HTTP-only cookie can't be read by javascript, preventing vulnerability to XSS. There is truth here that ex-filtrating an HTTP cookie is harder, but it doesn't remove any XSS vulnerabilities. All it does is add a marginal level of complexity: Instead of taking your token and doing stuff later, they just script the interaction they would have performed and put it in the XSS payload up front. It all runs on your client, which happily sends that cookie along for the ride. Marginally more complicated, absolutely doable, still completely hacked.
---
IMO there are really only two reasons to prefer a BFF:
1. Your client has needs that don't mirror the structure of the api you're accessing. Your bff can consolidate and simplify the api that the client has to consume, while also ensuring that you can handle breaking upstream api changes without needing to redeploy clients (the later is not a huge deal for websites, but IS a big deal for items that need to pass store review on redeploy - like mobile apps or browser extensions, and also for things that are technically complex to deploy - like enterprise desktop software)
2. You can reduce the available footprint of the API beyond the default scopes of your access_token. This is the only real security win - period. If you build a client that never needs to touch billing endpoints in the API... don't ever expose them in the BFF. You can limit the blast radius of an attack to things the client should be doing, even if the token would have allowed other, more dangerous, things. This is usually a sign of poorly implemented token scopes, but if that's out of your control - this is a viable solution.
In a lot of cases - the extra complexity just isn't worth it. Prefer using tooling that makes XSS difficult (React is genuinely pretty solid by default here, but you need to be careful with libraries and still enforce that you're not allowing dangerous calls). Prefer using SameSite and CORS with an HTTP-only cookie by default from your auth provider if you control the whole stack and can configure uri allowlists (esp if you're only authing across subdomains).