ReqDPoP

Hex.pmHexdocs.pmLicense: MIT

ReqDPoP is a small Req plugin for OAuth 2.0 DPoP proof generation as defined by RFC 9449.

It is not an OAuth provider, token store, or full OAuth client. It does not fetch tokens for you. It only signs DPoP proofs for outgoing Req requests and, when configured, attaches a DPoP-bound access token.

Installation

def deps do
  [
    {:req_dpop, "~> 0.5"}
  ]
end

Resource Request

key = ReqDPoP.Key.generate(:es256)

client =
  Req.new(base_url: "https://api.example.com")
  |> ReqDPoP.attach(key: key, access_token: access_token)

Req.get!(client, url: "/resource")

The plugin adds:

htu and htm are derived from the final Req request URL and method after Req has applied base URL and path options. Per RFC 9449, htu excludes the request URL's query string and fragment.

Token Endpoint Proof

Use proof-only mode by omitting :access_token:

Req.new()
|> ReqDPoP.attach(key: key)
|> Req.post!(url: "https://auth.example.com/oauth/token", form: params)

Nonce Retry

By default, ReqDPoP retries once when a response is a DPoP nonce challenge:

The retry proof includes the server nonce. Configure this behavior with :retry_on_nonce and :max_nonce_retries.

Key Persistence

Generated keys are process-local values. Production clients should persist the DPoP key if they need stable sender binding across restarts:

key = ReqDPoP.Key.generate(:es256)
jwk = ReqDPoP.Key.export(key)
key = ReqDPoP.Key.load!(jwk)

Security Notes

Development

mix format --check-formatted
mix compile --warnings-as-errors
mix credo --strict
mix test
mix docs
mix hex.build

License

MIT. See LICENSE.