From a713d4a81c5501f5fc9410e6530542e8d1377a4b Mon Sep 17 00:00:00 2001 From: Mridang Agarwalla Date: Tue, 27 May 2025 13:00:07 +0300 Subject: [PATCH 1/3] feat: Add Key ID (kid) support to JWT assertions Adds support for the 'kid' (Key ID) header parameter in JWT assertions, allowing clients to specify the key identifier used for signing. This improves key management and verification in systems consuming JWTs. Updates `OAuth2::Strategy::Assertion#build_assertion` to accept `kid` in `encoding_opts` and include it in the JWT header. Also adds a test case to verify the functionality. --- lib/oauth2/strategy/assertion.rb | 6 +++++- spec/oauth2/strategy/assertion_spec.rb | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/oauth2/strategy/assertion.rb b/lib/oauth2/strategy/assertion.rb index 800a4a78..5449932e 100644 --- a/lib/oauth2/strategy/assertion.rb +++ b/lib/oauth2/strategy/assertion.rb @@ -95,8 +95,12 @@ def build_request(assertion, request_opts = {}) def build_assertion(claims, encoding_opts) raise ArgumentError.new(message: "Please provide an encoding_opts hash with :algorithm and :key") if !encoding_opts.is_a?(Hash) || (%i[algorithm key] - encoding_opts.keys).any? - JWT.encode(claims, encoding_opts[:key], encoding_opts[:algorithm]) + headers = {} + headers[:kid] = encoding_opts[:kid] if encoding_opts.key?(:kid) + + JWT.encode(claims, encoding_opts[:key], encoding_opts[:algorithm], headers) end + end end end diff --git a/spec/oauth2/strategy/assertion_spec.rb b/spec/oauth2/strategy/assertion_spec.rb index 38a35dd0..d8d3af46 100644 --- a/spec/oauth2/strategy/assertion_spec.rb +++ b/spec/oauth2/strategy/assertion_spec.rb @@ -164,6 +164,24 @@ expect { client_assertion.get_token(claims, encoding_opts) }.to raise_error(ArgumentError, /encoding_opts/) end end + + context "when including a Key ID (kid)" do + let(:algorithm) { "HS256" } + let(:key) { "new_secret_key" } + let(:kid) { "my_super_secure_key_id_123" } + + before do + client_assertion.get_token(claims, algorithm: algorithm, key: key, kid: kid) + raise "No request made!" if @request_body.nil? + end + + it_behaves_like "encodes the JWT" + + it "includes the kid in the JWT header" do + expect(header).not_to be_nil + expect(header["kid"]).to eq(kid) + end + end end end From e0732768a59c6a3eeaa129f0e4f2b560baa7edec Mon Sep 17 00:00:00 2001 From: Mridang Agarwalla Date: Tue, 27 May 2025 13:04:19 +0300 Subject: [PATCH 2/3] refactor(assertion): Remove empty line in build_assertion Removes an unnecessary empty line within the `build_assertion` method for improved code style and consistency. --- lib/oauth2/strategy/assertion.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/oauth2/strategy/assertion.rb b/lib/oauth2/strategy/assertion.rb index 5449932e..6396fd6d 100644 --- a/lib/oauth2/strategy/assertion.rb +++ b/lib/oauth2/strategy/assertion.rb @@ -100,7 +100,6 @@ def build_assertion(claims, encoding_opts) JWT.encode(claims, encoding_opts[:key], encoding_opts[:algorithm], headers) end - end end end From 5f4251e074fd9947a17e578ec416b1bbef8be3fa Mon Sep 17 00:00:00 2001 From: Mridang Agarwalla Date: Tue, 27 May 2025 13:08:45 +0300 Subject: [PATCH 3/3] chore(rubocop): Update gradual lock file Updates `.rubocop_gradual.lock` due to changes in `spec/oauth2/strategy/assertion_spec.rb`. This reflects the introduction of the new `kid` test context. --- .rubocop_gradual.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.rubocop_gradual.lock b/.rubocop_gradual.lock index eaf00efa..d22e4a36 100644 --- a/.rubocop_gradual.lock +++ b/.rubocop_gradual.lock @@ -68,7 +68,7 @@ "spec/oauth2/response_spec.rb:2248532534": [ [3, 1, 31, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/response*_spec.rb`.", 3190869319] ], - "spec/oauth2/strategy/assertion_spec.rb:793170256": [ + "spec/oauth2/strategy/assertion_spec.rb:3524328522": [ [6, 1, 42, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/strategy/assertion*_spec.rb`.", 3665690869] ], "spec/oauth2/strategy/auth_code_spec.rb:142083698": [