Hacker News new | past | comments | ask | show | jobs | submit login
OAuth with Cloudflare workers on a statically generated site (abyteofcoding.com)
183 points by vonadz on Nov 15, 2021 | hide | past | favorite | 69 comments



To quote Sourcehut Pages Limitations (https://srht.site/limitations)

> Connections from CloudFlare’s reverse proxy are dropped. Do not help one private company expand its control over all internet traffic.

We really to not let the internet become so centralized.


SourceHut and its founder are the promulgators or a never ended stream of strong opinions and principled edicts that do little but alienate people. Drew’s solution to every problem is blocking and blackholing [0] which makes him seem weak and petty and suggests that by refusing to work constructively with people he’s mostly interested in strongarming and asserting dominance. I find it pretty hard to take him seriously and run from anything he’s associated with, even when I agree. There’s this concept called “non-violent communication” that he would be well-served to explore.

https://github.com/makeworld-the-better-one/amfora/issues/19...


Non-violent communication works if you're talking to an individual as an equal but corporations cannot empathise or be empathised with. It's madness to try.


The open source developer of amfora is about as far as you can get from a corporation, though. And behind every cloudflare reverse proxy connection is a human. Blocking them for nothing other than their choice of Internet route stands antithetical to the foundational spirit of the net, which he is ostensibly trying to protect.


Promulgators... nice. Saving that in the lexicon for future use.


s/promulgators or/promulgators of/

Yeah, it's usually used in the context of the unilateral issuing of decrees.


Cloudflare is the only provider that I know of that provides IPv6 reverse proxy for free with fair limits.

If it wasn't for them most of my sites won't be accessible for more than half of the internet.


For "free"

Also maybe there is a reasons for most of the internet not to care about ipv6 or current implementation, but that is another different big debate


What would those reasons be?


Even if I don't agree with his opinion, I really don't understand why so much people actually use cloudflare.

SSL is a solved problem since let's encrypt, cloudflare actually decreases performance (by adding an hop when serving dynamic content). For most websites, DDoS attacks are a non-issue.

It just feels like, unnecessary technology?


I've recently started using their DNS service and I've been using 1.1.1.1 for a couple of years now. I think Cloudflare has done more for the Internet than a lot of other large companies, and I'm inclined to trust them regardless of what the sr.ht founder says.

Their CAPTCHAs are annoying, though, and I wouldn't miss them an ounce if they went away.


I feel like I've single-handedly trained their AI to identify buses, boats, and planes at this point.


I've never gotten planes. Buses and boats are very rare (for me).

I mostly get crosswalks and traffic lights. I occasionally get mountains, motorcycles, and bicycles.


You don't get them because I've done them all!


The CAPTCHAs are a per-website setting that individual webmasters set (or, more likely, forget to set).

As an end user, I agree they are annoying. These two things may or may not help (hCaptcha is the engine used by Cloudflare*):

1) You can set an accessibility cookie that should be good for a while: https://www.hcaptcha.com/accessibility

2) There is also the Privacy Pass beta, which lets you redeem CAPTCHA solves for "tokens" that can be used for later CAPTCHAs https://www.hcaptcha.com/privacy-pass

But yeah, hCaptcha is really annoying, especially compared to the auto-solve of reCAPTCHA when you're logged in to a Google account.

* Cloudflare switched to hCaptcha in 2020: https://blog.cloudflare.com/moving-from-recaptcha-to-hcaptch...


The CAPTCHAs are probably over-applied by people who use the defaults, but they're absolutely necessary for some sites, especially e-commerce. The alternative would be flat-out blocking requests that trigger the CAPTCHAs. An absolute shitload of traffic on the Internet is the abusive sort, and lots of that's aimed at sites that accept CC payments. Used correctly, CAPTCHAs mean you don't have to blackhole as much traffic, so actually increase the fraction of people who can reach your site, versus some other world without them where you'd just be forced (by costs & risks of dealing with abuse) to drop those requests.


