A library for handling DID identifiers used in Bluesky AT Protocol
1# DIDKit 🪪
2
3A small Ruby gem for handling Distributed Identifiers (DIDs) in Bluesky / AT Protocol.
4
5> [!NOTE]
6> Part of ATProto Ruby SDK: [ruby.sdk.blue](https://ruby.sdk.blue)
7
8
9## What does it do
10
11Accounts on Bluesky use identifiers like [did:plc:oio4hkxaop4ao4wz2pp3f4cr](https://plc.directory/did:plc:oio4hkxaop4ao4wz2pp3f4cr) as unique IDs, and they also have assigned human-readable handles like [@mackuba.eu](https://bsky.app/profile/mackuba.eu), which are verified either through a DNS TXT entry or a `/.well-known/atproto-did` file. This library allows you to look up any account's assigned handle using a DID string or vice versa, load the account's DID JSON document that specifies the handles and the PDS server hosting user's repo, and check if the assigned handle verifies correctly.
12
13
14## Installation
15
16To use DIDKit, you need a reasonably new version of Ruby – it should run on Ruby 2.6 and above, although it's recommended to use a version that's still getting maintainance updates, i.e. currently 3.2+. A compatible version should be preinstalled on macOS Big Sur and above and on many Linux systems. Otherwise, you can install one using tools such as [RVM](https://rvm.io), [asdf](https://asdf-vm.com), [ruby-install](https://github.com/postmodern/ruby-install) or [ruby-build](https://github.com/rbenv/ruby-build), or `rpm` or `apt-get` on Linux (see more installation options on [ruby-lang.org](https://www.ruby-lang.org/en/downloads/)).
17
18To install the gem, run in the command line:
19
20 [sudo] gem install didkit
21
22Or add this to your app's `Gemfile`:
23
24 gem 'didkit', '~> 0.3'
25
26
27## Usage
28
29The simplest way to use the gem is through the `DIDKit::DID` class, aliased as just `DID`:
30
31```rb
32did = DID.resolve_handle('jay.bsky.team')
33 # => #<DIDKit::DID:0x0... @did="did:plc:oky5czdrnfjpqslsw2a5iclo",
34 # @resolved_by=:dns, @type=:plc>
35```
36
37This returns a `DID` object, which tells you:
38
39- the DID as a string (`#to_s` or `#did`)
40- the DID type (`#type`, `:plc` or `:web`)
41- if the handle was resolved via a DNS entry or a `.well-known` file (`#resolved_by`, `:dns` or `:http`)
42
43To go in the other direction – to find an assigned and verified handle given a DID – create a `DID` from a DID string and call `get_verified_handle`:
44
45```rb
46DID.new('did:plc:ewvi7nxzyoun6zhxrhs64oiz').get_verified_handle
47 # => "atproto.com"
48```
49
50You can also load the DID JSON document using `#document`, which returns a `DIDKit::Document` (`DID` caches the document, so don't worry about calling this method multiple times):
51
52```rb
53did = DID.new('did:plc:ragtjsm2j2vknwkz3zp4oxrd')
54
55did.document.handles
56 # => ["pfrazee.com"]
57
58did.document.pds_host
59 # => "morel.us-east.host.bsky.network"
60```
61
62
63### Checking account status
64
65`DIDKit::DID` also includes a few methods for checking the status of a given account (repo), which call the `com.atproto.sync.getRepoStatus` endpoint on the account's assigned PDS:
66
67```rb
68did = DID.new('did:plc:ch7azdejgddtlijyzurfdihn')
69did.account_status
70 # => :takendown
71did.account_active?
72 # => false
73did.account_exists?
74 # => true
75
76did = DID.new('did:plc:44ybard66vv44zksje25o7dz')
77did.account_status
78 # => :active
79did.account_active?
80 # => true
81```
82
83### Configuration
84
85You can customize some things about the DID/handle lookups by using the `DIDKit::Resolver` class, which the methods in `DID` use behind the scenes.
86
87Currently available options include:
88
89- `:nameserver` - override the nameserver used for DNS lookups, e.g. to use Google's or CloudFlare's DNS
90- `:timeout` - change the connection/response timeout for HTTP requests (default: 15 s)
91- `:max_redirects` - change allowed maximum number of redirects (default: 5)
92
93Example:
94
95```rb
96resolver = DIDKit::Resolver.new(nameserver: '8.8.8.8', timeout: 30)
97
98did = resolver.resolve_handle('nytimes.com')
99 # => #<DIDKit::DID:0x0... @did="did:plc:eclio37ymobqex2ncko63h4r",
100 # @resolved_by=:dns, @type=:plc>
101
102resolver.resolve_did(did)
103 # => #<DIDKit::Document:0x0... @did=#<DIDKit::DID:...>, @json={...}>
104
105resolver.get_verified_handle(did)
106 # => 'nytimes.com'
107```
108
109## Credits
110
111Copyright © 2026 Kuba Suder ([@mackuba.eu](https://bsky.app/profile/did:plc:oio4hkxaop4ao4wz2pp3f4cr)).
112
113The code is available under the terms of the [zlib license](https://choosealicense.com/licenses/zlib/) (permissive, similar to MIT).
114
115Bug reports and pull requests are welcome 😎