From 22803159d8f3892ddbdd22f0b108a20a93d15456 Mon Sep 17 00:00:00 2001 From: Martin Zarate Date: Wed, 13 Dec 2023 14:08:16 -0500 Subject: [PATCH] bluesky api article --- .../Snow/_posts/2023-12-13-bluesky-api.md | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 SnowSite/Snow/_posts/2023-12-13-bluesky-api.md diff --git a/SnowSite/Snow/_posts/2023-12-13-bluesky-api.md b/SnowSite/Snow/_posts/2023-12-13-bluesky-api.md new file mode 100644 index 0000000..a059ad3 --- /dev/null +++ b/SnowSite/Snow/_posts/2023-12-13-bluesky-api.md @@ -0,0 +1,223 @@ +--- +published: published +layout: post +category: Programming +title: Bluesky API +--- + +Personally in the post-Muskening twitter world, I'm pulling for +[Mastodon](https://mastodon.social/@pxtl), but [Bluesky](https://bsky.app) is a +somewhat interesting platform too. One feature of Bluesky that stands out is +that you can set your name to be based on a domain-name you own. I own Pxtl.ca, +so I thought I'd take a crack at leveraging that feature. + +What follows is a guide on how to do this in Powershell, which is a programming +language you *already have installed* if you use Windows. + + + +# Preamble + +## What you need + +I'm going to be doing this in Powershell 5.1, which is what's built into +Windows. If you're not on Windows or you're a pro-star, you can install +Powershell 7 on any operating system. + +Second, you need your own domain. Those cost money annually, but that's how you +can have your own snazzy site like "Pxtl.ca". Personally I use Google Domains, +but sadly this is a sunsetting product so going forwards I'm going to need a new +service to run my domain-name subscription. + +## Intro to Powershell + +First up, we open up our Powershell console. You can type `⊞ Win` + `R` to +launch the **run** menu to access it, and then type "powershell" to use it. If +this is your first time running powershell you may need to do some fiddling to +enable it properly. This will give you a console to run powershell commands. + +Now, if you're following along and copying and pasting Powershell code from this +article into your Powershell window, a warning: Copying and pasting code from a +stranger into your console and running it is very dangerous because a computer +does what it's told and this stranger may have told your computer to do +something very bad. In this situation, I am basically a stranger with candy. + +So, don't ever copy/paste code from an article without fully understanding what +it does. So, I'll be explaining everything I do. + +# Logging In to the API + +We're going to be sending HTTP commands (like your web browser does, but through +the Powershell console) using a powershell command called `Invoke-RestMethod`. +"Rest" is just a programmer-jargon for "HTTP that uses data structures instead +of websites". + +So first, we have to create a session in our console that we can use to do +stuff. Bluesky/Atproto (their programmer-interface protocol) makes you first +"login" before you can do stuff. + +So we run the following: + +```ps +$sessionResponse = Invoke-RestMethod -Method POST -Uri https://bsky.social/xrpc/com.atproto.server.createSession ` + -body (@{identifier = 'email@example.com'; password ='PASSWORDGOESHERE'} | ConvertTo-Json) ` + -ContentType 'application/json' +``` + +Where "email@example.com" should be replaced with your own email address +associated with your Bluesky account (we don't use your username, just the +email) and PASSWORDGOESHERE is, obviously, your Bluesky password. If your password +contains a ' char, you'll have to escape it. + +So, what this does: We're using Invoke-RestMethod to send a POST action (like +submitting a form on a website) to the url +[https://bsky.social/xrpc/com.atproto.server.createSession](https://bsky.social/xrpc/com.atproto.server.createSession). +We know that the target is trustworthy with your Bluesky password because it's +in the "bsky.social" domain -- that is, we're sending your password to Bluesky, +not to some stranger. + +The little backtick at the end of the line is just the simplest way to do +multi-line commands in Powershell. The backtick-line-continuation is considered +bad form by Powershell people but Powershell is a bad language so imho turnabout +is fair play. + +The `-body` parameter is the body of data we're sending to Bluesky. +`@{identifier = 'email@example.com'; password ='PASSWORDGOESHERE'}` is a +Powershell object we're building with the login and password, and then we're +piping it into `| ConvertTo-Json` to turn it into the JSON text format so it can +be sent over the wire to Bluesky. + +Finally we let Bluesky know we're sending it as JSON with the parameter +`-ContentType 'application/json'`. + +And we store the result of this command into `$sessionResponse`. + +## Inspecting the Result + +You can inspect `$sessionResponse` by just running `$sessionResponse` in your +Powershell console. You'll see an object with several members like `did` and +`handle` and `email` and `accessJwt`. The important bits of data we need going +forwards are `did`, which is your true user-account-ID in Bluesky, and +`accessJwt`, which is the temporary super-long secret code we use going forwards +to do other commands. + +Now, the `accessJwt` code is short-lived (a few minutes) before the Bluesky +server decides it doesn't like it anymore, so going forwards you might have to +re-run the `createSession` command above to get a new one if commands start +failing and complaining about security. + +# Creating the Domain Record + +Okay, so we've proven to Bluesky that we are who we say we are, but how do we +prove to Bluesky that we own the domain? I mean, I could say I'm google.com or +whatever if they don't check. But they check. + +So, let's say you own "mydomain.com". You'll have to go into your domain +registrar's website and create a new TXT record on "mydomain.com" that proves to +Bluesky you own it. So get the `did` value from `$sessionResponse` by typing +`$sessionResponse.did`. For example, my `did` value is +`did:plc:otu6mg5xkk47y3ghqpq2w3oo` (this isn't a secret it's fine that you know +that). + +Create a new TXT record on "mydomain.com" called "_atproto", and give it a value +of `did=YOURDIDGOESHERE`. So for me, I created "_atproto" as a TXT record with +the value `did=did:plc:otu6mg5xkk47y3ghqpq2w3oo`. Yes it's weirdly +double-barreled with the did=did part. This is fine. + +If you want your name to be some subdomain of your domain, you can even make +"_atproto.somesubdomain". I tried this out by making "_atproto.martin" so I +could be "@martin.pxtl.ca". This is great if you're running an organization and +you've got many users on that domain - you can create one TXT record per-user, +each with their own subdomain, so like if my son got his own Bluesky account (it would have a different `did`) I +could give him "_atproto.gooseguy" so he'd be "@gooseguy.pxtl.ca". + +## Testing the Domain Record + +Once the domain record has been created, you can test that it exists with the Powershell command `Resolve-DnsName` + +So, to test it, mash together the TXT record's host name and your domain name, and call it as follows: + +```ps +Resolve-DnsName _atproto.mydomain.ca +``` + +So for example for my "@martin.pxtl.ca" name, it would be, + +```ps +Resolve-DnsName _atproto.martin.pxtl.ca +``` + +If you get a result talking about the domain and servers and authorities? It +worked. If you get ugly red error messages, it didn't. That might mean you +screwed up, or it just hasn't propagated yet (DNS/domain updates can be slow, +give it a few more minutes). + +# Updating your Username + +Finally, now that we can log into Bluesky and we've created proof for Bluesky +that we own the domain, we can tell Bluesky to change our name to match our +domain. + +```ps +Invoke-RestMethod ` + -Method POST ` + -Uri https://bsky.social/xrpc/com.atproto.identity.updateHandle ` + -Headers @{Authorization = "Bearer $($sessionResponse.accessJwt)"} ` + -Body (@{handle ='mydomain.ca'} | ConvertTo-Json) ` + -ContentType 'application/json' +``` + +So again, we're doing an HTTP POST to "bsky.social", but this time we're calling +`updateHandle` instead of `createSession`. Since we've already *got* the +session, we need to reference a token (that short-lived secret I mentioned +before) to let them know "yes, I'm still the person you were talking to +earlier". So we use the parameter `-Headers @{Authorization = "Bearer +$($sessionResponse.accessJwt)"}` which adds the `accessJwt` token to this +request as an `Authorization` header entry. + +Again, we're doing a JSON body, but this time the body is just a single entry in +the object "handle". That should match the @ handle you're trying to get, the +same one you created a TXT entry for - like, since I did both +`_atproto.martin.pxtl.ca` and `_atproto.pxtl.ca`, I can do either +`handle='pxtl.ca'` or `handle=martin.pxtl.ca`. + +This action won't send any result if it works. It will only give you feedback +if it fails. + +So, check your Bluesky account. There will be errors for a minute or so, but +your user handle should be updated to match your domain. + +# TL;DR + +To review, in Powershell: + +Run + +```ps +$sessionResponse = Invoke-RestMethod -Method POST -Uri https://bsky.social/xrpc/com.atproto.server.createSession ` + -body (@{identifier = 'email@example.com'; password ='PASSWORDGOESHERE'} | ConvertTo-Json) ` + -ContentType 'application/json' +``` + +with your bluesky email and password. + +Get `$sessionResponse.did` and use that when you create a new TXT record on +"yourdomain.com" called "_atproto", and give it a value of +`did=YOURDIDGOESHERE`. If you want to use a subdomain of "yourdomain.com" +because you feel like it or you've got friends who want to use the same domain, +you can make "_atproto.mysubmodmain" to get that. + +Now, let Bluesky know about it by calling + +```ps +Invoke-RestMethod ` + -Method POST ` + -Uri https://bsky.social/xrpc/com.atproto.identity.updateHandle ` + -Headers @{Authorization = "Bearer $($sessionResponse.accessJwt)"} ` + -Body (@{handle ='yourdomain.com'} | ConvertTo-Json) ` + -ContentType 'application/json' +``` + +or whatever your domain (or subdomain or whatever) is. + +Questions? Scroll up to the detailed part. Don't @ me. \ No newline at end of file