If your problem is credit card fraud you can simply enforce 3D Secure (which offloads liability) for requests that are considered risky. The customer can then choose to either use a 3DS-supported card or complete a captcha/etc.


> cloudflare actually decreases performance (by adding an hop when serving dynamic content).

Page load time tends to be dominated by static content.

But even for dynamic content, this isn't necessarily true. Setting up a TLS connection requires multiple network round trips. When using an edge network, those round trips only need to go to the nearest PoP rather than all the way to the server. If the PoP already has connections open to your server (which is probably the case if you have consistent traffic) then the network round trips back to your origin server are avoided, and your dynamic content ends up being served faster.

Additionally, Cloudflare's Argo Smart Routing is often able to route packets across the internet faster than than default network routing, which speeds up the communications between Cloudflare and your origin server.

So it turns out "adding a hop" does not necessarily decrease performance.

(Disclosure: I work for Cloudflare.)


> Setting up a TLS connection requires multiple network round trips

QUIC significantly reduces the cost of the TLS handshake, I think now it's only a single additional packet-exchange: https://blog.cloudflare.com/the-road-to-quic/


Most traffic is not QUIC yet maybe in the future.


Their service is great if you take money online at all. The $200/m tier plan, that is. I gather the $5,000+/m custom plans are nice if you need all the extra networking features, though way overpriced if you just need basic CDN features—which includes some kind of firewall, DDOS protection, e-commerce attack protection (e.g. anti-credit-card-stuffing) and light routing/rewriting/"worker" features at this point, all of which are quickly becoming table stakes in that market.

The free tier is great for serving low-value (that is, not enough value that you need a SLA from your vendor) static sites for pennies a month.

Having so much in one place is really nice for small shops.

But they 100% are on track to be the next Big Bad of the tech world, and they're heading that way very much on purpose. Their entire strategy for how they've positioned themselves is, transparently, bent toward making themselves the Web's #1 middle-man.


For my static site, it substantially decreased loading times compared to when I just host from a VPS.


Free DNS, Free CDN, easy to use the user interface, APIs, they use Go


sounds like then never getting off the hook again.


Your qualification there is important--dynamic content. Static content remains by far the primary source of internet traffic. Streaming video is over 65% of all mobile traffic by volume. That doesn't even account for mobile images.


> SSL is a solved problem since let's encrypt

Only if you remember to update your cert chains, and your web servers have to keep up with TLS etc. updates too

> cloudflare actually decreases performance (by adding an hop when serving dynamic content).

If your dynamic content doesn't require true real-time updates (like a forum or chat or something), but can be limited to once a minute updates or similar (like a reddit-style front page), caching and global CDNs can still drastically speed that up for users who aren't near your data center.

And that's just their static cache offering. If you build your site around their edge infrastructure (workers, workers KV, durable objects), you can entirely remove the last hop by handling client requests and sharing state across the CDN itself. Two of their demos show IRC-like chat and Doom (the game) running entirely on the edge: https://github.com/cloudflare/workers-chat-demo https://blog.cloudflare.com/doom-multiplayer-workers/

They also do other performance boosts, like auto-optimizing images, converting to webp, minifying stylesheets & scripts, dynamic loading, http QUIC, etc. And they offer a edge streaming solution for video (although Vimeo is probably much cheaper for most use cases).

> For most websites, DDoS attacks are a non-issue.

It can also help with things like Google Analytics bot spam, drive-by vulnerability scans against certain web servers or Wordpress, etc. It's not just a IP blacklist but does some degree of traffic analysis.

And all of that is available for free or cheap. It's very difficult to do all that yourself as a small-biz or solo web dev, even if you had full time dev-ops.

As for "the internet shouldn't be controlled by a single entity", sure, but it's always been a corporate network. Choose your nemesis: Cloudflare, Google, Amazon, Facebook, Verisign/network solutions (in the old days)... there's never been a truly free internet. At least Cloudflare is doing a darned good job of stewarding the internet.


