Class: AtprotoAuth::DPoP::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/atproto_auth/dpop/client.rb

Overview

High-level client for managing DPoP operations. Integrates key management, proof generation, and nonce tracking to provide a complete DPoP client implementation according to RFC 9449.

This client handles:

  • Key management for signing proofs

  • Proof generation for HTTP requests

  • Nonce tracking across servers

  • Header construction for requests

  • Response processing for nonce updates

Defined Under Namespace

Classes: Error

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key_manager: nil, nonce_ttl: nil) ⇒ Client

Creates a new DPoP client

Parameters:

  • key_manager (KeyManager, nil) (defaults to: nil)

    Optional existing key manager

  • nonce_ttl (Integer, nil) (defaults to: nil)

    Optional TTL for nonces in seconds



29
30
31
32
33
# File 'lib/atproto_auth/dpop/client.rb', line 29

def initialize(key_manager: nil, nonce_ttl: nil)
  @key_manager = key_manager || KeyManager.new
  @nonce_manager = NonceManager.new(ttl: nonce_ttl)
  @proof_generator = ProofGenerator.new(@key_manager)
end

Instance Attribute Details

#key_managerKeyManager (readonly)

Returns DPoP key manager instance.

Returns:



20
21
22
# File 'lib/atproto_auth/dpop/client.rb', line 20

def key_manager
  @key_manager
end

#nonce_managerNonceManager (readonly)

Returns DPoP nonce manager instance.

Returns:



24
25
26
# File 'lib/atproto_auth/dpop/client.rb', line 24

def nonce_manager
  @nonce_manager
end

#proof_generatorProofGenerator (readonly)

Returns DPoP proof generator instance.

Returns:



22
23
24
# File 'lib/atproto_auth/dpop/client.rb', line 22

def proof_generator
  @proof_generator
end

Instance Method Details

#export_key(include_private: false) ⇒ Hash

Exports the current keypair as JWK

Parameters:

  • include_private (Boolean) (defaults to: false)

    Whether to include private key

Returns:

  • (Hash)

    JWK representation of keypair



94
95
96
# File 'lib/atproto_auth/dpop/client.rb', line 94

def export_key(include_private: false)
  @key_manager.to_jwk(include_private: include_private)
end

#generate_proof(http_method:, http_uri:, access_token: nil, nonce: nil) ⇒ String

Generates a DPoP proof for an HTTP request

Parameters:

  • http_method (String)

    HTTP method (e.g., “POST”)

  • http_uri (String)

    Full request URI

  • access_token (String, nil) (defaults to: nil)

    Optional access token to bind to proof

Returns:

  • (String)

    The DPoP proof JWT

Raises:

  • (Error)

    if proof generation fails



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/atproto_auth/dpop/client.rb', line 41

def generate_proof(http_method:, http_uri:, access_token: nil, nonce: nil)
  uri = URI(http_uri)
  server_url = "#{uri.scheme}://#{uri.host}#{":#{uri.port}" if uri.port != uri.default_port}"

  # Use provided nonce or get one from the manager
  nonce ||= @nonce_manager.get(server_url)

  @proof_generator.generate(
    http_method: http_method,
    http_uri: http_uri,
    nonce: nonce,
    access_token: access_token
  )
rescue StandardError => e
  raise Error, "Failed to generate proof: #{e.message}"
end

#process_response(response_headers, server_url) ⇒ void

This method returns an undefined value.

Updates stored nonce from server response

Parameters:

  • response_headers (Hash)

    Response headers

  • server_url (String)

    Server’s base URL

Raises:

  • (Error)

    if nonce update fails



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/atproto_auth/dpop/client.rb', line 63

def process_response(response_headers, server_url)
  return unless response_headers

  # Look for DPoP-Nonce header (case insensitive)
  nonce = response_headers.find { |k, _| k.downcase == "dpop-nonce" }&.last
  return unless nonce

  # Store new nonce for future requests
  @nonce_manager.update(nonce: nonce, server_url: server_url)
rescue StandardError => e
  raise Error, "Failed to process response: #{e.message}"
end

#public_keyHash

Gets the current public key in JWK format

Returns:

  • (Hash)

    JWK representation of public key



87
88
89
# File 'lib/atproto_auth/dpop/client.rb', line 87

def public_key
  @key_manager.public_jwk
end

#request_headers(proof) ⇒ Hash

Constructs DPoP header value for a request

Parameters:

  • proof (String)

    The DPoP proof JWT

Returns:

  • (Hash)

    Headers to add to request



79
80
81
82
83
# File 'lib/atproto_auth/dpop/client.rb', line 79

def request_headers(proof)
  {
    "DPoP" => proof
  }
end