Clients should stop retrying requests if they get a OHTTP key rejection
When a directory responds with Key Configuration Rejected 400 error, clients should switch on that error variant and attempt to re-fetch fresh OHTTP keys. Currently they keep retrying and failing:
2025-03-31T15:41:51.163943Z DEBUG payjoin_directory: serve_payjoin_directory: ["", ".well-known", "ohttp-gateway"]
2025-03-31T15:41:51.164681Z TRACE bitcoin_ohttp: HPKE info: 6d6573736167652f626874747020726571756573740001001600010003
2025-03-31T15:41:51.165224Z ERROR payjoin_directory: Bad request: Key configuration rejected: a problem occurred with HPKE: Failed to open ciphertext
2025-03-31T15:41:52.216120Z DEBUG payjoin_directory: serve_payjoin_directory: ["", ".well-known", "ohttp-gateway"]
2025-03-31T15:41:52.217250Z TRACE bitcoin_ohttp: HPKE info: 6d6573736167652f626874747020726571756573740001001600010003
2025-03-31T15:41:52.217875Z ERROR payjoin_directory: Bad request: Key configuration rejected: a problem occurred with HPKE: Failed to open ciphertext
2025-03-31T15:41:53.449042Z DEBUG payjoin_directory: serve_payjoin_directory: ["", ".well-known", "ohttp-gateway"]
2025-03-31T15:41:53.450171Z TRACE bitcoin_ohttp: HPKE info: 6d6573736167652f626874747020726571756573740001001600010003
2025-03-31T15:41:53.450777Z ERROR payjoin_directory: Bad request: Key configuration rejected: a problem occurred with HPKE: Failed to open ciphertext
2025-03-31T15:41:54.145756Z DEBUG payjoin_directory: serve_payjoin_directory: ["", ".well-known", "ohttp-gateway"]
2025-03-31T15:41:54.146435Z TRACE bitcoin_ohttp: HPKE info: 6d6573736167652f626874747020726571756573740001001600010003
2025-03-31T15:41:54.146954Z ERROR payjoin_directory: Bad request: Key configuration rejected: a problem occurred with HPKE: Failed to open ciphertext
For receivers, this requires making SessionContext modifiable (specifically providing a way to update ohttp_keys and persisting the change).
For senders, it means falling back to the io::fetch_ohttp_keys functionality if the OHTTP keys provided in the receiver's payjoin URL are stale.
Relates to #614
Additional thoughts:
Once #616 is merged and deployed, this issue becomes much less serious because the default session expires after 24 hours, so old key configurations should always be valid for the duration of a session (as long as directory's grace period for old configs > default session expiry time).
So trying to refetch on OHTTP key rejection errors is probably overkill, and would add a lot of complexity for little gain.
The simpler solution would be for implementers to stop retrying requests on any 400 response and mark that session as failed. This should be encouraged/made explicit with good error types that can be matched against. I started exploring this in https://github.com/payjoin/rust-payjoin/pull/617
Also note that payjoin-cli correctly stops looping on any process_res error, but other implementations may not. This is likely due to language bindings not exposing enough error details currently.