I mean CDNs (content delivery networks) are pretty much agreed help performance by serving static content close to the end user. https://stevesouders.com/examples/rules.php

And you'd be surprised how much bot traffic that most sites get that you may or may not want to allow. Not every user feels comfortable setting up Let's Encrypt (though I agree it's awesome) or even has sufficient privileges to do so.

Compared to other services like AWS Cloudfront/WAF/etc., Fastly, Akamai, etc. IMO their offerings are quite powerful and economical.

https://www.cloudflare.com/plans/#overview


Good, it's not up to Sourcehut to decide how I should expose a web service (or browse the Internet FWIW).


They're not? You're free to not use Sourcehut.


They are working via WARP VPN, which is good. I wonder how do they differ those services, by headers only?


Fantastic use of workers!

I added the ability to do captcha submissions from my site and send alerts to slack myself. I opted not to go the worker route as I found the language a bit hard to use and I could get the same effect with just javascript pulling other dynamic javascript hosted elsewhere.

(You can see an example with the submission form at the bottom of this page: https://mrsteinberg.com/how-to-kill-your-startup-co-founder-...)


> Fantastic use of workers!

Well, when you think of Workers as Nginx, Squid, Memcached as-a-service, the possibilities simply present themselves. It is absolutely appalling that AWS has Lambda@Edge (relatively, uber expensive) and CloudFront Functions (uber lame) positioned against Workers.

Full-stack week starting today, and it is very likely that Cloudflare launch Container support for Workers: https://blog.cloudflare.com/full-stack-week-2021/

Let's see if Adam Selipsky announces anything compelling at re:invent aloof from their Lightsail initiatives which are priced similar to Cloudflare (and cheap only if you're running toy products atop, but not any SaaS-like services).


Thanks! I'd like to explore adding debugging and warning alerts in the future. Right now it's kind of hard to tell if anything is broken, short of going through the registration process myself. If you're pulling javascript hosted somewhere else to your site, doesn't that expose your slack API key?


I should have explained more. The javascript is dynamically created and hosted on S3. The keys, etc are safely on a server that runs to generate the file. I built this around the time Cloudflare first released workers, their documentation seems much less confusing now.


I'm having a hard time understanding how a file hosted on S3 can send a request to Slack without exposing your API key. Can you elaborate on that?

EDIT: guessing by the delay in response, someone just told all of HN they exposed their API key?


My understanding is that they used cloud functions. Code is being executed on someone else's server, not the client, so the keys don't have to be shared with the client.


That would be the logical solution, but "The javascript is dynamically created and hosted on S3. The keys, etc are safely on a server that runs to generate the file" sounds a lot like they have a server where they build a .js file that is capable of querying Slack, then store that file on S3 for the website to pull whenever someone registers. In that case, the client is pulling a .js file that probably has the Slack API key in it.


> I opted not to go the worker route as I found the language a bit hard to use and I could get the same effect with just javascript pulling other dynamic javascript hosted elsewhere

I'm confused by this since the default language for Workers is javascript. Do you mean their api is confusing?


I answered above - looking at their site it appears there is much more documentation. It was hard to wrap my head around what it was doing / the APIs when I wrote this


Same question.


From the article itself:

  ... one might think implementing OAuth sign up is relatively trivial; after all, you just need to write a fetch request that redirects the user to the OAuth page, then another request that sends their email to the newsletter service of choice to sign them up. Well, the issue is that in order to do the second step of that process, one needs to hit an API endpoint that requires authentication (an API key). That is essentially a password and not something you want to expose on the front end and give everyone access to.


The OAuth Authorization Code Flow with Proof Key for Code Exchange (PKCE) solves this problem without needing a worker.

This article Auth0 does a good job of explaining PKCE: https://auth0.com/docs/authorization/flows/authorization-cod...


The problem isn't about secure transmission of the access_token, it's about secure storage of the access_token: it's impossible to safely and securely store secrets in browser-based (JS) OIDC clients when using OIDC's Implicit flow, which is the only flow that works with client-side-JS applications (especially SPAs).

Conventional web-applications let the application server store per-user secrets (e.g. access_tokens). If the application server needs to be stateless then secrets are packed into a web-browser cookie with the "httponly" and "secure" attributes which prevents any and all client-scripts from accessing them. Of course browser cookies are not the same thing as a true Bearer Token, so this means that when using an SPA the SPA cannot make its own HTTP requests to other RPs, it needs to use some non-local secret-storing-proxy to make the request for it... which starts to make a mockery of how microservices should operate.

Code Flow with PKCE does not replace the Implicit flow. Also, the Auth0 article you linked to is not a "good job". On the contrary, that article talks about using client-secrets - which you *must never have* in a JS-only/SPA/static client.

The only real solution would be some kind of opaque OIDC client built-in to a browser that handles secrets-storage on-behalf of JS applications (such that JS code never gets to see or handle any secrets, including the auth code and access_token, but the OIDC identity_token should be exposed, of course). I'm surprised Google and Mozilla haven't done this already...


I think you misunderstood what I said. The API key I don't want to expose is the one that is required to register the user with the newsletter service, not the client key for the OAuth service.


In that case you could create a backend endpoint that accepts a request and makes the call with the API key on behalf of the client/front-end.

The title of the article says OAuth, and hence assumed that you wanted an authenticated client to be able to make the call to the backend for subscribing.


"In that case you could create a backend endpoint that accepts a request and makes the call with the API key on behalf of the client/front-end"

This is what is happening, except instead of a backend endpoint hosted on my own VPS, I'm using a Cloudflare worker.

"The title of the article says OAuth, and hence assumed that you wanted an authenticated client to be able to make the call to the backend for subscribing."

An authenticated client is necessary in order to retrieve the email of the client.


I follow the implementation here.

The conflating part here is that using the callback as a mechanism to imply subscription.

This works for your situation.

However, if you need to start making multiple backend calls, then, you will likely need to separate the authentication part from the subscription part.

Generally, OAuth implies that the requirement is to get authenticated by a provider and making multiple subsequent calls to some backend. Additionally, the backend will verify the authenticity of the short-lived token before allowing the operation to proceed.


OAuth doesn't use "API keys". Please clarify.


"not the client key for the OAuth service"

OAuth uses a client key and/or a client secret, for the application that is requesting access on behalf of the client.


OAuth + OIDC only uses client-secrets when using the client_credentials flow, which is only for us with non-human software, or when a client needs to authenticate and authorize itself independently of any human user. When humans are involved you won't be using client_credentials, you'll be using 'implicit' or 'code' (preferably with PKCE) - but ONLY when the client can actually safely store secrets - so static-website SPAs simply can't.

While non-human client-credentials can be used in-conjunction with a human-user's credentials it's largely unnecessary as an unauthorized client wouldn't be able to authenticate with a human-user because the redirect_uri sent from the client would be rejected automatically (and if that worked, there's always 'aud' audience filtering too), so the human-user wouldn't even be prompted to authenticate, they'd get an error message.


