Skip to content

Vendor atlassian-jwt and unlock jwt 3.x#482

Merged
bobbrodie merged 1 commit into
sumoheavy:masterfrom
byroot:jwt-3.0
May 20, 2026
Merged

Vendor atlassian-jwt and unlock jwt 3.x#482
bobbrodie merged 1 commit into
sumoheavy:masterfrom
byroot:jwt-3.0

Conversation

@byroot
Copy link
Copy Markdown
Contributor

@byroot byroot commented Apr 9, 2026

Currently jira-ruby depends on atlassian-jwt which itself has a dependency on jwt ~> 2.1.

jwt being a popular dependency, this not allowing jwt 3.x, prevent updating a lot of other gems.

Given the state of atlassian-jwt, I don't expect them to ever release a new version, but it's not a whole lot of code so I think it makes more sense to just vendor it. Licensing wise there is compatibility.

Ref: https://bitbucket.org/atlassian/atlassian-jwt-ruby/src/master/
Ref: https://rubygems.org/gems/atlassian-jwt

@bobbrodie bobbrodie added this to the v3.1.1 milestone May 8, 2026
@bobbrodie
Copy link
Copy Markdown
Member

bobbrodie commented May 8, 2026

@byroot I'd like to propose a different approach. Since tests are failing after vendoring, what if we just switch to jwt and then re-implement compatible changes from Atlassian::Jwt.build_claims? I think something like this will work with both jwt 2.x and 3.x. All tests are passing but it needs further testing:

diff --git a/jira-ruby.gemspec b/jira-ruby.gemspec
index e825102..a31c832 100644
--- a/jira-ruby.gemspec
+++ b/jira-ruby.gemspec
@@ -23,8 +23,8 @@ Gem::Specification.new do |s|
   s.require_paths = ['lib']
 
   s.add_dependency 'activesupport'
-  s.add_dependency 'atlassian-jwt'
   s.add_dependency 'cgi'
+  s.add_dependency 'jwt'
   s.add_dependency 'multipart-post'
   s.add_dependency 'oauth', '~> 1.0'
 end
diff --git a/lib/jira/jwt_client.rb b/lib/jira/jwt_client.rb
index 1fa441e..ab0fb7d 100644
--- a/lib/jira/jwt_client.rb
+++ b/lib/jira/jwt_client.rb
@@ -1,6 +1,9 @@
 # frozen_string_literal: true
 
-require 'atlassian/jwt'
+require 'cgi'
+require 'digest'
+require 'jwt'
+require 'uri'
 
 module JIRA
   class JwtClient < HttpClient
@@ -29,15 +32,32 @@ module JIRA
     end
 
     def build_jwt(url)
-      claim = Atlassian::Jwt.build_claims \
-        @options[:issuer],
-        url,
-        http_method.to_s,
-        @options[:site],
-        (Time.now - 60).to_i,
-        (Time.now + 86_400).to_i
+      now = Time.now.to_i
+      claim = {
+        iss: @options[:issuer],
+        iat: now - 60,
+        exp: now + 86_400,
+        qsh: query_string_hash(url, http_method.to_s)
+      }
 
       JWT.encode claim, @options[:shared_secret]
     end
+
+    def query_string_hash(url, http_method)
+      uri = URI.parse(url)
+      base_uri = URI.parse(@options[:site])
+
+      path = uri.path.delete_prefix(base_uri.path)
+      path = '/' if path.empty?
+
+      params = CGI.parse(uri.query || '')
+      params.delete('jwt')
+      sorted_params = params.sort.map do |key, values|
+        "#{CGI.escape(key)}=#{values.sort.map { |v| CGI.escape(v) }.join(',')}"
+      end.join('&')
+
+      canonical = "#{http_method.upcase}&#{path}&#{sorted_params}"
+      Digest::SHA256.hexdigest(canonical)
+    end
   end
 end

@byroot
Copy link
Copy Markdown
Contributor Author

byroot commented May 9, 2026

My bad on the failing CI, it's unclear to me how these specs ever passed. But regardless, that code isn't actually needed, so I trimed it, it should pass now.

But otherwise, yes your proposal seem fine, I just went the simpler route because I only have limited context on this code, I'm not attached to a particular solution, as long as jira-ruby no longer block upgrading JWT I'm happy.

@byroot
Copy link
Copy Markdown
Contributor Author

byroot commented May 20, 2026

Respectful nudge

@bobbrodie bobbrodie self-requested a review May 20, 2026 14:24
@bobbrodie
Copy link
Copy Markdown
Member

Respectful nudge

Hi @byroot, I've updated the permissions on this PR to allow the checks to run and it looks like there's one minor Rubocop issue. If you could clear that up then I'll get this merged, thanks!

@byroot
Copy link
Copy Markdown
Contributor Author

byroot commented May 20, 2026

Indeed, which is weird because it doesn't fail on my machine 🤔

Currently `jira-ruby` depends on `atlassian-jwt` which itself
has a dependency on `jwt ~> 2.1`.

`jwt` being a popular dependency, this not allowing `jwt 3.x`, prevent
updating a lot of other gems.

Given the state of `atlassian-jwt`, I don't expect them to ever release
a new version, but it's not a whole lot of code so I think it makes
more sense to just vendor it. Licensing wise there is compatibility.
@byroot
Copy link
Copy Markdown
Contributor Author

byroot commented May 20, 2026

Nevermind, I was on the wrong machine 😂 .

It's fixed now. However I still can't trigger builds, sorry.

Copy link
Copy Markdown
Member

@bobbrodie bobbrodie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much for the contribution!

@bobbrodie bobbrodie merged commit dc25a17 into sumoheavy:master May 20, 2026
8 checks passed
@bobbrodie
Copy link
Copy Markdown
Member

bobbrodie commented May 20, 2026

Great, everything passes, we're merged in, and I'll get this in v3.1.1 v3.2.0 today. Thanks again, I appreciate it!

@byroot byroot deleted the jwt-3.0 branch May 20, 2026 15:19
@byroot
Copy link
Copy Markdown
Contributor Author

byroot commented May 20, 2026

Thanks for the merge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants