Documentation Index Fetch the complete documentation index at: https://mintlify.com/bluesky-social/atproto/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The @atproto/identity package provides TypeScript utilities for resolving and managing decentralized identities in the AT Protocol. It supports DID resolution (did:plc and did:web) and handle resolution via DNS and HTTP methods.
Installation
npm install @atproto/identity
Core Concepts
The identity package handles two main types of identifiers:
DIDs (Decentralized Identifiers) : Persistent, cryptographically-verifiable identifiers
Handles : Human-readable domain names that resolve to DIDs
This package provides resolvers for both identifier types and utilities for extracting AT Protocol-specific data from DID documents.
Main Exports
Classes
IdResolver
The main class that combines both DID and handle resolution.
import { IdResolver } from '@atproto/identity'
const resolver = new IdResolver ({
timeout: 3000 ,
plcUrl: 'https://plc.directory' ,
backupNameservers: [ '8.8.8.8' , '1.1.1.1' ]
})
// Resolve a handle to a DID
const did = await resolver . handle . resolve ( 'alice.bsky.social' )
// => 'did:plc:...'
// Resolve a DID to its document
const doc = await resolver . did . resolve ( did )
// Get AT Protocol-specific data
const data = await resolver . did . resolveAtprotoData ( did )
console . log ( data . handle , data . pds , data . signingKey )
Configuration options for the resolver Timeout in milliseconds for resolution requests
plcUrl
string
default: "https://plc.directory"
URL of the PLC directory server
Optional cache implementation for DID documents
Backup DNS nameservers for handle resolution
Properties:
handle: HandleResolver - Handle resolver instance
did: DidResolver - DID resolver instance
DidResolver
Resolves DIDs to their DID documents. Supports did:plc and did:web methods.
import { DidResolver } from '@atproto/identity'
const resolver = new DidResolver ({
timeout: 3000 ,
plcUrl: 'https://plc.directory'
})
const doc = await resolver . resolve ( 'did:plc:ewvi7nxzyoun6zhxrhs64oiz' )
Configuration options plcUrl
string
default: "https://plc.directory"
PLC directory URL
Optional cache implementation
Methods:
async resolve ( did : string , forceRefresh ?: boolean ): Promise < DidDocument >
Resolves a DID to its document. Uses cache unless forceRefresh is true. Skip cache and force fresh resolution
async resolveAtprotoData ( did : string , forceRefresh ?: boolean ): Promise < AtprotoData >
Resolves a DID and extracts AT Protocol-specific data. Returns an object with:
did: string - The DID
signingKey: string - The signing key in did:key format
handle: string - The associated handle
pds: string - The PDS endpoint URL
HandleResolver
Resolves handles to DIDs using DNS TXT records and HTTP well-known endpoints.
import { HandleResolver } from '@atproto/identity'
const resolver = new HandleResolver ({
timeout: 3000 ,
backupNameservers: [ '8.8.8.8' ]
})
const did = await resolver . resolve ( 'alice.bsky.social' )
// => 'did:plc:...'
Configuration options Backup DNS servers to use if primary resolution fails
Methods:
resolve
Promise<string | undefined>
async resolve ( handle : string ): Promise < string | undefined >
Resolves a handle to a DID. Tries DNS first, then HTTP, then backup DNS. The handle to resolve (e.g., ‘alice.bsky.social’)
resolveDns
Promise<string | undefined>
async resolveDns ( handle : string ): Promise < string | undefined >
Resolves via DNS TXT record at _atproto.{handle}
resolveHttp
Promise<string | undefined>
async resolveHttp ( handle : string , signal ?: AbortSignal ): Promise < string | undefined >
Resolves via HTTPS at https://{handle}/.well-known/atproto-did
Utility Functions
DID Document Parsing
Extract AT Protocol-specific data from DID documents.
import {
parseToAtprotoDocument ,
ensureAtpDocument ,
getKey ,
getHandle ,
getPds
} from '@atproto/identity'
const doc = await resolver . did . resolve ( 'did:plc:...' )
// Parse with partial data (may have missing fields)
const partial = parseToAtprotoDocument ( doc )
if ( partial . handle && partial . pds ) {
console . log ( `Handle: ${ partial . handle } , PDS: ${ partial . pds } ` )
}
// Ensure all required fields are present
try {
const complete = ensureAtpDocument ( doc )
console . log ( complete . did , complete . handle , complete . pds , complete . signingKey )
} catch ( err ) {
console . error ( 'Missing required fields' )
}
// Extract individual fields
const signingKey = getKey ( doc )
const handle = getHandle ( doc )
const pdsUrl = getPds ( doc )
function parseToAtprotoDocument ( doc : DidDocument ) : Partial < AtprotoData >
Extracts AT Protocol data from a DID document. Returns partial data - some fields may be undefined.
function ensureAtpDocument ( doc : DidDocument ) : AtprotoData
Ensures all required AT Protocol fields are present. Throws if any are missing.
function getKey ( doc : DidDocument ) : string | undefined
Extracts the signing key in did:key format.
function getHandle ( doc : DidDocument ) : string | undefined
Extracts the handle from the DID document.
function getPds ( doc : DidDocument ) : string | undefined
Extracts the PDS endpoint URL.
Types
AtprotoData
type AtprotoData = {
did : string
signingKey : string
handle : string
pds : string
}
Complete AT Protocol-specific data extracted from a DID document.
DidDocument
W3C DID Document structure. Re-exported from @atproto/common-web.
DidCache
Interface for implementing custom DID document caching.
interface DidCache {
cacheDid (
did : string ,
doc : DidDocument ,
prevResult ?: CacheResult
) : Promise < void >
checkCache ( did : string ) : Promise < CacheResult | null >
refreshCache (
did : string ,
getDoc : () => Promise < DidDocument | null >,
prevResult ?: CacheResult
) : Promise < void >
clearEntry ( did : string ) : Promise < void >
clear () : Promise < void >
}
Errors
The package exports several error classes:
import {
DidNotFoundError ,
PoorlyFormattedDidError ,
UnsupportedDidMethodError ,
PoorlyFormattedDidDocumentError ,
UnsupportedDidWebPathError
} from '@atproto/identity'
DidNotFoundError - DID could not be resolved
PoorlyFormattedDidError - DID syntax is invalid
UnsupportedDidMethodError - DID method is not supported (only did:plc and did:web are supported)
PoorlyFormattedDidDocumentError - DID document structure is invalid
UnsupportedDidWebPathError - did:web path is not supported
Complete Example
import { IdResolver } from '@atproto/identity'
const resolver = new IdResolver ({
timeout: 3000 ,
plcUrl: 'https://plc.directory' ,
backupNameservers: [ '8.8.8.8' ]
})
// Resolve handle to DID
const handle = 'alice.bsky.social'
const did = await resolver . handle . resolve ( handle )
if ( ! did ) {
throw new Error ( 'Handle resolution failed' )
}
console . log ( `Resolved ${ handle } to ${ did } ` )
// Get full DID document
const doc = await resolver . did . resolve ( did )
// Extract AT Protocol data
const data = await resolver . did . resolveAtprotoData ( did )
// Verify handle matches
if ( data . handle !== handle ) {
throw new Error ( 'Handle mismatch - DID document does not match' )
}
console . log ( 'Identity verified:' , {
did: data . did ,
handle: data . handle ,
pds: data . pds ,
signingKey: data . signingKey
})
// Subsequent resolutions use cache
const cachedDoc = await resolver . did . resolve ( did ) // Fast, from cache
// Force fresh resolution
const freshDoc = await resolver . did . resolve ( did , true ) // Bypasses cache
Additional Resources