Yeah so in this case I'm using the client code, which is safely stored in the worker.


I don't understand how you can log out using this method, and that's very concerning. You're basically logged in forever?


There is no logout because the login isn't really a login. All this is doing is using the user's permission to submit their email (registered on the OAuth service) to subscribe to the newsletter. Nothing in the browser is changing that could compromise your details.


I absolute love the graph, really. When the idea is simple and easy, you don't need hundreds of tools, just the plain old paint is fine.


Thanks :) paint is the graphic editor I'm most proficient in!


Why not just use Cloudflare Access for this? It’s the same thing for even less work (and it’s free for personal use).


Not quite sure why my other comment got flagged, it was a genuine question. If they had, and they still suggested this, I would inquire how that would be possible. It appeared to me that they had just read the title of the article and suggested something related to it.

As far as I can tell, Cloudflare Access doesn't allow you to run arbitrary code in an environment that isn't exposed to the user, which is kind of the whole purpose of this setup. The sole purpose of the OAuth part of this operation is so that the user doesn't have to type in their email. Session persistence/selective access isn't relevant here, and that appears to be the only thing the Cloudflare Access really offers.


This worker might be cheaper depending on how heavy your app is (eg. how many requests this worker triggers on) versus Access if you have >50 users.


At my company we've been using workers extensively for routing, specific auth logic (including integration with Auth0) and more -- I guess moving towards an api gateway pattern. I loved it at first but its becoming very cumbersome to maintain. I'm currently migrating away from this pattern and try to keep logic closer to the application/code that leans on it.

