From 0164ed5e411a2f6554cf472915fcf802c8aaae31 Mon Sep 17 00:00:00 2001 From: makssein <90086818+makssein@users.noreply.github.com> Date: Mon, 12 Oct 2026 17:44:47 +0000 Subject: [PATCH 1/2] Add failing specs for secrets in the request body of the debug log #get_token passes the params to Faraday as a Hash. The debug logger is added before :url_encoded, so it prints the request body with #pretty_inspect, and the sanitized logger, which only redacts JSON and form-encoded pairs, leaves the client secret, the code verifier and the refresh token in the output. --- spec/oauth2/client_spec.rb | 57 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/spec/oauth2/client_spec.rb b/spec/oauth2/client_spec.rb index f1654779..56a98866 100644 --- a/spec/oauth2/client_spec.rb +++ b/spec/oauth2/client_spec.rb @@ -410,6 +410,54 @@ expect(printed).to match(/FILTERED|REDACTED/) end + # #get_token passes the params to Faraday as a Hash, which the debug logger, + # added before :url_encoded, prints with #pretty_inspect. + it "redacts the client secret from the request body of #get_token from STDOUT" do + client = debug_logging_client do |stub| + stub.post("/oauth/token") do + [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-access-token")] + end + end + + printed = capture(:stdout) do + client.auth_code.get_token("the-code") + end + + expect(printed).to include("/oauth/token") + expect(printed).not_to include("the-client-secret") + end + + it "redacts the code verifier from the request body of #get_token from STDOUT" do + client = debug_logging_client do |stub| + stub.post("/oauth/token") do + [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-access-token")] + end + end + + printed = capture(:stdout) do + client.auth_code.get_token("the-code", code_verifier: "the-code-verifier") + end + + expect(printed).to include("/oauth/token") + expect(printed).not_to include("the-code-verifier") + end + + it "redacts the refresh token from the request body of AccessToken#refresh! from STDOUT" do + client = debug_logging_client do |stub| + stub.post("/oauth/token") do + [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-new-access-token")] + end + end + access_token = OAuth2::AccessToken.new(client, "the-access-token", refresh_token: "the-refresh-token") + + printed = capture(:stdout) do + access_token.refresh! + end + + expect(printed).to include("/oauth/token") + expect(printed).not_to include("the-refresh-token") + end + it "safely redacts obvious secrets in opaque non-JSON response bodies" do client = stubbed_client do |stub| stub.get("/opaque_secret") do @@ -1654,4 +1702,13 @@ def stubbed_client(params = {}, &stubs) builder.adapter :test, &stubs end end + + # Builds the connection the way the default one is built, with :url_encoded before the adapter, + # and sends the client secret in the request body. + def debug_logging_client(&stubs) + OAuth2::Client.new("abc", "the-client-secret", site: "https://api.example.com", auth_scheme: :request_body) do |builder| + builder.request :url_encoded + builder.adapter :test, &stubs + end + end end From 47125e02cf2cdc14a7f804715de9ec41d3138b09 Mon Sep 17 00:00:00 2001 From: makssein <90086818+makssein@users.noreply.github.com> Date: Mon, 12 Oct 2026 18:35:47 +0000 Subject: [PATCH 2/2] Build debug_logging_client like stubbed_client --- spec/oauth2/client_spec.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/oauth2/client_spec.rb b/spec/oauth2/client_spec.rb index 56a98866..a9c0e072 100644 --- a/spec/oauth2/client_spec.rb +++ b/spec/oauth2/client_spec.rb @@ -1703,10 +1703,11 @@ def stubbed_client(params = {}, &stubs) end end - # Builds the connection the way the default one is built, with :url_encoded before the adapter, - # and sends the client secret in the request body. - def debug_logging_client(&stubs) - OAuth2::Client.new("abc", "the-client-secret", site: "https://api.example.com", auth_scheme: :request_body) do |builder| + # Like stubbed_client, but with :url_encoded as in the default connection + # and the client secret sent in the request body. + def debug_logging_client(params = {}, &stubs) + params = {site: "https://api.example.com", auth_scheme: :request_body}.merge(params) + OAuth2::Client.new("abc", "the-client-secret", params) do |builder| builder.request :url_encoded builder.adapter :test, &stubs end