We need the international software development community to have its own standards body outside of massive corporations and creaking old institutions with outsized influence. Standards should represent the majority of people writing and using the code.
That said, after doing a decent amount of implementing OAuth2/OpenID Connect, the core profiles are actually pretty reasonable and about what you would want to do if you were starting from scratch. The trick is making sense of all the optional stuff. There have been some efforts[0] to improve that.
The part I've never been able to figure out is why does OAuth2 use tokens at all, rather than generating a key pair and sending the public key with the initial auth request, then signing subsequent requests?
[0]: https://fusionauth.io/articles/oauth/differences-between-oau...
It’s such an obvious trap but it’s convenient and convenience is the only thing anyone cares about.
I’m gonna say I told you so in a few years. Nobody will care.
Identity is next. I think they'll start tying your Google, Apple, etc. account back to your real world ID. It'll be opt-in and they'll give some kind of sucker's reward for it like reduced captchas. It'll be sold to the public with the insinuation the "good guys" use verified IDs and the "bad guys" don't.
> I’m gonna say I told you so in a few years. Nobody will care.
Yep. Auth, identity, etc. are going to get sucked up by big tech and even after it happens we'll have people on HN telling us how awesome it is that we don't have any control over our digital lives because Google, Apple, etc. are "protecting" us. Case in point, the iOS app store.
Passwordless tied back to biometrics is their endgame IMO.
I recently stumbled upon this documentary[1] again, and it took me a while to realize I had seen it already a decade ago.
In 2023, the whole video serves as an "I told you so", and you're right, nobody cares.
[1] Panopticon (2012): https://www.youtube.com/watch?v=FUyB0Tsj6jE
But logging in with a URL was unfamiliar to users and it was easier to click the Google button.
It is so sad that this vision got so distorted by corporate interests into delegating to MS/FB/Google/Apple.
Well really, the proper body to issue (digital) identity is the government, which already issues driver's licenses, passports, etc. Google and Microsoft aren't the best bodies to issue identity, they're just the ones that are picking up the ball when the public body best positioned to do so is inactive.
OIDC doesn't increase lock in.
Before, I had to (for example) generate AWS credentials, download them, and store them in GitHub Actions.
But now, I can have GitHub Actions be directly authorized to access resources in AWS.
The only "lock in" is that these two services support an open protocol that would be minorly annoying to give up.
I am a member of the IET, but it's not strong on CS/SE. Some might be of the BCS (aka Chartered Institute for IT, which says it all IMO) or ACM. The latter is probably the most relevant we have, but it's more publication focussed than professional development/regulation/whistleblowing support/standards providing etc. of traditional bodies.
Everything related to AuthZ ends up being so specific to every other decision you make about your infra, and companies that offer solutions tend to charge an arm and a leg so it's not easy to experiment (let's not even talk about vendor lock-in risks).
I've found Cognito + CASL to be an... acceptable middle ground, as Cognito specifically "standardizes" the various OIDC/SAML/OAuth2 integrations such that I can rely on a certain structure within the JWT that apparently (based on this article) isn't consistent! And CASL I at least know how to insert into our infra, though I could see how it might not be the latest-and-greatest...
I just wish I had the time to dive into the theory more. It seems interesting, but it's such a "boring" and "solved" thing that spending time on it doesn't really move the needle when it comes to stuff like customer acquisition.
As for authz choices, you're correct that it's almost always entirely dependent on the application, and subject to frequent change as applications evolve, and as e.g. user and group structure evolves as well. The "managers" group of today might turn into "directors" and "VPs" as the company grows, and "pictures" might soon incorporate "albums" as an optional grouping factor with its own permissions.
In general, I would not really call authentication/authorization boring. There are components of it that are solved, but the reality of today is that people want a "share" link that they can paste in Slack and anybody can use it within seconds, and that kind of speed needs to be accounted for in authz, which is a significant engineering challenge.
Papers like Zanzibar [1] are super interesting to read too. And at least to me, not boring at all.
OAuth2 and OpenID has many standards documents. A 'standard' OAuth2 server can be written in 30 minutes if you only care about 1 grant type and none of the extra features and 1 flavor.
But it can also take 6 months if you do want support for all the features such as introspection, revokating, multiple grant types, ID Tokens, etc.
I wrote a bit about this issue here:
https://evertpot.com/oauth2-usability/
Note that this post is only about OAuth2, adding OpenID to the mix blows this problem up further.
The key point is that OAuth2 and OpenID provide a framework for building authentication and identity systems, with a matrix of possible implementation details that often have to be communicated out-of-band. It's still useful as a foundation, but picking an OAuth2 implementation is not as simple as just finding one that is OAuth2 compliant, you might have to dig deep and find out what parts you need and if your server implements them.
I love Auth! It's always the key that unlocks everything else. Chances are that 50% of the "blocked" problems in your company can be solved if you know how their Auth works.
Plus, everyone thinks it's not worth their time to learn so you can be a superhero with just a few weeks of work.
By "boring", I see that as a good thing; you want auth to be boring, is my point. Intellectually stimulating it is in any event (I enjoy learning systems), but I want the process to be me learning how it's done (the "boring"), not having to come up with novel solutions given my problem set (the "exciting").
Well, don't forget it's also a security thing so no matter what DON'T IMPLEMENT IT YOURSELF YOU'LL GET IT WRONG so you sort of _have_ to mostly ignore the spec and start looking for a (probably commercial) implementation.
What I've experienced however, is that this isn't as easy as I expected. The "middle ground" here is between "inventing form whole cloth a bespoke library to solve AuthZ" and "do absolutely nothing whatsoever new". Using CASL in my infra's middleware to solve AuthN seems to be working for me. I can write the rules in a way CASL understands, and I was able to quickly implement the middleware without having to do anything crazy.
As for "JWT structure being inconsistent" I mean to say that often I'm asked to "connect" many different providers, e.g. Google social sign-in, Okta, Auth0, etc., all of whom have their own way of structuring their JWT payloads (beyond the standard that is), and using Cognito as an intermediary has been helpful to avoid all of that, as again, I'm trying to do as little as possible myself.
I write SPAs. I use Keycloak OIDC as the authentication layer. I have the SPA set up as a client using the 'Standard Flow' with no Client Authentication[0]. I've carefully set my valid redirect URIs. I use the official Keycloak JS client and the standard JWT authentication implementation in my API server.
To this day I still have no idea if I'm doing everything correctly. I guess I'll have to eventually hire some expensive security consultant to go over everything, but every step of this setup is filled with hidden gotchas:
* There's multiple overlapping standards, each with a dozen different variants. The Keycloak OIDC config refers to OAuth2 over a dozen times.
* There's thousands of blogs and articles, each 1000s of words long and each recommending different things. I have yet to find a concrete guideline for what a 'sane default' set of choices are.
* Am I vulnerable to the issue described in the article? I guess I must be, given I don't see the server-side JWT validator doing anything special beyond validating the signature, so there's no validation of whether the token was generated for my app.[1][2]
* What are best practices for "client scopes"? I notice that the more I add the larger the JWT, but are there any gotchas to watch out for?
I think much of this boils down to there needing to be a published set of recommended defaults for common use cases, alongside some cleanup around deprecated/not-recommended config options.
[0] Given client secrets can be trivially extracted.
[1] Though I guess the fact I'm only using my own auth server and there's only one client means this isn't a problem.
[2] Isn't this how SSO works? One set of tokens to grant access to a bunch of different services?
First, you know which app the access token was issued for, it's the "aud" in the JWT.
Second, you should at least use the "state" parameter on authorization requests so that when you receive the access token via a redirect, you can guaranteee that the user was logging in intentionally and is now completing the flow (rather than coming from an attacker controlled website).
Even better is to use PKCE! It should be common knowledge by now that you must use PKCE[1] if you really want to completely prevent CSRF attacks. OIDC helps with that because it practically makes this a requirement, but you don't need OIDC just for that.
Finally, OIDC is not meant to increase OAuth security as this post tries to imply! It's just a layer on top of OAuth to establish an authentication procedure (OAuth intentionally leaves authentication out of scope as it's focused on authorization protocols). IT does end up improving certain things, but those things can be improved using simple OAuth extensions (like PKCE mentioned), only use OIDC if you actually need user information besides what's in the Access Token.
[1] https://datatracker.ietf.org/doc/html/draft-ietf-oauth-secur...
I work in application security and still have trouble understanding all the behaviours of oauth and oidc, even after reading the specs multiple times.
If I can’t understand it fully, how are you going to expect some developer who has no security or crypto background implement it correctly when nobody is there to validate the implementation?
I feel like the oauth/oidc are insecure not because of the core logic, but because the design and terminology aren’t easily understood - that complexity IS a vulnerability.
Along comes this comment's parent, essentially going "this is wrong in many ways, it's so easy if you just...". Very reminiscent of https://news.ycombinator.com/item?id=8863 .
Authentication and authorization need to be simple (enough) and, most importantly, offer a set of sane defaults. It mustn't require years worth of expertise. It is bound to be misused.
To put it simply, OIDC = OAuth2 + id_token (a standard way for the provider to let your client knows who the user is)
> There's thousands of blogs and articles, each 1000s of words long and each recommending different things. I have yet to find a concrete guideline for what a 'sane default' set of choices are.
There's only one sane default for client-side application: Authorization Code with PKCE
> Am I vulnerable to the issue described in the article? I guess I must be, given I don't see the server-side JWT validator doing anything special beyond validating the signature, so there's no validation of whether the token was generated for my app.[1][2]
The id_token provide by OIDC has the standard field `aud`, which should contain you `client_id`. Match them together and you can check whether the tokens was issued for your app.
> What are best practices for "client scopes"? I notice that the more I add the larger the JWT, but are there any gotchas to watch out for?
Best practice for "client scopes" is as small as possible, the only required scope for OIDC is `openid`, which allows you to fetch the `id_token`. Any other scope like `email`, `profile`, etc... is optional, and provider-specific so should be look up from the provider documents.
That’s why there’s a “state” param that is passed between the source and the identity provider. It validates that the request indeed came from your system. Combined with prop CSRF protection you can ensure the user willfully logged into the system and the response from the IdP was intended for your system.
> Some people believe that using the state parameter in OAuth protects against token substitution. The only binding a browser cookie to state protects against is Cross Site Scripting.
Note that I am not arguing about this point as I don't understand nearly enough about OAuth/OIDC, just pointing out this has been adressed in the article.
I believe what you are actually wanting to discuss is the aud claim, or rather the audience claim.
One of them doesn't tell you how long tokens are valid for, and they are blaming it on their IDP (Salesforce).
One of them just simply doesn't have the possibility for custom schemes (com.example.org://oauth-redirect) and blames their IDP (SAP Gigya).
One of them has their own IDP, even has a debug screen in the html site, never causes any issues. Still requires some locale modification because of Norway's language.
And then they configure it so that users are force-logged out after 1 or 7 days. When users expect to be kept logged in (just like at big apps like Google, Facebook, Instagram, etc). Agggh!
[0]: https://www.facebook.com/.well-known/openid-configuration
OpenID is a specific layer on top of OAuth2. It standardised claims for authentication, scopes it down to the 2 credentials flows it can care about, and that's core in a nutshell. It's complicated, but so is HTTP, which most people don't use directly anyway (and the same should be applied for OpenID, just use a blessed implementation, the OpenID foundation maintains a list of certified libraries you can rely on).
See, a large part of the problem comes from the fact that there are really two things you want to encapsulate under the word "auth," (authentication and authorization), but OAuth2 only evan attempts one of them, and pretty badly at that.
That isn't to say OpenIdConnect is perfect or anything, but at least when you're doing the dance of encrypting a signed token (which, BTW, is the correct order, because in order to modify the payload and still have it validate, an attacker would need to break the encryption first in order to modify the payload into something malicious), having proper TTLs, and then, on top of that, having a way for the client/user side to signal the server/API resource side that "hey, I'm done with this token a little early, so just ignore it forever now, mmmkay," you reduce the amount of damage an attacker/malicious observer can do by intercepting one valid token.
Oh, but that's only if both the client/user side and the server/API resource side each implement their half of the protocol 100% correctly... which is, of course, nontrivial and full of landmines for you to step on. [0]
Now, I stepped in this particular pile of bullshit because the company I was working for at the time was in health tech, and we had a client who thought they wanted to exchange EPHI (electronic personal health information -- you know, the kind of data that HIPAA makes radioactive with its massive financial penalties) with our servers to do some other random crap I didn't really care about on their side. But, you can end up in the exact same place by replacing "exchanging EPHI" with "accessing any confidential or sensitive data," so don't think you're safe from all this just because you're not in the healthcare space.
Fortunately, in the end, our client realized that they did not, in fact, have the technical expertise and know-how to be able to deal with the security implications of what they were saying they wanted to do. So, our product and sales people talked them down to something that they could handle, and, which, fortunately, did none of give me headaches, cause me to lose sleep, or make me want to strangle people. And, that meant I could go back to paying attention to the things that actually mattered at the time, like making sure our RDS instance wasn't going to keel over, hiring a couple new senior SWEs, and occasionally even leading the team.
I see that turned into a bit more of a rant than I had expected, so I'm just going to cut myself off here. I hope anyone reading this is able to learn from my experience and maybe not drive themselves crazy in the process.
Thanks for coming to my TED talk.
---
[0]: For instance: https://auth0.com/blog/critical-vulnerabilities-in-json-web-...