Class: AtprotoAuth::PAR::Client
- Inherits:
-
Object
- Object
- AtprotoAuth::PAR::Client
- Defined in:
- lib/atproto_auth/par/client.rb
Overview
Client for making Pushed Authorization Requests (PAR) according to RFC 9126. Handles submitting authorization parameters to the PAR endpoint and building the subsequent authorization URL.
In AT Protocol OAuth, all authorization requests must first go through PAR. This means instead of sending authorization parameters directly to the authorization endpoint, clients:
-
Submit parameters to the PAR endpoint via POST
-
Receive a request_uri in response
-
Use only the request_uri and client_id in the authorization redirect
All requests are made using HTTPS and include proper content-type headers. DPoP proofs can be included for enhanced security. The client validates all responses and provides clear error messages for any failures.
Instance Attribute Summary collapse
-
#dpop_client ⇒ Object
readonly
Returns the value of attribute dpop_client.
-
#endpoint ⇒ Object
readonly
Returns the value of attribute endpoint.
-
#nonce_manager ⇒ Object
readonly
Returns the value of attribute nonce_manager.
Instance Method Summary collapse
-
#authorization_url(authorize_endpoint:, request_uri:, client_id:) ⇒ String
Builds authorization URL from PAR response.
- #extract_nonce(response) ⇒ Object
-
#initialize(endpoint:, dpop_client:) ⇒ Client
constructor
A new instance of Client.
-
#submit(request) ⇒ Response
Submits a PAR request, handling DPoP nonce requirements.
Constructor Details
#initialize(endpoint:, dpop_client:) ⇒ Client
Returns a new instance of Client.
59 60 61 62 63 64 |
# File 'lib/atproto_auth/par/client.rb', line 59 def initialize(endpoint:, dpop_client:) @endpoint = endpoint @dpop_client = dpop_client @nonce_manager = dpop_client.nonce_manager validate_endpoint! end |
Instance Attribute Details
#dpop_client ⇒ Object (readonly)
Returns the value of attribute dpop_client.
57 58 59 |
# File 'lib/atproto_auth/par/client.rb', line 57 def dpop_client @dpop_client end |
#endpoint ⇒ Object (readonly)
Returns the value of attribute endpoint.
57 58 59 |
# File 'lib/atproto_auth/par/client.rb', line 57 def endpoint @endpoint end |
#nonce_manager ⇒ Object (readonly)
Returns the value of attribute nonce_manager.
57 58 59 |
# File 'lib/atproto_auth/par/client.rb', line 57 def nonce_manager @nonce_manager end |
Instance Method Details
#authorization_url(authorize_endpoint:, request_uri:, client_id:) ⇒ String
Builds authorization URL from PAR response
111 112 113 114 115 116 117 118 |
# File 'lib/atproto_auth/par/client.rb', line 111 def (authorize_endpoint:, request_uri:, client_id:) uri = URI() uri.query = encode_params( "request_uri" => request_uri, "client_id" => client_id ) uri.to_s end |
#extract_nonce(response) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/atproto_auth/par/client.rb', line 94 def extract_nonce(response) # Try all possible header key formats headers = response[:headers] nonce = headers["DPoP-Nonce"] || headers["dpop-nonce"] || headers["Dpop-Nonce"] raise Error, "No DPoP nonce provided in response" unless nonce nonce end |
#submit(request) ⇒ Response
Submits a PAR request, handling DPoP nonce requirements
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/atproto_auth/par/client.rb', line 70 def submit(request) # Try the initial request response = make_request(request) return process_response(response) if response[:status] == 201 # Handle DPoP nonce requirement if requires_nonce?(response) nonce = extract_nonce(response) store_nonce(nonce) # Get stored nonce to verify nonce_manager.get(server_origin) # Generate new proof with nonce and retry response = make_request(request) return process_response(response) if response[:status] == 201 end handle_error_response(response) rescue StandardError => e raise Error, "PAR request failed: #{e.}" end |