diff --git a/CHANGELOG.md b/CHANGELOG.md --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,12 @@ - `/logout` route for `Atex.OAuth.Plug` to revoke the current session, as well as `Atex.OAuth.Plug.revoke_session/2` to revoke a conn's session programmaticly (e.g. from a session management dashboard). +### Fixed + +- Fix issue when trying to validate OAuth authorisation codes in localhost mode + on PDS implementations that are more strict than the Bluesky reference + implementation. + ## [0.8.0] - 2026-03-29 ### Breaking Changes diff --git a/lib/atex/config/oauth.ex b/lib/atex/config/oauth.ex --- a/lib/atex/config/oauth.ex +++ b/lib/atex/config/oauth.ex @@ -40,6 +40,14 @@ %{private_key | fields: %{"kid" => key_id}} end @doc """ + Returns whether OAuth should be put into the localhost loopback mode. + """ + @spec is_localhost() :: boolean() + def is_localhost() do + Keyword.get(Application.get_env(:atex, Atex.OAuth, []), :is_localhost, false) + end + + @doc """ Returns the client ID based on configuration. If `is_localhost` is set, it'll be a string handling the "http://localhost" @@ -48,9 +56,7 @@ string pointing to the location of the `client-metadata.json` route. """ @spec client_id() :: String.t() def client_id() do - is_localhost = Keyword.get(Application.get_env(:atex, Atex.OAuth, []), :is_localhost, false) - - if is_localhost do + if is_localhost() do query = %{redirect_uri: redirect_uri(), scope: scopes()} |> URI.encode_query() diff --git a/lib/atex/oauth.ex b/lib/atex/oauth.ex --- a/lib/atex/oauth.ex +++ b/lib/atex/oauth.ex @@ -362,10 +362,17 @@ grant_type: "authorization_code", client_id: client_id, redirect_uri: redirect_uri, code: code, - code_verifier: code_verifier, - client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", - client_assertion: client_assertion + code_verifier: code_verifier } + + body = + if !Config.is_localhost(), + do: + Map.merge(body, %{ + client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + client_assertion: client_assertion + }), + else: body Req.new(method: :post, url: authz_metadata.token_endpoint, form: body) |> send_oauth_dpop_request(dpop_key)