Jessie Rushing: Tales of Adding oAuth Login with Bsky to an OS

Jessie Rushing gives a talk about Adding oAuth Login with Bsky to an OS at ATmosphere Conference 2025 in Seattle

So, for anyone who has not yet met me at this conference, my name is Jesse, and today I'm going to be telling you about some tales of adding OAuth login with Blue Sky to an existing open-source comments tool. I'm going to take you through that process and hopefully give you an idea of what I experienced along the way. This is kind of my outline of all the stages.

To give you a little bit of background first of all about myself and the project: Coral by Vox Media is an open-source comments tool that is currently in use on news sites, big and small, all over the world. I personally was an SRE on the Coral team a few years ago, so I’m very familiar with this particular application. Coral already has a bunch of OAuth strategies.

So my initial idea started because I personally run a micro-SaaS where I offer Coral as a service to people, and I wanted to integrate a “Login with Blue Sky” button so I could have that on my service. Being that Coral already has a couple of OAuth2 clients baked in, I thought, “This is going to be really easy, right? I’ll just copy one of Coral’s existing Facebook or Google OAuth2 clients, make a new one, and this is going to be a great idea.”

So, my initial assumptions—TL;DR—were a little incorrect about how easy this was going to be. I honestly thought that the hardest part was going to be making all the login buttons and adding the config to the admin so you could enable this new feature.

After about a week of doing that, I start with my enthusiastic new branch and just go start making buttons and adding things. As I get to the part where I’m starting to actually clone the authenticators, I realize none of this is how any of this works. So this is my first real introduction into what are the differences in App-Proto OAuth versus the OAuth2 clients that we’re more familiar with from previous social media.

At this point, I realized that there were a couple of assumptions I had made that were faulty. The first one is that because an App-Proto profile can live anywhere on the internet—not just at bsky.social—you don’t have one redirect URL that you’re going to send that user back to.

The other one is that there is no, as was mentioned in a talk earlier about OAuth, if you want to enable OAuth with GitHub, the very first step is to follow that long list of instructions to set yourself up as a GitHub client. There is no such thing for App-Proto. You would not want to have to go to every single PDS host and say, “I’m making a new app that’s going to have login.” So you actually have to publish your own client ID and secret keys at a client metadata JSON route. This is not something Coral was doing with its other OAuth clients, so this was something that was going to have to be added in.

At this point, having spent a little bit of time on this project and now wondering if it was even a good idea, I needed to get some external validation. So I paused and did two things to validate whether this was something the rest of the world besides myself actually wanted.

The first one was I went to Coral and asked, “Hey, is this something that you would want and that your users would want?” And they said, “Yes, absolutely, please help us.” The other one was I submitted this to a call for proposals for this lightning talk, and having been selected, that kind of gave me some indication that this might be something the App-Proto community would also be interested in.

So at this point, I was like, “Cool. Alright, you can’t stop me. I’m going to make this be a thing.”

Having figured out that the differences were there, I wanted to get more familiar myself with how the Proto-OAuth flow worked first. One of my first steps was to clone this Statosphere example app and make my own little app that did absolutely nothing but OAuth. I ignored all the firehose stuff, all the lexicon stuff, and just made a button that I could click that would say “Login.” Once I could log in to my own Blue Sky account locally and have that working, then I was ready to go back to Coral and start trying to figure out how this was going to work in the Coral application.

Meanwhile, Coral had written some new integration tests around their OAuth strategies, and it was politely suggested that I branch off of that new branch to incorporate those new integration tests. There was a little bit of cherry-picking and redoing of branches, and along the way I ran into a couple of interesting errors.

One was if you are not correctly passing things into the client, you’ll get a “cannot resolve handle” error, because if you don’t tell it that it’s an App-Proto generic scope, it’s not going to know that that’s an App-Proto handle that it needs to resolve. The other one is that at first, in my local app, I was being a little lazy with my state store, and that doesn’t work. You have to actually store state so that it can be retrieved; otherwise, you’ll get a 401.

I’m not going to go through the individual steps of what the flow looks like when it works, but I have documented them, and there is a gist on my GitHub. I’ll share a link to that on Blue Sky as well, so you’ll be able to see it. Basically, this is what the flow looks like when it works. It is only different in the ways that you are creating that client metadata JSON and getting your redirect based on the handle. You figure out where to send the user for the authorization step based on the data that was retrieved from their handle.

I was really hoping this would be all done and completed by the time of the talk, but of course, my plans and reality are sometimes different. At this point, I’m still working with the Coral team to get this all the way through their QA process. It is going to be available probably in the next couple of weeks, but it is not fully out yet.

A few things I can answer now:

Would I have attempted this if I had known how long it would take? Definitely not.

Was it worth it though, and would I do it again? Absolutely yes. I have learned so much about this protocol and the future of what these things can do that I would do it again.

A few takeaways for anyone starting their own version of this project:

Especially if you have an existing application and think it’s going to be really simple to just do OAuth, there is no such thing as adding just Blue Sky login. You are adding login with App-Proto. That’s important. Right now, the button will say “Login with Blue Sky,” which is not an accurate representation. Users who are hosting or self-hosting or have moved their handle to a non-BSky address may know, but other users will not.

You have to issue your own client ID and secrets; you don’t go to an OAuth provider and register as a client app.

I used the OAuth client Node npm package and highly recommend using this instead of writing your own OAuth2 clients. If you have written your own OAuth2 clients in the past, you will not be able to reuse them for this.

There’s a gotcha when doing the client ID from localhost versus production; make sure you are encoding your URIs.

Two other npm packages I used for convenience were syntax and API; I highly recommend looking at those as well.

So that’s my tale of adding OAuth login to an existing open-source app, and this will be available on GitHub for anyone who wants the links.

Thank you so much. I feel like I rushed through that, so I hope I didn’t go too fast.