Lets say you want to use google as an auth provider. You do this:
"Hey google who is this guy? I'm going to send them to google.com/oauth, send them back to example.com/oauth, and in the headers of the request include the word "Authorization: bearer" followed by a bunch of text"
Google says "Oh yeah I know that guy, here I'll send them back to where you said with a token"
Then later on you can take the token and say "Hey google, somebody gave me this token, who is it?"
That's pretty much it. You have to trust that google isn't lying to you, but that's kindof the point of oauth.
But that's never what the documentation says. It's always 10 pages long and the examples are like "here's a fully functioning python web server using flask and function decorators, oh the actual auth flow, which is really like 3 lines of code, is hidden inside of a library".
To people who write documentation: PLEASE for the love of god show me how to talk to your API both using your library, but also using something like urllib2 or requests or something.
Ideally the documentation is the absolute most minimal way of making the service work, and then adds more and more usefulness on top of that. I'm not going to judge you for writing bad code in an example. The example could practically be pseudocode for all I care. I just want to see generally how your API is supposed to work.
edit: yes, auth0, I am looking at you.
Then you ask them to log you in by sending a request to an implementation-dependent webpage, with implementation-dependent parameters (which ones are required are--you guessed it--implementation-dependent), telling them to redirect you to your page when you're done. Well, actually, that assumes you're building a website. If you're a desktop application, you'll do something else. If you're on an embedded system that can't open up a webpage, there's another option. And there's yet more flows. Which ones are supported by the provider? You guessed it, it's all implementation-dependent. Oh, and maybe you need to refresh tokens to login the future. When? If? You guessed it, implementation-dependent!
It makes writing a generic OAuth client library hard because there's basically no commonality there. Really, it makes me long for Kerberos as a much saner SSO system than OAuth.
OAuth supports lots of different scenarios. Many people when they say “OAuth” they are only thinking of one or two of those scenarios, and ignoring all the others which aren’t relevant to them personally-but may be relevant to someone else
I worked on a system where we had a micro-service which had a token from OAuth server 1, and it needed to exchange it for a token from OAuth server 2, and we needed some policies to decide whether that token exchange was allowed or not. And that’s totally a use case the OAuth RFCs support (there is even an RFC specifically on token exchange), but a person wanting to add a “login with Google” button to their website isn’t interested in anything remotely like that.
> Which ones are supported by the provider? You guessed it, it's all implementation-dependent.
Security needs vary widely from system to system. So they defined a protocol which supports many different scenarios. But if your application only needs two of them, why implement the other N? OTOH, for someone who actually needs one of those other scenarios, having it standardised makes their life easier. You can’t expect the protocol to tell you which scenario you have, that’s inherently “implementation-dependent”, to the point that calling it that is getting tautologous
Not because the "figuring out who to OAuth with from DNS" part would be hard to design; but because there's no way to "autodiscover" all those implementation-dependent details of how you're supposed to talk to an OAuth IdP.
Compare/contrast: SAML. SAML binding a webapp to an arbitrary IdPs just by punching in the IdP's SAML config endpoint URL? Works perfectly.
+1, it really solves nearly all the authn and federation problems. You still find KDC installations in places with large *nix footprints. Sometimes it's AD, sometimes it's MIT with a cross-realm trust.
It's incredibly flexible and transparent to the user. It's easy for sysadmins, and various service owners to implement as it's basically drop a keytab in place, and set an environment variable for many daemons and libraries.
IMO, the only reason it fell out of favor with the web crowd is there wasn't a gaggle of centralized providers that let them stand up services without thinking about the infrastructure. It wasn't packaged up nicely.
Because it is, really.
OAuth (2.0) is really the backbone for OpenID.
It's fully specified. It's well implemented - you'd have to go out of your way to find an authorization server that doesn't do everything above, with the exception of dynamic client registration, because that's not intended for clients but rather for integration with developer portals and similar. Google Auth and Amazon Cognito don't support dynamic registration for third parties, eg, because if you're doing dynamic registration it'll be because you're operating your own AS - Okta, Auth0, and Keycloak all support it.
There's also plenty of good generic OAuth client libraries. Spring Security, the oauth2 crate for Rust, etc.
If the spec was smaller people would go all the way to be fully compliant since the marginal effort would be minimal.
For example, Google won't give you a long-lived access token. You need a refresh token, and then you use that to retrieve access tokens, and continue doing that as they expire.
Why? I have not a flipping idea. Please, HN enlighten me how refresh/access token dichotomy improves the API.
Refresh tokens are more like session tokens/cookies - those get checked every time. At Google scale, checking it probably expensive, so they are using refresh tokens.
These aren't for end-user or development experience, those are for AS performance.
If a short-lived token gets leaked the damage is limited to the TTL of the short-lived token.
If you were to pass around the long-lived token you would need to do forensics on the entire life of the token to figure out how/if the credential was used.
Just think very pragmatically about the probability to keep a short-lived token secret across all the places it's being transmitted vs. keeping the single API that exchanges the refresh token for a short-lived token super secure.
https://www.rfc-editor.org/rfc/rfc6749.html contains everything you might want to know about OAuth in great detail :)
So for me, mobile wasn't relevant, SPA wasn't relevant, and my use case, the third one was hard to find.
- https://www.rfc-editor.org/rfc/rfc6749.html: The OAuth 2.0 Authorization Framework
- https://www.rfc-editor.org/rfc/rfc6750.html: The OAuth 2.0 Authorization Framework: Bearer Token Usage
And to be honest, this is part of the problem. We use confusing (and sometimes conflicting) terminology to describe both authentication (identifying somebody) and authorization (making sure you have the right permissions to do something).
More information: https://stackoverflow.com/a/1087071/19020
“The possessor of the bearer token is authorised to re-request a refresh token code cookie.” is only a very slight exaggeration.
I also want to slap the Microsoft employees that use six different similar terms for three GUIDs that look identically random. E.g.: “Client ID (Principal ID)”.
It’s maddening.
I like what you’ve done here with your explanation - I can practically envision a couple (or three!) literal sock puppets giving me this perfectly adequate overview.
I've an Internet-Draft somewhere to fix this by making it possible to indicate on a 3xx that this is for authentication (so copy Authorization: from redirect responses to redirected requests) and to allow 401s to have Location: headers that make it more like a 3xx, and 3xxs have WWW-Authenticate:, so you can negotiate between legacy HTTP auth and redirect-based authentication.
I think the reason OAuth is so successful and prevalent is because it is so flexible. This let folks implement what they needed and not what they didn't.
Overspecifying things didn't help SAML, after all. There are still holes and unimplemented/incompatible options. Authentication and authorization, especially across systems and organizations, is hard.
Is there a simpler standard for third party delegated authorization?
Then your examples can be simple, rather than trying to be a complete explanation of everything.
Unfortunately, developers seem to think their contrived examples are a stand-in for actually documenting the methods. I deal with a lot of Javascript libraries like this and it drives me insane.
It was way easier than anything else I've done with OAuth (except log in as a user).
1. Read loads of docs, end up pretty confused
2. Find a library that seems to do what I want
3. Install this huge library full of opaque code doing...things
4. Have an impossible time troubleshooting issues
5. Get scared ("I'm almost certainly doing something wrong here") and give up
I find it hard to have much faith in security standards like this. I want them small, well defined and understandable and OAuth does not meet any of these criteria in my experience.
The one that I find easiest to understanding is still the one that I wrote about a decade ago when I first had to work with OAuth 2. All others I understanding by mapping what they said to concepts in mine, and that seems to work pretty well.
My document is available at https://metacpan.org/dist/LWP-Authen-OAuth2/view/lib/LWP/Aut.... Even though you're unlikely to ever use that library or language, you may find it worthwhile.
Perhaps it's a semi-consequence of Perl being perceived as old and crusty, and popular with old crusty people who are merely trying to get things done without fluff (at least speaking for myself).
Reminds me of Data::Manip, another favorite of mine.
Thanks for taking the time to write this (and implement all that nonsense).
> OAuth 2 makes it easy for large service providers to write many APIs that users can securely authorize third party consumers
If I'm trying to write a Mastodon client, I'm reading this line piece by piece:
> OAuth 2 makes it easy for large service providers
"service providers" OK, that must be the Mastodon service.
> ... to write many APIs that users
"users" That must be me
> ... can securely authorize third party consumers
"consumers" OK... that's also me?
The only thing I'd suggest is putting the terminology first, so readers can first correct their misconceptions from all the terrible literature around this.
(Only feedback I can think of is that it would be great to have a few diagrams... like from excalidraw or something. Am largely a visual learner.)
- Send user to example.com
- Eventually they're sent back to yoursite.com with a ?code=abc
- Call example.com/OAuth to exchange ?code=abc for access token and refresh token
- You're done (for now)
- When access token expires, call example.com/OAuth to exchange refresh token for a new access token and refresh token
The tricky part is that a bunch is implementation specific, so memorising the above only gets you half way to implementing with another provider.
But the application currently has it's own authorization policy in a flat file which organizes users into groups and gives groups permission to take certain actions, a simple RBAC. I'd like to refactor this so that the authorization is delegated to the OAuth server.
Ideally I want to be able to ask a keycloak/okta server "now that user X is authenticated, are they part of the group Y?".
Since this isn't a common use case and everything is so abstract it's been very difficult to find an obvious path forward.
Adding the oauth calls into your app that already has a web server, job processing, and a db is way easier than integrating what ever weird stuff some random library does.
Overall I found it fairly OK, it's a bit of a learning curve when you're just used to basic user/pass, but it's fine.
However the main issue is that when it's not working it's very opaque. This is even worse when trying to _use_ the tokens.
I spent many hours trying to figure out why my Client Credentials tokens wouldn't work for logging on to Office365's IMAP server, only to spend half an hour searching and finding some Microsoft community forum post saying it wasn't implemented yet... they only supported Authorization Code flow. This has been fixed they say, I'll know later today cause that just came up as a priority ticket...
All you get back is some "nope", with no way to figure out why.
[1]: https://learn.microsoft.com/en-us/azure/active-directory/dev...
[2]: https://learn.microsoft.com/en-us/azure/active-directory/dev...
[3]: https://learn.microsoft.com/en-us/azure/active-directory/dev...
Don't ask me why, I thought the whole point of OAuth was that example.com was allowed to access identity.com. Instead, example.com opens a hidden identity.com iframe and does what do I know?
At my old job, users could specify their own IdentityProvider for their instance, which added a whole layer of complexity.
Now we have found out that a different team has implemented their side of OAuth completely wrong: Their device flow ("Open in app and enter 56474") doesn't poll automatically. Instead, user have to click "try now" manually. The whole auth is lost when the device restarts.
I'm not surprised Microsoft lost control of Bing because they implemented OAuth wrong for one of the services displayed there.
I abstracted it away behind a "token provider" interface, so I can just instantiate the right one for the job.
There's some incantations to get the request right, but I found most documentation decent so just follow that.
One service required I implemented RFC 8693 token exchange, which turned out to be trivial since I could represent it as one "token provider" instance wrapping another.
Failures can still be opaque though, especially when using the tokens.
I spent a lot of time making sure I did everything as by the book as possible and , in the end, I had a good experience and felt confident in my implementation, and like I understood all the moving parts. I even got help in a SO thread from an auth0 employee.
Auth0 could have been anything, here... On the same project, I kind of did the same thing with vite/react/tailwind client and fast api backend where I touched every piece of it, made every decision, and made sure I was really confident. This was in my own little vacuum where a big part of the app was just creating my perfect little sandbox. Stuff gets way more complicated when you have to hustle to get stuff over the line or you're trying to cram so new auth implementation in to an 8 yr old app that's been walked around on by dozens of engineers slamming out slop to close a ticket.
(Note: I know auth0 is a little more on-rails than implementing auth0 without it. They tend to have pretty good guides if you're using current hotness like react or fastapi)
I get the problem though, many of the libraries are not great or simply difficult to use
In short it works when you can see it as a guideline instead of a standard.
In practice, isn’t OAuth predominantly used to verify proof of email ownership? If so, why not just use magic links as sign up & sign in?
1. Sign in/up: Enter email (can be pre-filled by browser/app)
2. Click the email verification link or enter code if on different device.
3. Profit. No manual typing necessary, only clicks.
This is trivial to implement, and can be extended in the future with a simple standard for browsers/apps to automatically verify in the background (to avoid the tab-switching inconvenience in step 2). On iOS they auto-populate SMS codes in a similar fashion.
2FA can be out of scope, (many times not needed because email providers already have it). But if needed, it can be added as a second step after the email proof.
Please tell me what I’m missing. This seems, to me, like an excellent trade off between implementation simplicity, extensibility, user convenience and security.
(On a side note, I'm constantly annoyed/frustrated that after about 20 years of development, authentication codes/apps and smartcode verification are starting to be almost as secure and usable as the HTTPS client certificate support that was built into every browser as far back as the '90s)
For example - login system that merged LDAP/Kerberos/client cert/long-lived application token authentication into single system, that also linked said authentication system into all applications in the network, including making it possible to login to AWS Console using Kerberos (that one was twisty to get running, not because of OAuth2 but because of how it is handled by AWS IAM).
Also, I have used it to link in MFA systems of different kinds (it was definitely easier side than industry standard of using Radius)
In addition, this proposed system requires that every app has ability to send emails, which honestly is less simple than it sounds, especially today when sending to arbitrary public emails.
I have rough understanding of oauth but never had to dive in.
1) skimming for limited context
2) copying and pasting random code
3) trying it with print statements
4) getting stuck
5) repeating steps 1-3 until it works
None. They are entirely duplicative features.
But ... reason, reason, reason ... they both exist, and are going to exist, forever.
EDIT: I should say, PKCE is a functional superset of redirect URI allowlist.
It's typically not a list. You typically will have one redirect uri (at least, one per AS), because thats the communication endpoint defined by your client. There are other parameters like state to remember what you wanted to do after you had an access token.
PKCE exists to bind the front-channel authorization request and back-channel token request together as being by the same client. There is otherwise no evidence that the two parts are by the same software instance, which causes other security issues.
I am referring to the redirect allowlist registered out-of-band by the client: https://datatracker.ietf.org/doc/html/rfc6749#section-2
There is a good reason why we mandate both redirect URI allowlisting AND PKCE in the OAuth Security BCP RFC draft. One learning from our discovery of mix-up attacks with "code injection" was that client authentication is not sufficient to prevent the misuse of authorization codes.
Could you please expand on that thought, I'm genuinely curious if you actually might be right or whether this assumption of yours is how we get security holes.
With PKCE, the other app can still intercept the token, but the token is incomplete and useless.
PKCE also gives you nice assurances that the device finishing the flow is the same as the device that started it. Without PKCE, the classic client credentials flow risks login CSRF - https://support.detectify.com/support/solutions/articles/480... - which may or may not be an attack vector you care about.
Correct. Fortunately, in my personal experience many services offer exactly this (JIRA, Hubspot, Slack).
OAuth is only relevant where the resource owner and client are different parties. I.e. it's for third party clients, not second party clients.
If you are developing an API please have mercy: provide something other than OAuth. For me, avoid OAuth unless there is 3 distinct parties.
When the environment involves delegating authentication across service providers, dealing with browsers and native clients, mobile apps, etc, there will not be a simple solution.
This is made even more challenging by constantly evolving application and edge deployment architectures, each bringing with it a new element of complexity.
OAuth sucks, and I’m sure it could be replaced with something better, but that replacement will also suck and bear a passing resemblance to OAuth, because the underlying problem is a messy one that isn’t going away soon.
It's by far not THE worst, you're spouting total nonsense. What's THE worst is lack of attention, and one needs quite literally 10 minutes to read the RFC and understand it's fairly simple protocol with minimal number of parameters.
I'm sorry you had a hard time with OAuth, but have you ever thought the problem is in you and not the protocol? Reason I'm asking is because you declare it sucks but you are not providing any kind of alternative of how it would not suck.
rfc 6749 is 4259 words according to wc -l. You mean that it takes 10 minutes to carelessly skim it.
Never mind that there are several other OAuth RFCs.
You can implement client credential mode - this means storing a credential and using it to acquire a token from OAuth2/OIDC provider, then using that token as Bearer Token in your API calls.
EDIT: I can add that I have implemented client credential mode in what was effectively raw PowerShell and similarly it can be done with curl from any shell script, even pretty dumb ones. Just do a single POST containing the necessary JSON structure to your OAuth2/OIDC provider, parse returned JSON to grab bearer token value, use said token value in header
curl -H "Authorization: Bearer ${token}"
You can also implement any kind of authentication in your provider (or configure a 3rd party one) and make it accept it - then ensure that this authentication model is supported by your headless program when it receives a redirect to login page. For example I have implemented Kerberos 5 login this way - CLI program would connect to OIDC provider (keycloak), get offered HTTP Negotiate GSSAPI auth, perform it using users kerberos identity, get token, use that token to access AWS STS to acquire AWS token. Completely transparent to end user/service.But the client credential flow assumes the client _is_ a resource owner and already has authorizations to do its business. Thats what you would typically use for pure system-to-system use cases, and basically amounts to "hit this endpoint periodically to get the current API key"
You're looking for client credentials.
[1]: https://www.authelia.com/integration/trusted-header-sso/intr...
For example: a CI service wants to write to a Slack channel.
The CI service produces a request and directs me, the channel owner, to Slack where I confirm the request, and then the CI service obtains the scoped access token.
How is this replaced by anything to do with an "upstream reverse proxy"?
EDIT: I think you are thinking of OAuth as SSO. It can be used for that, but that's not it's "true" purpose like it is for SAML.
---
> The fact that I have to hand over my administrator password as they pass it over LDAP to authenticate me
Yes, that is insane and why LDAP is generally no longer used for web applications.
That's not even getting into the fact that the "SSO technologies" that you listed have vastly different mental models of what inputs and "claims" they support. Maybe you're hinting at https://xkcd.com/927/ but for better or worse I don't believe there is a magic wand authn/authz standard like you want
So the answer is - OAuth doesn't solve the phishing issues around authentication any more than any other sort of non-curated hyperlink on the web.
WebAuthn, mutual TLS and Kerberos are the systems where that authentication is bound to a DNS domain or communications channel. Password managers also can provide this, although there are security considerations there such as competing web extensions, and it is a mechanism that the server cannot vet for risk analysis.
Such phishing-resistant mechanisms raise the bar for a successful attack from someone sending out a creative email to something a lot closer to coordinated/state-sponsored attacks on internet infrastructure.
The industry has played fast and loose with the spec because too many people implementing OAuth support in their app do not understand OAuth and/or insist on bleeding application or architecture-specific behavior into their authentication flow.
The end result is what you describe: a proliferation of approaches that roughly follow the spec. But this should not be mistaken for the spec being loose IMO. Rather that the state of auth is abysmally non-standard and homegrown.
I owned the authentication stack for a large enterprise platform company, and worked directly with the biggest players on ensuring compatibility between our platform and their auth flows, and the typical deviations from spec are almost always unnecessary and duplicate something that was already possible.
To be fair, Auth Code flow gets pretty funky with browser redirects + backend calls and can be hard to grok at first.
The other major issue is that once some custom auth thing exists in production, it's never going away if there are enterprise customers relying on the behavior. I suspect that a lot of customized implementations were never meant to be long term solutions.
Why should tens of thousands of developers have to discover the particular quirks of an implementation instead of doing it once and re-using the results?
I get charged per connection, so I just pass that cost onto my customers. As a solo developer, I'd have a hard time supporting so many IDPs with a unified API without this.
They did recently hike up the cost per connection, but they're giving a one-year extension at the old rates, which seems fair.
The issue itself also sounds easy enough to implement that you might get suckered into rolling your own (you only need to do a redirect and a request every n-minutes) ... But it's surprisingly hard as there are a lot of edge cases with long running timers and potentially multiple browser tabs/windows etc.
With that, and the redirect URL (and therefore trusting DNS), and the other browser security model stuff…. You’re in fairly good shape.
There’s newer standards coming like DPoP - but it’s probably not worth it yet.
This explainer is pretty good. Sorry for the archive link, the original seems to be down
OAuth is one of that pieces of infrastructure that power lots of things without people even noticing them, but don’t bode well with armchair engineers.
I made this because I was tired of asking the same question.
There are a bunch of services out there trying to address the same thing, but unfortunately they get wildly expensive and they own/control your user data.
Professionally, I've been a consultant and freelance developer for 10+ years. Time and time again I'd see teams start with Auth0/etc, only to eventually:
1. duplicate user data into their own DB/Cache to avoid the latency of asking Auth0 for user data
2. remove Auth0 entirely because having active users !== having paying users... so Auth0's monthly bill of $3000 to $10000+ couldn't be justified
3. #1 then eventually #2
btn.social is just as simple to set up, but has predictable & transparent pricing with volume discounts the more you use it. At its most expensive, it's 100 logins per penny ($0.01), which is to say that "MAUs" are a thing of the past.
As quick pricing comparison:
- Auth0's (public) pricing calculator [1] shows 10k MAUs for $228/mo. That just means 10k users logged in 1+ time(s) that month. In btn.social terms, that's 10k, 20k, or 30k logins depending on if each of those users logged in 1x, 2x, or 3x (etc). For $5, you get 50k logins with btn.social.... and for $169 you get 2.5M logins... [2]
- Supabase charges $25/mo, which includes a lot more than just OAuth(!) but if you look at Auth alone, that $25 includes 100k MAUs and is an additional $0.00325 per MAU thereafter [3]. Assuming 1x login per MAU, that's $2950/mo for 1M users. With btn's "Business" tier, you get 1M logins for $79/mo, but of course there's still the $169 for 2.5M if you don't like the "1x login per MAU" assumption.
Another key difference is that btn.social saves nothing about your users.
It's your app so you get to keep your data. You'll never need to have to ask btn.social for Alex's profile because we won't have it :D This means we're privacy-first & we don't add/pose a risk for GDPR concerns.
btn.social was just launched last week [4], so some additional guides & examples are still underway, but there are already 10+ OAuth providers [5] to choose from & a free/"Hobby" tier so anyone can start playing around in just a few minutes.
[1]: https://auth0.com/pricing
[2]: https://btn.social/#pricing
[3]: https://supabase.com/pricing#compare-plans
[4]: https://twitter.com/lukeed05/status/1648751062340501505
One question I have around OAuth in general is whether it only applies for SPAs or if I could also use it for more traditional multi-page apps? I guess I could do something similar to what you're doing in your guide [0] and do a POST from the onlogin callback, but how does my backend know that the payload is valid?
[0] https://docs.btn.social/guides/#link-a-payload-with-a-db-rec...
Your `onlogin` callback will only ever be invoked by the SDK on successful login. So the data coming thru there is always the result of the OAuth flow itself. For MPAs, you can create your own document cookie and/or modify local/sessionStorage, and then every new page load will pull/load from those storage systems. SPAs can & should do the same – they just have the added benefit of keeping in-memory state alive.
As for POSTing to your backend, the same XSRF/CSRF/CORS rules & mechanisms apply as with any other client->server transaction. You can rely on CORS for limiting who can talk to your API, you can pass along a unique token for CSRF prevention, and/or come up with your own Authorization header format.
Soon I'll be adding a `redirect_uri` config option for all btn.social apps. Much like the normal `redirect_uri` in OAuth, this will be a target URL that btn.social redirects users to post-login. This will enable server-side redirects, which means that your API just has to verify the "login.btn.social" referer.
Agreed that the biggest reason is that OAuth is a framework and not a protocol. That means different companies can do it ever so slightly differently, and as a dev, you need to understand the differences and normalize it for your use case.
At Stytch we've run into the same issues, normalization problems, security implications, flaky IdPs; a hard problem, but one you _have_ to get right!
Indeed, a lot of people do not realize the difference. Frameworks do not provide interoperability, and at most we can push to try to get people to solve problems the same way.
Profiles (such as OpenID Connect or FAPI) constrain frameworks allowing implementations to be interoperable.
OAuth is somewhat like the multitude of different dialects in some places like the United Kingdom.
The original article was talking about the problems due to trying to support all those different OAuth dialects. I'd argue most developers will never know that degree of pain, because they are only trying to solve problems within their particular application space.
Make it so that the token is only valid for 30 days or something and then it requires moving to OAuth. But for prototyping stuff with curl and bash scripts, it's a giant pain.
That said, my first thoughts when looking at the advertised service is that I would be adding a huge external dependency with all the associated problems. That's a big cost, and I don't mean just in monetary value. I now have to rely on the network, as well as an external company with a business model that might or might not work out for them. Said company is likely to get acquired or shut down, none of these outcomes are good for me. Also, external APIs are a pain to maintain (I found that on average an API gets completely rewritten once every 2-5 years, which if you have 5 external APIs means that you will be rewriting one every year).
Also, OAuth has an unpleasantly large interaction surface with the rest of the software.
As a counterpoint, if I could buy a good local OAuth2 library for Clojure (subscription is fine), I probably would.
For me who runs a simple website (no 3rd party login), I learned that OAuth2 is just not a good choice. JWE/JWT and samesite=strict plus HttpOnly cookies are reasonably simple, yet secure enough.
With just a single helmfile, I can deploy the entire application stack on my local machine (authN, authZ, smtp server,app db, application). Gives me ease that I don't have to rely on a third party vendor just for testing simple app flows. Transitioning to production is a simple swap of DSNs (database connection strings, real smtp servers, ...). Also, no more burning money when running simple tests or performing load tests with dummy users when using an external/managed IdP.
Still need to experiment with how upgrading will work and migration of user data. But otherwise I am a happy user/developer.
We have the same issue with the UK Wiring Regulations, so they produced an "On Site Guide", which covers only the main parts of the main regulations and is about 10th the size. The same could be true of the OAuth spec.
To be fair, OpenId Connect partially addressed both issues by taking a subset of the spec (when used for authentication) and then nailed down what the properties should be and what encryption mechanisms are required to be implemented.
Names are funny because many implementations of standards make the mistake of presuming there's such a thing as a "first name" and a "last name" that make up a name. Or that the "last name" is the part you pass down to your family, and so on. If I see "first name" in any spec, I assume the spec is written solely for a small subsection of the population by someone who didn't put all that much thought into the spec. Not every service needs an email address, there's no telling what a valid username may look like, address specifications are basically plaintext strings even though many services pretend there's structure to them, and so on. Hell, most APIs authenticating against OAuth don't even need a username or user ID to function, all they need to provide is an access token.
Most fields have no business being standardised because they cannot be. OAuth is not a "log in with Facebook" standard, just like IPv4 isn't an "access Wikipedia" standard. If you host something that people authenticate through OAuth yet, you inevitably need to provide some kind of custom service properties.
That's it. That's the end of the spec.
If you want to do anything with those tokens, you need to implement against other APIs the provider makes available. Unless all of those APIs are also standardized, it means implementing a bunch of stuff for each integration. And now things are no longer easy.
And if you read the article, you would have something of substance to contribute on that topic, whether it is easy or hard or otherwise.
Big companies had to roll out their own authentication layer on top. When OIDC came into play, it was already too late.
2. because the standard was messed up (instead of specificing a protocol with _at most_ one clearly specified flow per use-case (you can use it for more then SSO/Cross App Auth) they specified something more like a framework to build your own standard, but still pretended it's a single protocol, but if you can't use the standard to "blindly" build a client which works without knowing anything about the vendor then it's not a protocol, at least not a complete one)
3. because the standard covers too much potential use cases
4. because vendors haven't yet converged their implementations enough and might never do so (time for OAuth 3 which just specified on specific OAuth2 flow implementation??)
Given that OAuth2 was started with clearly very different goals in mind and the main profiteers of the current situation are a few big companies like Google, Facebook and Microsoft I have heard people stating that OAuth2 being messed up was intentionally. _I don't believe so_, it more looks like a typical case of accidentally over engineering by trying to doing so much.
I still don't like the situation as OAuth2 was too some degree a coffin nail to the idea of generic SSO (i.e. you as a customer can freely choose a SSO provider when signing one) and that sucks really hard and if we had generic SSO passwords would be _way_ less of an issue today (imagine _any_ email provider could _easily_ also provide a SSO service for any side you can have an account with).
Here lies another pain point of integrating OAuth flows: In my experience those client libraries are a lot better in following the RFCs than the authorization server implementations.
It can cause a great deal of pain using such client library with a botched authorization server. If you take a look at the issue trackers of some client libraries you see a lot of "Please make this library work with auth provider XYZ" reports to which the maintainers (rightfully but painfully) respond: "Won't fix! We're following the RFCs here, we can't deal with every crooked authorization server implementation. Get it fixed at the other side."
And then you have to take the decision if you want to patch the client library youself to make it work (with the risk that this patches break on updates of the client library) or if you roll your own client for that particular auth provider. This decision gets even more complex if you have to support multiple authorization servers. If it's only one auth provider the third option would be using a vendor specific client library, which may be as botched as the authorization server, but at least they can talk with each other.
"We support standard oauth butttt..."
https://gist.github.com/nckroy/dd2d4dfc86f7d13045ad715377b6a...
Since the program written in Haskell I also provided precompiled binaries to spare my potential users, most of them not Haskellers, from the complications of compiling it. The program have become moderately popular. However, little I knew how big can of worms I opened by releasing it to the public.
As many others pointed out, the two main reasons for the difficulties with OAuth are 1) the OAuth "standard" is terrible complex 2) the service providers' API documentation is an impenetrable obscure mess, always one step behind of the current working system. I have the feeling that the second one is not just negligence but might also be an intentional hidden lock-in mechanism by forcing the use of the vendors' ever changing API libraries.
[1] https://sr.ht/~petrus/mailctl/ also mirrored at https://github.com/pdobsan/mailctl
I found that all the off-the-shelf solutions were either easy but expensive or cheap/free but difficult. I failed to find that mythical cheap or free and also easy and fabulous. Eventually we settled on self-hosted KeyCloak as the best bang for the buck. It took a bit of effort to get there, but we are happy with the results.
We signed up before they had an admin dashboard and did everything over cli. It was easy then and even easier now. We have also contributed a couple of providers when they didn't have apis we wanted to use setup yet (Stripe, Zapier NLA). They have an open slack channel and we were able to get them shipped immediately.
Add to that the various version of OAuth/OIDC/FAPI and no clear migration path laid out to upgrade and it's a basic nightmare.
The Australia CDR (Consumer Data Right) notionally supports FAPI but they have their own interpretation of what is right so you simply can't use an off-the-shelf library to do anything.
The only way to preserve any kind of inter-operability is to wait for some other sucker to release their interpretation of this standard and everybody else in the eco-system has to test against that and eventually call it good.
Add to that - I just can't see why it has to be that complicated. Sometimes you can request signed+encrypted tokens, sometimes not, you can query the provider to ask them what they support but there are holes and gray area defaults for algorithms and encryption schemes and the whole thing needs to be set fire to and abandoned.
For example, most APIs don't implement PKCE in order to prevent injection attacks against the authorization code grant type.
Just keeping up with security practices is a full time job for teams.
https://www.ory.sh/oauth2-openid-connect-do-you-need-use-cas...
I’m not a backend guy, for a hobby php site I’m trying to get Oauth2 with gmail free smtp, and the token refresh part to run on its own and even with packages like Phpmailer there’s no simple working copy/paste examples, just loads and loads of bits and pieces and outdated examples and small print about Google changed this or that… I mean wtf is the point of having a package that is supposed to abstract OAuth if you still end up having to dig for hours and having to figure OAuth2’s flow in detail?
I’m so disgusted I figured maybe I’ll do the password with 2fa on that email acct and be done with it even though OAuth shpuld be the better option.
I recently wasted hours implementing OAuth login for Bitbucket because their docs have bad links, bad explanation of params to pass, and bad explanation of endpoints to hit. I implemented Github and Gitlab just before in ~30 minutes total, so it really is a YMMV by provider problem.
Oauth is authz
But do get in “the door” you need OIDC + PKCE auth code grant.. or authn
In my case it's Duo, literally the only 2FA thing I must use that doesn't let me have my dang token so I can use whatever app I want?
Hard to make it right, hard to make it secure, hard to make it simple. And exponentially harder to make it versatile.
And if oauth is "hard", wait until you see OpenID and the myriad of extensions...
HN shows me the name of the submitter, bastienbeurier, in the colour #cd6e00. (Not sure what people call that colour in natural language, as i'm colour-blind.)
What's up with that? The account was created in 2013.
Some require scopes, some don't.
Some require comma-separated scopes, some want an array.
Some require an HMAC signature, some don't.
Some want a JSON body, some want a urlencoded form.
Etc.
Etc.
Etc.
You're never implementing OAuth, you're implementing some company's bastardized flavor.
Frankly, I'm not sure what keeps people from simply putting fake Oauth screens on random phishing emails. Figure out what a companies default auth screen looks like, pop up a similar looking web page.. bam plaintext passwords that can be used to authenticate with real services.
They implement a few happy parths of the standard, but a lot of things are just not there.
As someone often working with OAuth 2.0 flows, I enjoyed the article and think that it raises many good points. I'd also say that many of them come from things that affect _any_ system solving a problem similar to OAuth 2.0, because authorisation is hard to get right, or from extensions to the protocol that really aren't OAuth 2.0's fault (like the `realmID` parameter, obviously added to make the life of those API developers easier at the expense of those actually trying to integrate with their systems).
To me though, I wholeheartedly agree with 'Problem 1: The OAuth standard is just too big and complex' and 'Problem 2: Everybody’s OAuth is different in subtle ways'. OAuth 2.0 is more of a framework or metastandard, and no API implementation uses all parts of it because they simply are not relevant to that API or use case. This alone makes it quite hard to 'simply use OAuth' for an integration, because a big part of the job is figuring out which parts are used and in which ways, even if everything is done per the RFCs.
By contrast, OAuth 1.0a was comparatively much simpler and focused on a more narrow problem. OAuth 2.0 allows you to convert a SAML claim from one provider into an OAuth 2.0 token for a different provider to then delegate permissions conditionally to another actor for a particular action on yet another API.
Are we better off with OAuth 2.0? I say yes, because figuring out the differences between providers is probably easier than realising a hundred completely different implementations that have very different ideas of what an authorisation or delegation flow should look like. I think that one can learn to reason about OAuth 2.0 and then apply this logic to integration jobs with slightly less cognitive load than a completely bespoke solution.
At the same time, I think something sorely needed is something like OAuth 2.0 profiles that standardise the features used to integrate with OAuth 2.0. Probably most social media sites have similar requirements, most auth-as-a-service have similar requirements and so on. Having a common subset of features and decisions for common use cases and scenarios would IMO greatly simplify integration tasks and, paired with choosing a good library, make it indeed possible to integrate with a random service in under an hour.
The thing is that some of that was the spirit of older standards like OAuth 1.0a and OpenID (not to be confused with the newer OpenID Connect, which is OAuth 2.0-based), and the world seems to have moved away from that, probably because of the flexibility that OAuth 2.0 affords and the want to tightly control authorisation and external integrations.