tl;dr: Orchestrating many cloudflare workers at scale has not been a great experience.


Yeah I don't find this at all surprising. Ultimately it's always a balance of what's worse to maintain, the reality (server) or the abstraction (workers).


Can you self host these workers? Otherwise you get vendor lock in which is a no go.


Yes, miniflare [0] lets you run Workers locally, but I wouldn't treat it to production traffic.

There's also Deno, which is very similar in technology to Workers [1].

Others are building "Workers" atop WebAssembly, and things are looking up on that front as well [2][3].

See also: https://github.com/debarshibasak/awesome-paas

[0] https://github.com/cloudflare/miniflare

[1] https://deno.land

[2] https://github.com/suborbital/atmo

[3] https://github.com/krustlet/krustlet


Self hosting would pretty much defeat the whole purpose of workers. The point is that you don't need to self host.


Their point is, can you mitigate vendor lock-in if you need to do so? The fact that you don't even consider that is a sad commentary in itself.


If their point was can you mitigate vendor lock-in, they should have said that instead of asking about self-hosting. Saying you have vendor lock-in because you can't self-host something is very strange in the context of this article.

I didn't make a point of vendor lock-in because migrating this process flow to a self-hosted HTTP server would take about 5 minutes. On top of that, this flow is going to be very similar for any vendor offering javascript functions.

Perhaps it is my fault for not including a section discussing this, but I assumed that the audience for this would primarily be people understand basic javascript and could deduce the portability of the code by looking at it.


It's regular Javascript, so if you program it properly then you can re-use a lot of code with minimal work. Depends on how you architect your project to say how easy it would be.


The point is that you don't need to host them in production. Being able to self-host is still very useful for testing and local development workflows


"Instead of using a single server with NGINX and an API on it, I use multiple external hosted services that cost more-per-request than an old-school setup with less portability and more vendor lock-in"

This isn't even a technical accomplishment in any way, it's just slapping together a few managed services together to sign up someone for a newsletter. I cannot imagine being the one to maintain a signup flow like this, it certainly looks unnecessarily painful from here.


In regards to your quote, this is free and if I wanted to switch, I could just copy and paste the javascript into node with some minor tweaks.

A big motivator for this was definitely just to try out Cloudflare workers and see how they are. I've set up countless servers for APIs. In terms of time, I'd say Cloudflare workers is a bit faster when you get over the initial learning curve. Obviously you could write a deploy script for a server and have it set up everything automatically, and I have done that in the past, but sometimes it's fun to try new things right?

I never intended for this to come across as a technological accomplishment. I even end the article with "That’s pretty much it. It’s fairly simple with no real catches". I'm merely presenting what I thought would be useful information for some people. Personally I think maintaining a server is more work than maintaining this, but to each their own.


Thanks for sharing a small writeup of a neat thing you did! I think maybe the parent comment missed the context, which is that you wanted to add an email signup to an otherwise static site.

In that context, setting up a VPS would now mean that you have to be responsible for a new pet, including security updates and monitoring. You would also have to change your deployment tooling / workflow to something quite different (pushing and restarting a running service, rather than just running aws s3 sync ...)

Of course I don't think I would take this approach if I already had a backend service hosting a site, but I certainly would experiment with it if I were in your situation.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: