Apex handle
Overview¶
How to give an account the apex handle example.com instead of a
something.example.com subdomain.
The PDS only auto-accepts handles under its configured domain (the
.example.com subdomains), and the apex is also the PDS service identity
(did:web:example.com). So the handle is applied in two stages. Create
the account under a subdomain, then switch it to the apex once handle
verification is in place.
Requirements¶
- DNS control over
example.comto add a TXT record under_atproto. - The account's DID, which
pdsadminlists once the account exists. - An invite code if you create the account through the XRPC API rather than
pdsadmin. Generate one withpdsadmin create-invite-code.
Handle verification¶
AT Protocol resolves a handle to a DID by one of two methods, and the PDS accepts a handle once either one points at the account DID.
- DNS: a TXT record at
_atproto.<handle>whose value isdid=<did>. - HTTPS: a file at
https://<handle>/.well-known/atproto-didcontaining the DID as plain text.
Prefer DNS for the apex. The HTTPS method would place a file under the same origin the PDS serves, which risks colliding with the PDS routes.
The record for example.com:
Steps¶
Create the account with a bootstrap subdomain handle. pdsadmin prints a
generated password once:
Find the account DID:
Add the _atproto.example.com TXT record with that DID at your DNS
provider, then wait for it to propagate. Confirm it resolves before continuing:
Authenticate as the account to get an accessJwt. updateHandle fails if the
DNS record is not yet visible to the PDS, so run this only after the record
resolves:
docker exec bluesky-pds curl --silent --request POST \
http://localhost:3000/xrpc/com.atproto.server.createSession \
--header 'Content-Type: application/json' \
--data '{"identifier":"bootstrap.example.com","password":"<account-password>"}'
Switch the handle to the apex, passing the accessJwt:
docker exec bluesky-pds curl --silent --request POST \
http://localhost:3000/xrpc/com.atproto.identity.updateHandle \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <accessJwt>' \
--data '{"handle":"example.com"}'
Verify the apex now resolves to the account DID: