pax_global_header00006660000000000000000000000064137166775230014533gustar00rootroot0000000000000052 comment=d79d045a0054db78c489343670b3c77bd7e2005c ruby-jwt-2.2.2/000077500000000000000000000000001371667752300133215ustar00rootroot00000000000000ruby-jwt-2.2.2/.codeclimate.yml000066400000000000000000000003661371667752300164000ustar00rootroot00000000000000engines: rubocop: enabled: true golint: enabled: false gofmt: enabled: false eslint: enabled: false csslint: enabled: false ratings: paths: - lib/** - "**.rb" exclude_paths: - spec/**/* - vendor/**/* ruby-jwt-2.2.2/.ebert.yml000066400000000000000000000004211371667752300152200ustar00rootroot00000000000000styleguide: excpt/linters engines: reek: enabled: true fixme: enabled: true rubocop: enabled: true channel: rubocop-0-49 duplication: config: languages: - ruby enabled: true remark-lint: enabled: true exclude_paths: - spec ruby-jwt-2.2.2/.gitignore000066400000000000000000000001641371667752300153120ustar00rootroot00000000000000.idea/ jwt.gemspec pkg Gemfile.lock coverage/ .DS_Store .rbenv-gemsets .ruby-version .vscode/ .bundle *gemfile.lock ruby-jwt-2.2.2/.rspec000066400000000000000000000000101371667752300144250ustar00rootroot00000000000000--color ruby-jwt-2.2.2/.rubocop.yml000066400000000000000000000026311371667752300155750ustar00rootroot00000000000000AllCops: Exclude: - 'bin/**/*' - 'db/**/*' - 'config/**/*' - 'script/**/*' Rails: Enabled: true Style/AlignParameters: EnforcedStyle: with_fixed_indentation Style/CaseIndentation: EnforcedStyle: end Style/AsciiComments: Enabled: false Style/IndentHash: Enabled: false Style/CollectionMethods: Enabled: true PreferredMethods: inject: 'inject' Style/Documentation: Enabled: false Style/BlockDelimiters: Exclude: - spec/**/*_spec.rb Style/BracesAroundHashParameters: Exclude: - spec/**/*_spec.rb Style/GuardClause: Enabled: false Style/IfUnlessModifier: Enabled: false Style/SpaceInsideHashLiteralBraces: Enabled: false Style/Lambda: Enabled: false Style/RaiseArgs: Enabled: false Style/SignalException: Enabled: false Metrics/AbcSize: Max: 20 Metrics/ClassLength: Max: 100 Metrics/ModuleLength: Max: 100 Metrics/LineLength: Enabled: false Metrics/MethodLength: Max: 15 Style/SingleLineBlockParams: Enabled: false Lint/EndAlignment: EnforcedStyleAlignWith: variable Style/FormatString: Enabled: false Style/MultilineMethodCallIndentation: EnforcedStyle: indented Style/MultilineOperationIndentation: EnforcedStyle: indented Style/WordArray: Enabled: false Style/RedundantSelf: Enabled: false Style/AlignHash: Enabled: true EnforcedLastArgumentHashStyle: always_ignore Style/TrivialAccessors: AllowPredicates: trueruby-jwt-2.2.2/.travis.yml000066400000000000000000000012071371667752300154320ustar00rootroot00000000000000sudo: required cache: bundler dist: trusty language: ruby rvm: - 2.3 - 2.4 - 2.5 - 2.6 gemfile: - gemfiles/standalone.gemfile - gemfiles/rails_5.0.gemfile - gemfiles/rails_5.1.gemfile - gemfiles/rails_5.2.gemfile - gemfiles/rails_6.0.gemfile script: "bundle exec rspec && bundle exec codeclimate-test-reporter" before_install: - sudo add-apt-repository ppa:chris-lea/libsodium -y - sudo apt-get update -q - sudo apt-get install libsodium-dev -y - gem install bundler matrix: fast_finish: true exclude: - gemfile: gemfiles/rails_6.0.gemfile rvm: 2.3 - gemfile: gemfiles/rails_6.0.gemfile rvm: 2.4 ruby-jwt-2.2.2/AUTHORS000066400000000000000000000021421371667752300143700ustar00rootroot00000000000000Tim Rudat Jeff Lindsay A.B Emilio Cristalli Bob Aman Zane Shannon Oliver Paul Battley Nikita Shatov blackanger Tyler Pickett James Stonehill Adam Michael Ville Lautanala Peter M. Goldstein Joakim Antman Korstiaan de Ridder Klaas Jan Wierenga Steve Sloan Bill Mill Erik Michaels-Ober Brian Flethcer Jurriaan Pruis Kevin Olbrich Larry Lv Rodrigo López Dato Steven Davidovitz Tom Wey lukas ojab sawyerzhang wohlgejm yann ARMAND Jordan Brough Juanito Fatas Julio Lopez Zuzanna Stolińska Katelyn Kasperowicz aarongray B Adam Greene Lowell Kirsh Lucas Mazza Makoto Chiba Manuel Bustillo Marco Adkins Micah Gates Mike Eirih Mike Pastore Mingan Mitch Birti Nicolas Leger Austin Kabiru Artsiom Kuts Arnaud Mesureur Ariel Salomon Rob Wygand danielgrippi Ryan Brushett Ryan McIlmoyl Aman Gupta Steve Teti revodoge Taiki Sugawara nycvotes-dev Alexandr Kostrikov Tobias Haar Toby Pinder rono23 Tomé Duarte Travis Hunter Alexander Boyd Yuji Yaginuma Ernie Miller Evgeni Golov Ewoud Kohl van Wijngaarden Ilyaaaaaaaaaaaaa Zhitomirskiy Dorian Marié Dave Grijalva Jens Hausherr Jeremiah Wuenschel Brandon Keepers John Downey Josh Bodah ruby-jwt-2.2.2/Appraisals000066400000000000000000000003711371667752300153440ustar00rootroot00000000000000appraise 'standalone' do end appraise 'rails-5.0' do gem 'rails', '~> 5.0.0' end appraise 'rails-5.1' do gem 'rails', '~> 5.1.0' end appraise 'rails-5.2' do gem 'rails', '~> 5.2.0' end appraise 'rails-6.0' do gem 'rails', '~> 6.0.0' end ruby-jwt-2.2.2/CHANGELOG.md000066400000000000000000001222021371667752300151310ustar00rootroot00000000000000# Changelog ## [v2.2.2](https://github.com/jwt/ruby-jwt/tree/v2.2.2) (2020-08-18) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.2.1...v2.2.2) **Implemented enhancements:** - JWK does not decode. [\#332](https://github.com/jwt/ruby-jwt/issues/332) - Inconsistent use of symbol and string keys in args \(exp and alrogithm\). [\#331](https://github.com/jwt/ruby-jwt/issues/331) - Pin simplecov to \< 0.18 [\#356](https://github.com/jwt/ruby-jwt/pull/356) ([anakinj](https://github.com/anakinj)) - verifies algorithm before evaluating keyfinder [\#346](https://github.com/jwt/ruby-jwt/pull/346) ([jb08](https://github.com/jb08)) - Update Rails 6 appraisal to use actual release version [\#336](https://github.com/jwt/ruby-jwt/pull/336) ([smudge](https://github.com/smudge)) - Update Travis [\#326](https://github.com/jwt/ruby-jwt/pull/326) ([berkos](https://github.com/berkos)) - Improvement/encode hmac without key [\#312](https://github.com/jwt/ruby-jwt/pull/312) ([JotaSe](https://github.com/JotaSe)) **Fixed bugs:** - v2.2.1 warning: already initialized constant JWT Error [\#335](https://github.com/jwt/ruby-jwt/issues/335) - 2.2.1 is no longer raising `JWT::DecodeError` on `nil` verification key [\#328](https://github.com/jwt/ruby-jwt/issues/328) - Fix algorithm picking from decode options [\#359](https://github.com/jwt/ruby-jwt/pull/359) ([excpt](https://github.com/excpt)) - Raise error when verification key is empty [\#358](https://github.com/jwt/ruby-jwt/pull/358) ([anakinj](https://github.com/anakinj)) **Closed issues:** - JWT RSA: is it possible to encrypt using the public key? [\#366](https://github.com/jwt/ruby-jwt/issues/366) - Example unsigned token that bypasses verification [\#364](https://github.com/jwt/ruby-jwt/issues/364) - Verify exp claim/field even if it's not present [\#363](https://github.com/jwt/ruby-jwt/issues/363) - Decode any token [\#360](https://github.com/jwt/ruby-jwt/issues/360) - \[question\] example of using a pub/priv keys for signing? [\#351](https://github.com/jwt/ruby-jwt/issues/351) - JWT::ExpiredSignature raised for non-JSON payloads [\#350](https://github.com/jwt/ruby-jwt/issues/350) - verify\_aud only verifies that at least one aud is expected [\#345](https://github.com/jwt/ruby-jwt/issues/345) - Sinatra 4.90s TTFB [\#344](https://github.com/jwt/ruby-jwt/issues/344) - How to Logout [\#342](https://github.com/jwt/ruby-jwt/issues/342) - jwt token decoding even when wrong token is provided for some letters [\#337](https://github.com/jwt/ruby-jwt/issues/337) - Need to use `symbolize\_keys` everywhere! [\#330](https://github.com/jwt/ruby-jwt/issues/330) - eval\(\) used in Forwardable limits usage in iOS App Store [\#324](https://github.com/jwt/ruby-jwt/issues/324) - HS512256 OpenSSL Exception: First num too large [\#322](https://github.com/jwt/ruby-jwt/issues/322) - Can we change the separator character? [\#321](https://github.com/jwt/ruby-jwt/issues/321) - Verifying iat without leeway may break with poorly synced clocks [\#319](https://github.com/jwt/ruby-jwt/issues/319) - Adding support for 'hd' hosted domain string [\#314](https://github.com/jwt/ruby-jwt/issues/314) - There is no "typ" header in version 2.0.0 [\#233](https://github.com/jwt/ruby-jwt/issues/233) **Merged pull requests:** - Fix 'already initialized constant JWT Error' [\#357](https://github.com/jwt/ruby-jwt/pull/357) ([excpt](https://github.com/excpt)) - Support RSA.import for all Ruby versions. [\#333](https://github.com/jwt/ruby-jwt/pull/333) ([rabajaj0509](https://github.com/rabajaj0509)) - Removed forwardable dependency [\#325](https://github.com/jwt/ruby-jwt/pull/325) ([anakinj](https://github.com/anakinj)) ## [v2.2.1](https://github.com/jwt/ruby-jwt/tree/v2.2.1) (2019-05-24) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.2.0...v2.2.1) **Fixed bugs:** - need to `require 'forwardable'` to use `Forwardable` [\#316](https://github.com/jwt/ruby-jwt/issues/316) - Add forwardable dependency for JWK RSA KeyFinder [\#317](https://github.com/jwt/ruby-jwt/pull/317) ([excpt](https://github.com/excpt)) **Merged pull requests:** - Release 2.2.1 [\#318](https://github.com/jwt/ruby-jwt/pull/318) ([excpt](https://github.com/excpt)) ## [v2.2.0](https://github.com/jwt/ruby-jwt/tree/v2.2.0) (2019-05-23) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.2.0.pre.beta.0...v2.2.0) **Closed issues:** - misspelled es512 curve name [\#310](https://github.com/jwt/ruby-jwt/issues/310) - With Base64 decode i can read the hashed content [\#306](https://github.com/jwt/ruby-jwt/issues/306) - hide post-it's for graphviz views [\#303](https://github.com/jwt/ruby-jwt/issues/303) **Merged pull requests:** - Release 2.2.0 [\#315](https://github.com/jwt/ruby-jwt/pull/315) ([excpt](https://github.com/excpt)) ## [v2.2.0.pre.beta.0](https://github.com/jwt/ruby-jwt/tree/v2.2.0.pre.beta.0) (2019-03-20) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.1.0...v2.2.0.pre.beta.0) **Implemented enhancements:** - Use iat\_leeway option [\#273](https://github.com/jwt/ruby-jwt/issues/273) - Use of global state in latest version breaks thread safety of JWT.decode [\#268](https://github.com/jwt/ruby-jwt/issues/268) - JSON support [\#246](https://github.com/jwt/ruby-jwt/issues/246) - Change the Github homepage URL to https [\#301](https://github.com/jwt/ruby-jwt/pull/301) ([ekohl](https://github.com/ekohl)) - Fix Salt length for conformance with PS family specification. [\#300](https://github.com/jwt/ruby-jwt/pull/300) ([tobypinder](https://github.com/tobypinder)) - Add support for Ruby 2.6 [\#299](https://github.com/jwt/ruby-jwt/pull/299) ([bustikiller](https://github.com/bustikiller)) - update homepage in gemspec to use HTTPS [\#298](https://github.com/jwt/ruby-jwt/pull/298) ([evgeni](https://github.com/evgeni)) - Make sure alg parameter value isn't added twice [\#297](https://github.com/jwt/ruby-jwt/pull/297) ([korstiaan](https://github.com/korstiaan)) - Claims Validation [\#295](https://github.com/jwt/ruby-jwt/pull/295) ([jamesstonehill](https://github.com/jamesstonehill)) - JWT::Encode refactorings, alg and exp related bugfixes [\#293](https://github.com/jwt/ruby-jwt/pull/293) ([anakinj](https://github.com/anakinj)) - Proposal of simple JWK support [\#289](https://github.com/jwt/ruby-jwt/pull/289) ([anakinj](https://github.com/anakinj)) - Add RSASSA-PSS signature signing support [\#285](https://github.com/jwt/ruby-jwt/pull/285) ([oliver-hohn](https://github.com/oliver-hohn)) - Add note about using a hard coded algorithm in README [\#280](https://github.com/jwt/ruby-jwt/pull/280) ([revodoge](https://github.com/revodoge)) - Add Appraisal support [\#278](https://github.com/jwt/ruby-jwt/pull/278) ([olbrich](https://github.com/olbrich)) - Fix decode threading issue [\#269](https://github.com/jwt/ruby-jwt/pull/269) ([ab320012](https://github.com/ab320012)) - Removed leeway from verify\_iat [\#257](https://github.com/jwt/ruby-jwt/pull/257) ([ab320012](https://github.com/ab320012)) **Fixed bugs:** - Inconsistent handling of payload claim data types [\#282](https://github.com/jwt/ruby-jwt/issues/282) - Issued at validation [\#247](https://github.com/jwt/ruby-jwt/issues/247) - Fix bug and simplify segment validation [\#292](https://github.com/jwt/ruby-jwt/pull/292) ([anakinj](https://github.com/anakinj)) **Security fixes:** - Decoding JWT with ES256 and secp256k1 curve [\#277](https://github.com/jwt/ruby-jwt/issues/277) **Closed issues:** - RS256, public and private keys [\#291](https://github.com/jwt/ruby-jwt/issues/291) - Allow passing current time to `decode` [\#288](https://github.com/jwt/ruby-jwt/issues/288) - Verify exp claim without verifying jwt [\#281](https://github.com/jwt/ruby-jwt/issues/281) - Audience as an array - how to specify? [\#276](https://github.com/jwt/ruby-jwt/issues/276) - signature validation using decode method for JWT [\#271](https://github.com/jwt/ruby-jwt/issues/271) - JWT is easily breakable [\#267](https://github.com/jwt/ruby-jwt/issues/267) - Ruby JWT Token [\#265](https://github.com/jwt/ruby-jwt/issues/265) - ECDSA supported algorithms constant is defined as a string, not an array [\#264](https://github.com/jwt/ruby-jwt/issues/264) - NoMethodError: undefined method `group' for \ [\#261](https://github.com/jwt/ruby-jwt/issues/261) - 'DecodeError'will replace 'ExpiredSignature' [\#260](https://github.com/jwt/ruby-jwt/issues/260) - TypeError: no implicit conversion of OpenSSL::PKey::RSA into String [\#259](https://github.com/jwt/ruby-jwt/issues/259) - NameError: uninitialized constant JWT::Algos::Eddsa::RbNaCl [\#258](https://github.com/jwt/ruby-jwt/issues/258) - Get new token if curren token expired [\#256](https://github.com/jwt/ruby-jwt/issues/256) - Infer algorithm from header [\#254](https://github.com/jwt/ruby-jwt/issues/254) - Why is the result of decode is an array? [\#252](https://github.com/jwt/ruby-jwt/issues/252) - Add support for headless token [\#251](https://github.com/jwt/ruby-jwt/issues/251) - Leeway or exp\_leeway [\#215](https://github.com/jwt/ruby-jwt/issues/215) - Could you describe purpose of cert fixtures and their cryptokey lengths. [\#185](https://github.com/jwt/ruby-jwt/issues/185) **Merged pull requests:** - Release v2.2.0-beta.0 [\#302](https://github.com/jwt/ruby-jwt/pull/302) ([excpt](https://github.com/excpt)) - Misc config improvements [\#296](https://github.com/jwt/ruby-jwt/pull/296) ([jamesstonehill](https://github.com/jamesstonehill)) - Fix JSON conflict between \#293 and \#292 [\#294](https://github.com/jwt/ruby-jwt/pull/294) ([anakinj](https://github.com/anakinj)) - Drop Ruby 2.2 from test matrix [\#290](https://github.com/jwt/ruby-jwt/pull/290) ([anakinj](https://github.com/anakinj)) - Remove broken reek config [\#283](https://github.com/jwt/ruby-jwt/pull/283) ([excpt](https://github.com/excpt)) - Add missing test, Update common files [\#275](https://github.com/jwt/ruby-jwt/pull/275) ([excpt](https://github.com/excpt)) - Remove iat\_leeway option [\#274](https://github.com/jwt/ruby-jwt/pull/274) ([wohlgejm](https://github.com/wohlgejm)) - improving code quality of jwt module [\#266](https://github.com/jwt/ruby-jwt/pull/266) ([ab320012](https://github.com/ab320012)) - fixed ECDSA supported versions const [\#263](https://github.com/jwt/ruby-jwt/pull/263) ([starbeast](https://github.com/starbeast)) - Added my name to contributor list [\#262](https://github.com/jwt/ruby-jwt/pull/262) ([ab320012](https://github.com/ab320012)) - Use `Class\#new` Shorthand For Error Subclasses [\#255](https://github.com/jwt/ruby-jwt/pull/255) ([akabiru](https://github.com/akabiru)) - \[CI\] Test against Ruby 2.5 [\#253](https://github.com/jwt/ruby-jwt/pull/253) ([nicolasleger](https://github.com/nicolasleger)) - Fix README [\#250](https://github.com/jwt/ruby-jwt/pull/250) ([rono23](https://github.com/rono23)) - Fix link format [\#248](https://github.com/jwt/ruby-jwt/pull/248) ([y-yagi](https://github.com/y-yagi)) ## [v2.1.0](https://github.com/jwt/ruby-jwt/tree/v2.1.0) (2017-10-06) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.0.0...v2.1.0) **Implemented enhancements:** - Ed25519 support planned? [\#217](https://github.com/jwt/ruby-jwt/issues/217) - Verify JTI Proc [\#207](https://github.com/jwt/ruby-jwt/issues/207) - Allow a list of algorithms for decode [\#241](https://github.com/jwt/ruby-jwt/pull/241) ([lautis](https://github.com/lautis)) - verify takes 2 params, second being payload closes: \#207 [\#238](https://github.com/jwt/ruby-jwt/pull/238) ([ab320012](https://github.com/ab320012)) - simplified logic for keyfinder [\#237](https://github.com/jwt/ruby-jwt/pull/237) ([ab320012](https://github.com/ab320012)) - Show backtrace if rbnacl-libsodium not loaded [\#231](https://github.com/jwt/ruby-jwt/pull/231) ([buzztaiki](https://github.com/buzztaiki)) - Support for ED25519 [\#229](https://github.com/jwt/ruby-jwt/pull/229) ([ab320012](https://github.com/ab320012)) **Fixed bugs:** - JWT.encode failing on encode for string [\#235](https://github.com/jwt/ruby-jwt/issues/235) - Fix string payload issue [\#236](https://github.com/jwt/ruby-jwt/pull/236) ([excpt](https://github.com/excpt)) **Security fixes:** - Add HS256 algorithm to decode default options [\#228](https://github.com/jwt/ruby-jwt/pull/228) ([marcoadkins](https://github.com/marcoadkins)) **Closed issues:** - Change from 1.5.6 to 2.0.0 and appears a "Completed 401 Unauthorized" [\#240](https://github.com/jwt/ruby-jwt/issues/240) - Why doesn't the decode function use a default algorithm? [\#227](https://github.com/jwt/ruby-jwt/issues/227) **Merged pull requests:** - Release 2.1.0 preparations [\#243](https://github.com/jwt/ruby-jwt/pull/243) ([excpt](https://github.com/excpt)) - Update README.md [\#242](https://github.com/jwt/ruby-jwt/pull/242) ([excpt](https://github.com/excpt)) - Update ebert configuration [\#232](https://github.com/jwt/ruby-jwt/pull/232) ([excpt](https://github.com/excpt)) - added algos/strategy classes + structs for inputs [\#230](https://github.com/jwt/ruby-jwt/pull/230) ([ab320012](https://github.com/ab320012)) ## [v2.0.0](https://github.com/jwt/ruby-jwt/tree/v2.0.0) (2017-09-03) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.0.0.beta1...v2.0.0) **Fixed bugs:** - The README says it uses an algorithm by default [\#226](https://github.com/jwt/ruby-jwt/issues/226) - Support versions outside 2.1 [\#209](https://github.com/jwt/ruby-jwt/issues/209) - Verifying expiration without leeway throws exception [\#206](https://github.com/jwt/ruby-jwt/issues/206) - Ruby interpreter warning [\#200](https://github.com/jwt/ruby-jwt/issues/200) - TypeError: no implicit conversion of String into Integer [\#188](https://github.com/jwt/ruby-jwt/issues/188) - Fix JWT.encode\(nil\) [\#203](https://github.com/jwt/ruby-jwt/pull/203) ([tmm1](https://github.com/tmm1)) **Closed issues:** - Possibility to disable claim verifications [\#222](https://github.com/jwt/ruby-jwt/issues/222) - Proper way to verify Firebase id tokens [\#216](https://github.com/jwt/ruby-jwt/issues/216) **Merged pull requests:** - Release 2.0.0 preparations :\) [\#225](https://github.com/jwt/ruby-jwt/pull/225) ([excpt](https://github.com/excpt)) - Skip 'exp' claim validation for array payloads [\#224](https://github.com/jwt/ruby-jwt/pull/224) ([excpt](https://github.com/excpt)) - Use a default leeway of 0 [\#223](https://github.com/jwt/ruby-jwt/pull/223) ([travisofthenorth](https://github.com/travisofthenorth)) - Fix reported codesmells [\#221](https://github.com/jwt/ruby-jwt/pull/221) ([excpt](https://github.com/excpt)) - Add fancy gem version badge [\#220](https://github.com/jwt/ruby-jwt/pull/220) ([excpt](https://github.com/excpt)) - Add missing dist option to .travis.yml [\#219](https://github.com/jwt/ruby-jwt/pull/219) ([excpt](https://github.com/excpt)) - Fix ruby version requirements in gemspec file [\#218](https://github.com/jwt/ruby-jwt/pull/218) ([excpt](https://github.com/excpt)) - Fix a little typo in the readme [\#214](https://github.com/jwt/ruby-jwt/pull/214) ([RyanBrushett](https://github.com/RyanBrushett)) - Update README.md [\#212](https://github.com/jwt/ruby-jwt/pull/212) ([zuzannast](https://github.com/zuzannast)) - Fix typo in HS512256 algorithm description [\#211](https://github.com/jwt/ruby-jwt/pull/211) ([ojab](https://github.com/ojab)) - Allow configuration of multiple acceptable issuers [\#210](https://github.com/jwt/ruby-jwt/pull/210) ([ojab](https://github.com/ojab)) - Enforce `exp` to be an `Integer` [\#205](https://github.com/jwt/ruby-jwt/pull/205) ([lucasmazza](https://github.com/lucasmazza)) - ruby 1.9.3 support message upd [\#204](https://github.com/jwt/ruby-jwt/pull/204) ([maokomioko](https://github.com/maokomioko)) ## [v2.0.0.beta1](https://github.com/jwt/ruby-jwt/tree/v2.0.0.beta1) (2017-02-27) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.6...v2.0.0.beta1) **Implemented enhancements:** - Error with method sign for String [\#171](https://github.com/jwt/ruby-jwt/issues/171) - Refactor the encondig code [\#121](https://github.com/jwt/ruby-jwt/issues/121) - Refactor [\#196](https://github.com/jwt/ruby-jwt/pull/196) ([EmilioCristalli](https://github.com/EmilioCristalli)) - Move signature logic to its own module [\#195](https://github.com/jwt/ruby-jwt/pull/195) ([EmilioCristalli](https://github.com/EmilioCristalli)) - Add options for claim-specific leeway [\#187](https://github.com/jwt/ruby-jwt/pull/187) ([EmilioCristalli](https://github.com/EmilioCristalli)) - Add user friendly encode error if private key is a String, \#171 [\#176](https://github.com/jwt/ruby-jwt/pull/176) ([ogonki-vetochki](https://github.com/ogonki-vetochki)) - Return empty string if signature less than byte\_size \#155 [\#175](https://github.com/jwt/ruby-jwt/pull/175) ([ogonki-vetochki](https://github.com/ogonki-vetochki)) - Remove 'typ' optional parameter [\#174](https://github.com/jwt/ruby-jwt/pull/174) ([ogonki-vetochki](https://github.com/ogonki-vetochki)) - Pass payload to keyfinder [\#172](https://github.com/jwt/ruby-jwt/pull/172) ([CodeMonkeySteve](https://github.com/CodeMonkeySteve)) - Use RbNaCl for HMAC if available with fallback to OpenSSL [\#149](https://github.com/jwt/ruby-jwt/pull/149) ([mwpastore](https://github.com/mwpastore)) **Fixed bugs:** - ruby-jwt::raw\_to\_asn1: Fails for signatures less than byte\_size [\#155](https://github.com/jwt/ruby-jwt/issues/155) - The leeway parameter is applies to all time based verifications [\#129](https://github.com/jwt/ruby-jwt/issues/129) - Make algorithm option required to verify signature [\#184](https://github.com/jwt/ruby-jwt/pull/184) ([EmilioCristalli](https://github.com/EmilioCristalli)) - Validate audience when payload is a scalar and options is an array [\#183](https://github.com/jwt/ruby-jwt/pull/183) ([steti](https://github.com/steti)) - Fix: exp claim check [\#161](https://github.com/jwt/ruby-jwt/pull/161) ([excpt](https://github.com/excpt)) **Closed issues:** - Different encoded value between servers with same password [\#197](https://github.com/jwt/ruby-jwt/issues/197) - Signature is different at each run [\#190](https://github.com/jwt/ruby-jwt/issues/190) - Include custom headers with password [\#189](https://github.com/jwt/ruby-jwt/issues/189) - can't create token - 'NotImplementedError: Unsupported signing method' [\#186](https://github.com/jwt/ruby-jwt/issues/186) - Cannot verify JWT at all?? [\#177](https://github.com/jwt/ruby-jwt/issues/177) - verify\_iss: true is raising JWT::DecodeError instead of JWT::InvalidIssuerError [\#170](https://github.com/jwt/ruby-jwt/issues/170) **Merged pull requests:** - Version bump 2.0.0.beta1 [\#199](https://github.com/jwt/ruby-jwt/pull/199) ([excpt](https://github.com/excpt)) - Update CHANGELOG.md and minor fixes [\#198](https://github.com/jwt/ruby-jwt/pull/198) ([excpt](https://github.com/excpt)) - Add Codacy coverage reporter [\#194](https://github.com/jwt/ruby-jwt/pull/194) ([excpt](https://github.com/excpt)) - Add minimum required ruby version to gemspec [\#193](https://github.com/jwt/ruby-jwt/pull/193) ([excpt](https://github.com/excpt)) - Code smell fixes [\#192](https://github.com/jwt/ruby-jwt/pull/192) ([excpt](https://github.com/excpt)) - Version bump to 2.0.0.dev [\#191](https://github.com/jwt/ruby-jwt/pull/191) ([excpt](https://github.com/excpt)) - Basic encode module refactoring \#121 [\#182](https://github.com/jwt/ruby-jwt/pull/182) ([ogonki-vetochki](https://github.com/ogonki-vetochki)) - Fix travis ci build configuration [\#181](https://github.com/jwt/ruby-jwt/pull/181) ([excpt](https://github.com/excpt)) - Fix travis ci build configuration [\#180](https://github.com/jwt/ruby-jwt/pull/180) ([excpt](https://github.com/excpt)) - Fix typo in README [\#178](https://github.com/jwt/ruby-jwt/pull/178) ([tomeduarte](https://github.com/tomeduarte)) - Fix code style [\#173](https://github.com/jwt/ruby-jwt/pull/173) ([excpt](https://github.com/excpt)) - Fixed a typo in a spec name [\#169](https://github.com/jwt/ruby-jwt/pull/169) ([mingan](https://github.com/mingan)) ## [v1.5.6](https://github.com/jwt/ruby-jwt/tree/v1.5.6) (2016-09-19) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.5...v1.5.6) **Fixed bugs:** - Fix missing symbol handling in aud verify code [\#166](https://github.com/jwt/ruby-jwt/pull/166) ([excpt](https://github.com/excpt)) **Merged pull requests:** - Update changelog [\#168](https://github.com/jwt/ruby-jwt/pull/168) ([excpt](https://github.com/excpt)) - Fix rubocop code smells [\#167](https://github.com/jwt/ruby-jwt/pull/167) ([excpt](https://github.com/excpt)) ## [v1.5.5](https://github.com/jwt/ruby-jwt/tree/v1.5.5) (2016-09-16) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.4...v1.5.5) **Implemented enhancements:** - JWT.decode always raises JWT::ExpiredSignature for tokens created with Time objects passed as the `exp` parameter [\#148](https://github.com/jwt/ruby-jwt/issues/148) **Fixed bugs:** - expiration check does not give "Signature has expired" error for the exact time of expiration [\#157](https://github.com/jwt/ruby-jwt/issues/157) - JTI claim broken? [\#152](https://github.com/jwt/ruby-jwt/issues/152) - Audience Claim broken? [\#151](https://github.com/jwt/ruby-jwt/issues/151) - 1.5.3 breaks compatibility with 1.5.2 [\#133](https://github.com/jwt/ruby-jwt/issues/133) - Version 1.5.3 breaks 1.9.3 compatibility, but not documented as such [\#132](https://github.com/jwt/ruby-jwt/issues/132) **Security fixes:** - \[security\] Signature verified after expiration/sub/iss checks [\#153](https://github.com/jwt/ruby-jwt/issues/153) - Signature validation before claim verification [\#160](https://github.com/jwt/ruby-jwt/pull/160) ([excpt](https://github.com/excpt)) **Closed issues:** - Rendering Json Results in JWT::DecodeError [\#162](https://github.com/jwt/ruby-jwt/issues/162) - PHP Libraries [\#154](https://github.com/jwt/ruby-jwt/issues/154) - Is ruby-jwt thread-safe? [\#150](https://github.com/jwt/ruby-jwt/issues/150) - JWT 1.5.3 [\#143](https://github.com/jwt/ruby-jwt/issues/143) - gem install v 1.5.3 returns error [\#141](https://github.com/jwt/ruby-jwt/issues/141) - Adding a CHANGELOG [\#140](https://github.com/jwt/ruby-jwt/issues/140) **Merged pull requests:** - Bump version [\#165](https://github.com/jwt/ruby-jwt/pull/165) ([excpt](https://github.com/excpt)) - Improve error message for exp claim in payload [\#164](https://github.com/jwt/ruby-jwt/pull/164) ([excpt](https://github.com/excpt)) - Fix \#151 and code refactoring [\#163](https://github.com/jwt/ruby-jwt/pull/163) ([excpt](https://github.com/excpt)) - Create specs for README.md examples [\#159](https://github.com/jwt/ruby-jwt/pull/159) ([excpt](https://github.com/excpt)) - Tiny Readme Improvement [\#156](https://github.com/jwt/ruby-jwt/pull/156) ([b264](https://github.com/b264)) - Added test execution to Rakefile [\#147](https://github.com/jwt/ruby-jwt/pull/147) ([jabbrwcky](https://github.com/jabbrwcky)) - Bump version [\#145](https://github.com/jwt/ruby-jwt/pull/145) ([excpt](https://github.com/excpt)) - Add a changelog file [\#142](https://github.com/jwt/ruby-jwt/pull/142) ([excpt](https://github.com/excpt)) - Return decoded\_segments [\#139](https://github.com/jwt/ruby-jwt/pull/139) ([akostrikov](https://github.com/akostrikov)) ## [v1.5.4](https://github.com/jwt/ruby-jwt/tree/v1.5.4) (2016-03-24) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.3...v1.5.4) **Closed issues:** - 404 at https://rubygems.global.ssl.fastly.net/gems/jwt-1.5.3.gem [\#137](https://github.com/jwt/ruby-jwt/issues/137) **Merged pull requests:** - Update README.md [\#138](https://github.com/jwt/ruby-jwt/pull/138) ([excpt](https://github.com/excpt)) - Fix base64url\_decode [\#136](https://github.com/jwt/ruby-jwt/pull/136) ([excpt](https://github.com/excpt)) - Fix ruby 1.9.3 compatibility [\#135](https://github.com/jwt/ruby-jwt/pull/135) ([excpt](https://github.com/excpt)) - iat can be a float value [\#134](https://github.com/jwt/ruby-jwt/pull/134) ([llimllib](https://github.com/llimllib)) ## [v1.5.3](https://github.com/jwt/ruby-jwt/tree/v1.5.3) (2016-02-24) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-1.5.2...v1.5.3) **Implemented enhancements:** - Refactor obsolete code for ruby 1.8 support [\#120](https://github.com/jwt/ruby-jwt/issues/120) - Fix "Rubocop/Metrics/CyclomaticComplexity" issue in lib/jwt.rb [\#106](https://github.com/jwt/ruby-jwt/issues/106) - Fix "Rubocop/Metrics/CyclomaticComplexity" issue in lib/jwt.rb [\#105](https://github.com/jwt/ruby-jwt/issues/105) - Allow a proc to be passed for JTI verification [\#126](https://github.com/jwt/ruby-jwt/pull/126) ([yahooguntu](https://github.com/yahooguntu)) - Relax restrictions on "jti" claim verification [\#113](https://github.com/jwt/ruby-jwt/pull/113) ([lwe](https://github.com/lwe)) **Closed issues:** - Verifications not functioning in latest release [\#128](https://github.com/jwt/ruby-jwt/issues/128) - Base64 is generating invalid length base64 strings - cross language interop [\#127](https://github.com/jwt/ruby-jwt/issues/127) - Digest::Digest is deprecated; use Digest [\#119](https://github.com/jwt/ruby-jwt/issues/119) - verify\_rsa no method 'verify' for class String [\#115](https://github.com/jwt/ruby-jwt/issues/115) - Add a changelog [\#111](https://github.com/jwt/ruby-jwt/issues/111) **Merged pull requests:** - Drop ruby 1.9.3 support [\#131](https://github.com/jwt/ruby-jwt/pull/131) ([excpt](https://github.com/excpt)) - Allow string hash keys in validation configurations [\#130](https://github.com/jwt/ruby-jwt/pull/130) ([tpickett66](https://github.com/tpickett66)) - Add ruby 2.3.0 for travis ci testing [\#123](https://github.com/jwt/ruby-jwt/pull/123) ([excpt](https://github.com/excpt)) - Remove obsolete json code [\#122](https://github.com/jwt/ruby-jwt/pull/122) ([excpt](https://github.com/excpt)) - Add fancy badges to README.md [\#118](https://github.com/jwt/ruby-jwt/pull/118) ([excpt](https://github.com/excpt)) - Refactor decode and verify functionality [\#117](https://github.com/jwt/ruby-jwt/pull/117) ([excpt](https://github.com/excpt)) - Drop echoe dependency for gem releases [\#116](https://github.com/jwt/ruby-jwt/pull/116) ([excpt](https://github.com/excpt)) - Updated readme for iss/aud options [\#114](https://github.com/jwt/ruby-jwt/pull/114) ([ryanmcilmoyl](https://github.com/ryanmcilmoyl)) - Fix error misspelling [\#112](https://github.com/jwt/ruby-jwt/pull/112) ([kat3kasper](https://github.com/kat3kasper)) ## [jwt-1.5.2](https://github.com/jwt/ruby-jwt/tree/jwt-1.5.2) (2015-10-27) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-1.5.1...jwt-1.5.2) **Implemented enhancements:** - Must we specify algorithm when calling decode to avoid vulnerabilities? [\#107](https://github.com/jwt/ruby-jwt/issues/107) - Code review: Rspec test refactoring [\#85](https://github.com/jwt/ruby-jwt/pull/85) ([excpt](https://github.com/excpt)) **Fixed bugs:** - aud verifies if aud is passed in, :sub does not [\#102](https://github.com/jwt/ruby-jwt/issues/102) - iat check does not use leeway so nbf could pass, but iat fail [\#83](https://github.com/jwt/ruby-jwt/issues/83) **Closed issues:** - Test ticket from Code Climate [\#104](https://github.com/jwt/ruby-jwt/issues/104) - Test ticket from Code Climate [\#100](https://github.com/jwt/ruby-jwt/issues/100) - Is it possible to decode the payload without validating the signature? [\#97](https://github.com/jwt/ruby-jwt/issues/97) - What is audience? [\#96](https://github.com/jwt/ruby-jwt/issues/96) - Options hash uses both symbols and strings as keys. [\#95](https://github.com/jwt/ruby-jwt/issues/95) **Merged pull requests:** - Fix incorrect `iat` examples [\#109](https://github.com/jwt/ruby-jwt/pull/109) ([kjwierenga](https://github.com/kjwierenga)) - Update docs to include instructions for the algorithm parameter. [\#108](https://github.com/jwt/ruby-jwt/pull/108) ([aarongray](https://github.com/aarongray)) - make sure :sub check behaves like :aud check [\#103](https://github.com/jwt/ruby-jwt/pull/103) ([skippy](https://github.com/skippy)) - Change hash syntax [\#101](https://github.com/jwt/ruby-jwt/pull/101) ([excpt](https://github.com/excpt)) - Include LICENSE and README.md in gem [\#99](https://github.com/jwt/ruby-jwt/pull/99) ([bkeepers](https://github.com/bkeepers)) - Remove unused variable in the sample code. [\#98](https://github.com/jwt/ruby-jwt/pull/98) ([hypermkt](https://github.com/hypermkt)) - Fix iat claim example [\#94](https://github.com/jwt/ruby-jwt/pull/94) ([larrylv](https://github.com/larrylv)) - Fix wrong description in README.md [\#93](https://github.com/jwt/ruby-jwt/pull/93) ([larrylv](https://github.com/larrylv)) - JWT and JWA are now RFC. [\#92](https://github.com/jwt/ruby-jwt/pull/92) ([aj-michael](https://github.com/aj-michael)) - Update README.md [\#91](https://github.com/jwt/ruby-jwt/pull/91) ([nsarno](https://github.com/nsarno)) - Fix missing verify parameter in docs [\#90](https://github.com/jwt/ruby-jwt/pull/90) ([ernie](https://github.com/ernie)) - Iat check uses leeway. [\#89](https://github.com/jwt/ruby-jwt/pull/89) ([aj-michael](https://github.com/aj-michael)) - nbf check allows exact time matches. [\#88](https://github.com/jwt/ruby-jwt/pull/88) ([aj-michael](https://github.com/aj-michael)) ## [jwt-1.5.1](https://github.com/jwt/ruby-jwt/tree/jwt-1.5.1) (2015-06-22) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-1.5.0...jwt-1.5.1) **Implemented enhancements:** - Fix either README or source code [\#78](https://github.com/jwt/ruby-jwt/issues/78) - Validate against draft 20 [\#38](https://github.com/jwt/ruby-jwt/issues/38) **Fixed bugs:** - ECDSA signature verification fails for valid tokens [\#84](https://github.com/jwt/ruby-jwt/issues/84) - Shouldn't verification of additional claims, like iss, aud etc. be enforced when in options? [\#81](https://github.com/jwt/ruby-jwt/issues/81) - decode fails with 'none' algorithm and verify [\#75](https://github.com/jwt/ruby-jwt/issues/75) **Closed issues:** - Doc mismatch: uninitialized constant JWT::ExpiredSignature [\#79](https://github.com/jwt/ruby-jwt/issues/79) - TypeError when specifying a wrong algorithm [\#77](https://github.com/jwt/ruby-jwt/issues/77) - jti verification doesn't prevent replays [\#73](https://github.com/jwt/ruby-jwt/issues/73) **Merged pull requests:** - Correctly sign ECDSA JWTs [\#87](https://github.com/jwt/ruby-jwt/pull/87) ([jurriaan](https://github.com/jurriaan)) - fixed results of decoded tokens in readme [\#86](https://github.com/jwt/ruby-jwt/pull/86) ([piscolomo](https://github.com/piscolomo)) - Force verification of "iss" and "aud" claims [\#82](https://github.com/jwt/ruby-jwt/pull/82) ([lwe](https://github.com/lwe)) ## [jwt-1.5.0](https://github.com/jwt/ruby-jwt/tree/jwt-1.5.0) (2015-05-09) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-1.4.1...jwt-1.5.0) **Implemented enhancements:** - Needs to support asymmetric key signatures over shared secrets [\#46](https://github.com/jwt/ruby-jwt/issues/46) - Implement Elliptic Curve Crypto Signatures [\#74](https://github.com/jwt/ruby-jwt/pull/74) ([jtdowney](https://github.com/jtdowney)) - Add an option to verify the signature on decode [\#71](https://github.com/jwt/ruby-jwt/pull/71) ([javawizard](https://github.com/javawizard)) **Closed issues:** - Check JWT vulnerability [\#76](https://github.com/jwt/ruby-jwt/issues/76) **Merged pull requests:** - Fixed some examples to make them copy-pastable [\#72](https://github.com/jwt/ruby-jwt/pull/72) ([jer](https://github.com/jer)) ## [jwt-1.4.1](https://github.com/jwt/ruby-jwt/tree/jwt-1.4.1) (2015-03-12) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-1.4.0...jwt-1.4.1) **Fixed bugs:** - jti verification not working per the spec [\#68](https://github.com/jwt/ruby-jwt/issues/68) - Verify ISS should be off by default [\#66](https://github.com/jwt/ruby-jwt/issues/66) **Merged pull requests:** - Fix \#66 \#68 [\#69](https://github.com/jwt/ruby-jwt/pull/69) ([excpt](https://github.com/excpt)) - When throwing errors, mention expected/received values [\#65](https://github.com/jwt/ruby-jwt/pull/65) ([rolodato](https://github.com/rolodato)) - Add 'iss' support for ruby-jwt [\#61](https://github.com/jwt/ruby-jwt/pull/61) ([ZhangHanDong](https://github.com/ZhangHanDong)) ## [jwt-1.4.0](https://github.com/jwt/ruby-jwt/tree/jwt-1.4.0) (2015-03-10) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-1.3.0...jwt-1.4.0) **Closed issues:** - The behavior using 'json' differs from 'multi\_json' [\#41](https://github.com/jwt/ruby-jwt/issues/41) **Merged pull requests:** - Release 1.4.0 [\#64](https://github.com/jwt/ruby-jwt/pull/64) ([excpt](https://github.com/excpt)) - Update README.md and remove dead code [\#63](https://github.com/jwt/ruby-jwt/pull/63) ([excpt](https://github.com/excpt)) - Add 'iat/ aud/ sub/ jti' support for ruby-jwt [\#62](https://github.com/jwt/ruby-jwt/pull/62) ([ZhangHanDong](https://github.com/ZhangHanDong)) - Clarify .encode API in README [\#60](https://github.com/jwt/ruby-jwt/pull/60) ([jbodah](https://github.com/jbodah)) ## [jwt-1.3.0](https://github.com/jwt/ruby-jwt/tree/jwt-1.3.0) (2015-02-24) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-1.2.1...jwt-1.3.0) **Closed issues:** - Signature Verification to Return Verification Error rather than decode error [\#57](https://github.com/jwt/ruby-jwt/issues/57) - Incorrect readme for leeway [\#55](https://github.com/jwt/ruby-jwt/issues/55) - What is the reason behind stripping the = in base64 encoding? [\#54](https://github.com/jwt/ruby-jwt/issues/54) - Preperations for version 2.x [\#50](https://github.com/jwt/ruby-jwt/issues/50) - Release a new version [\#47](https://github.com/jwt/ruby-jwt/issues/47) - Catch up for ActiveWhatever 4.1.1 series [\#40](https://github.com/jwt/ruby-jwt/issues/40) **Merged pull requests:** - raise verification error for signiture verification [\#58](https://github.com/jwt/ruby-jwt/pull/58) ([punkle](https://github.com/punkle)) - Added support for not before claim verification [\#56](https://github.com/jwt/ruby-jwt/pull/56) ([punkle](https://github.com/punkle)) ## [jwt-1.2.1](https://github.com/jwt/ruby-jwt/tree/jwt-1.2.1) (2015-01-22) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-1.2.0...jwt-1.2.1) **Closed issues:** - JWT.encode\({"exp": 10}, "secret"\) [\#52](https://github.com/jwt/ruby-jwt/issues/52) - JWT.encode\({"exp": 10}, "secret"\) [\#51](https://github.com/jwt/ruby-jwt/issues/51) **Merged pull requests:** - Accept expiration claims as string [\#53](https://github.com/jwt/ruby-jwt/pull/53) ([yarmand](https://github.com/yarmand)) ## [jwt-1.2.0](https://github.com/jwt/ruby-jwt/tree/jwt-1.2.0) (2014-11-24) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-0.1.13...jwt-1.2.0) **Closed issues:** - set token to expire [\#42](https://github.com/jwt/ruby-jwt/issues/42) **Merged pull requests:** - Added support for `exp` claim [\#45](https://github.com/jwt/ruby-jwt/pull/45) ([zshannon](https://github.com/zshannon)) - rspec 3 breaks passing tests [\#44](https://github.com/jwt/ruby-jwt/pull/44) ([zshannon](https://github.com/zshannon)) ## [jwt-0.1.13](https://github.com/jwt/ruby-jwt/tree/jwt-0.1.13) (2014-05-08) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-1.0.0...jwt-0.1.13) **Closed issues:** - yanking of version 0.1.12 causes issues [\#39](https://github.com/jwt/ruby-jwt/issues/39) - Semantic versioning [\#37](https://github.com/jwt/ruby-jwt/issues/37) - Update gem to get latest changes [\#36](https://github.com/jwt/ruby-jwt/issues/36) ## [jwt-1.0.0](https://github.com/jwt/ruby-jwt/tree/jwt-1.0.0) (2014-05-07) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-0.1.11...jwt-1.0.0) **Closed issues:** - API request - JWT::decoded\_header\(\) [\#26](https://github.com/jwt/ruby-jwt/issues/26) **Merged pull requests:** - return header along with playload after decoding [\#35](https://github.com/jwt/ruby-jwt/pull/35) ([sawyerzhang](https://github.com/sawyerzhang)) - Raise JWT::DecodeError on nil token [\#34](https://github.com/jwt/ruby-jwt/pull/34) ([tjmw](https://github.com/tjmw)) - Make MultiJson optional for Ruby 1.9+ [\#33](https://github.com/jwt/ruby-jwt/pull/33) ([petergoldstein](https://github.com/petergoldstein)) - Allow access to header and payload without signature verification [\#32](https://github.com/jwt/ruby-jwt/pull/32) ([petergoldstein](https://github.com/petergoldstein)) - Update specs to use RSpec 3.0.x syntax [\#31](https://github.com/jwt/ruby-jwt/pull/31) ([petergoldstein](https://github.com/petergoldstein)) - Travis - Add Ruby 2.0.0, 2.1.0, Rubinius [\#30](https://github.com/jwt/ruby-jwt/pull/30) ([petergoldstein](https://github.com/petergoldstein)) ## [jwt-0.1.11](https://github.com/jwt/ruby-jwt/tree/jwt-0.1.11) (2014-01-17) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-0.1.10...jwt-0.1.11) **Closed issues:** - url safe encode and decode [\#28](https://github.com/jwt/ruby-jwt/issues/28) - Release [\#27](https://github.com/jwt/ruby-jwt/issues/27) **Merged pull requests:** - fixed urlsafe base64 encoding [\#29](https://github.com/jwt/ruby-jwt/pull/29) ([tobscher](https://github.com/tobscher)) ## [jwt-0.1.10](https://github.com/jwt/ruby-jwt/tree/jwt-0.1.10) (2014-01-10) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-0.1.8...jwt-0.1.10) **Closed issues:** - change to signature of JWT.decode method [\#14](https://github.com/jwt/ruby-jwt/issues/14) **Merged pull requests:** - Fix warning: assigned but unused variable - e [\#25](https://github.com/jwt/ruby-jwt/pull/25) ([sferik](https://github.com/sferik)) - Echoe doesn't define a license= method [\#24](https://github.com/jwt/ruby-jwt/pull/24) ([sferik](https://github.com/sferik)) - Use OpenSSL::Digest instead of deprecated OpenSSL::Digest::Digest [\#23](https://github.com/jwt/ruby-jwt/pull/23) ([JuanitoFatas](https://github.com/JuanitoFatas)) - Handle some invalid JWTs [\#22](https://github.com/jwt/ruby-jwt/pull/22) ([steved](https://github.com/steved)) - Add MIT license to gemspec [\#21](https://github.com/jwt/ruby-jwt/pull/21) ([nycvotes-dev](https://github.com/nycvotes-dev)) - Tweaks and improvements [\#20](https://github.com/jwt/ruby-jwt/pull/20) ([threedaymonk](https://github.com/threedaymonk)) - Don't leave errors in OpenSSL.errors when there is a decoding error. [\#19](https://github.com/jwt/ruby-jwt/pull/19) ([lowellk](https://github.com/lowellk)) ## [jwt-0.1.8](https://github.com/jwt/ruby-jwt/tree/jwt-0.1.8) (2013-03-14) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-0.1.7...jwt-0.1.8) **Merged pull requests:** - Contrib and update [\#18](https://github.com/jwt/ruby-jwt/pull/18) ([threedaymonk](https://github.com/threedaymonk)) - Verify if verify is truthy \(not just true\) [\#17](https://github.com/jwt/ruby-jwt/pull/17) ([threedaymonk](https://github.com/threedaymonk)) ## [jwt-0.1.7](https://github.com/jwt/ruby-jwt/tree/jwt-0.1.7) (2013-03-07) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-0.1.6...jwt-0.1.7) **Merged pull requests:** - Catch MultiJson::LoadError and reraise as JWT::DecodeError [\#16](https://github.com/jwt/ruby-jwt/pull/16) ([rwygand](https://github.com/rwygand)) ## [jwt-0.1.6](https://github.com/jwt/ruby-jwt/tree/jwt-0.1.6) (2013-03-05) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-0.1.5...jwt-0.1.6) **Merged pull requests:** - Fixes a theoretical timing attack [\#15](https://github.com/jwt/ruby-jwt/pull/15) ([mgates](https://github.com/mgates)) - Use StandardError as parent for DecodeError [\#13](https://github.com/jwt/ruby-jwt/pull/13) ([Oscil8](https://github.com/Oscil8)) ## [jwt-0.1.5](https://github.com/jwt/ruby-jwt/tree/jwt-0.1.5) (2012-07-20) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-0.1.4...jwt-0.1.5) **Closed issues:** - Unable to specify signature header fields [\#7](https://github.com/jwt/ruby-jwt/issues/7) **Merged pull requests:** - MultiJson dependency uses ~\> but should be \>= [\#12](https://github.com/jwt/ruby-jwt/pull/12) ([sporkmonger](https://github.com/sporkmonger)) - Oops. :-\) [\#11](https://github.com/jwt/ruby-jwt/pull/11) ([sporkmonger](https://github.com/sporkmonger)) - Fix issue with signature verification in JRuby [\#10](https://github.com/jwt/ruby-jwt/pull/10) ([sporkmonger](https://github.com/sporkmonger)) - Depend on MultiJson [\#9](https://github.com/jwt/ruby-jwt/pull/9) ([lautis](https://github.com/lautis)) - Allow for custom headers on encode and decode [\#8](https://github.com/jwt/ruby-jwt/pull/8) ([dgrijalva](https://github.com/dgrijalva)) - Missing development dependency for echoe gem. [\#6](https://github.com/jwt/ruby-jwt/pull/6) ([sporkmonger](https://github.com/sporkmonger)) ## [jwt-0.1.4](https://github.com/jwt/ruby-jwt/tree/jwt-0.1.4) (2011-11-11) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/jwt-0.1.3...jwt-0.1.4) **Merged pull requests:** - Fix for RSA verification [\#5](https://github.com/jwt/ruby-jwt/pull/5) ([jordan-brough](https://github.com/jordan-brough)) ## [jwt-0.1.3](https://github.com/jwt/ruby-jwt/tree/jwt-0.1.3) (2011-06-30) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/10d7492ea325c65fce41191c73cd90d4de494772...jwt-0.1.3) **Closed issues:** - signatures calculated incorrectly \(hexdigest instead of digest\) [\#1](https://github.com/jwt/ruby-jwt/issues/1) **Merged pull requests:** - Bumped a version and added a .gemspec using rake build\_gemspec [\#3](https://github.com/jwt/ruby-jwt/pull/3) ([zhitomirskiyi](https://github.com/zhitomirskiyi)) - Added RSA support [\#2](https://github.com/jwt/ruby-jwt/pull/2) ([zhitomirskiyi](https://github.com/zhitomirskiyi)) \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* ruby-jwt-2.2.2/Gemfile000066400000000000000000000000471371667752300146150ustar00rootroot00000000000000source 'https://rubygems.org' gemspec ruby-jwt-2.2.2/LICENSE000066400000000000000000000020401371667752300143220ustar00rootroot00000000000000Copyright (c) 2011 Jeff Lindsay Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-jwt-2.2.2/README.md000066400000000000000000000427501371667752300146100ustar00rootroot00000000000000# JWT [![Gem Version](https://badge.fury.io/rb/jwt.svg)](https://badge.fury.io/rb/jwt) [![Build Status](https://travis-ci.org/jwt/ruby-jwt.svg)](https://travis-ci.org/jwt/ruby-jwt) [![Code Climate](https://codeclimate.com/github/jwt/ruby-jwt/badges/gpa.svg)](https://codeclimate.com/github/jwt/ruby-jwt) [![Test Coverage](https://codeclimate.com/github/jwt/ruby-jwt/badges/coverage.svg)](https://codeclimate.com/github/jwt/ruby-jwt/coverage) [![Issue Count](https://codeclimate.com/github/jwt/ruby-jwt/badges/issue_count.svg)](https://codeclimate.com/github/jwt/ruby-jwt) [![Ebert](https://ebertapp.io/github/jwt/ruby-jwt.svg)](https://ebertapp.io/github/jwt/ruby-jwt) A ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) standard. If you have further questions related to development or usage, join us: [ruby-jwt google group](https://groups.google.com/forum/#!forum/ruby-jwt). ## Announcements * Ruby 1.9.3 support was dropped at December 31st, 2016. * Version 1.5.3 yanked. See: [#132](https://github.com/jwt/ruby-jwt/issues/132) and [#133](https://github.com/jwt/ruby-jwt/issues/133) ## Installing ### Using Rubygems: ```bash sudo gem install jwt ``` ### Using Bundler: Add the following to your Gemfile ``` gem 'jwt' ``` And run `bundle install` ## Algorithms and Usage The JWT spec supports NONE, HMAC, RSASSA, ECDSA and RSASSA-PSS algorithms for cryptographic signing. Currently the jwt gem supports NONE, HMAC, RSASSA and ECDSA. If you are using cryptographic signing, you need to specify the algorithm in the options hash whenever you call JWT.decode to ensure that an attacker [cannot bypass the algorithm verification step](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). **It is strongly recommended that you hard code the algorithm, as you may leave yourself vulnerable by dynamically picking the algorithm** See: [ JSON Web Algorithms (JWA) 3.1. "alg" (Algorithm) Header Parameter Values for JWS](https://tools.ietf.org/html/rfc7518#section-3.1) **NONE** * none - unsigned token ```ruby require 'jwt' payload = { data: 'test' } # IMPORTANT: set nil as password parameter token = JWT.encode payload, nil, 'none' # eyJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9. puts token # Set password to nil and validation to false otherwise this won't work decoded_token = JWT.decode token, nil, false # Array # [ # {"data"=>"test"}, # payload # {"alg"=>"none"} # header # ] puts decoded_token ``` **HMAC** * HS256 - HMAC using SHA-256 hash algorithm * HS512256 - HMAC using SHA-512-256 hash algorithm (only available with RbNaCl; see note below) * HS384 - HMAC using SHA-384 hash algorithm * HS512 - HMAC using SHA-512 hash algorithm ```ruby hmac_secret = 'my$ecretK3y' token = JWT.encode payload, hmac_secret, 'HS256' # eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.pNIWIL34Jo13LViZAJACzK6Yf0qnvT_BuwOxiMCPE-Y puts token decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' } # Array # [ # {"data"=>"test"}, # payload # {"alg"=>"HS256"} # header # ] puts decoded_token # Without secret key token = JWT.encode payload, nil, 'HS256' # eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.pVzcY2dX8JNM3LzIYeP2B1e1Wcpt1K3TWVvIYSF4x-o puts token decoded_token = JWT.decode token, nil, true, { algorithm: 'HS256' } # Array # [ # {"data"=>"test"}, # payload # {"alg"=>"HS256"} # header # ] puts decoded_token ``` Note: If [RbNaCl](https://github.com/cryptosphere/rbnacl) is loadable, ruby-jwt will use it for HMAC-SHA256, HMAC-SHA512-256, and HMAC-SHA512. RbNaCl enforces a maximum key size of 32 bytes for these algorithms. [RbNaCl](https://github.com/cryptosphere/rbnacl) requires [libsodium](https://github.com/jedisct1/libsodium), it can be installed on MacOS with `brew install libsodium`. **RSA** * RS256 - RSA using SHA-256 hash algorithm * RS384 - RSA using SHA-384 hash algorithm * RS512 - RSA using SHA-512 hash algorithm ```ruby rsa_private = OpenSSL::PKey::RSA.generate 2048 rsa_public = rsa_private.public_key token = JWT.encode payload, rsa_private, 'RS256' # eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.GplO4w1spRgvEJQ3-FOtZr-uC8L45Jt7SN0J4woBnEXG_OZBSNcZjAJWpjadVYEe2ev3oUBFDYM1N_-0BTVeFGGYvMewu8E6aMjSZvOpf1cZBew-Vt4poSq7goG2YRI_zNPt3af2lkPqXD796IKC5URrEvcgF5xFQ-6h07XRDpSRx1ECrNsUOt7UM3l1IB4doY11GzwQA5sHDTmUZ0-kBT76ZMf12Srg_N3hZwphxBtudYtN5VGZn420sVrQMdPE_7Ni3EiWT88j7WCr1xrF60l8sZT3yKCVleG7D2BEXacTntB7GktBv4Xo8OKnpwpqTpIlC05dMowMkz3rEAAYbQ puts token decoded_token = JWT.decode token, rsa_public, true, { algorithm: 'RS256' } # Array # [ # {"data"=>"test"}, # payload # {"alg"=>"RS256"} # header # ] puts decoded_token ``` **ECDSA** * ES256 - ECDSA using P-256 and SHA-256 * ES384 - ECDSA using P-384 and SHA-384 * ES512 - ECDSA using P-521 and SHA-512 ```ruby ecdsa_key = OpenSSL::PKey::EC.new 'prime256v1' ecdsa_key.generate_key ecdsa_public = OpenSSL::PKey::EC.new ecdsa_key ecdsa_public.private_key = nil token = JWT.encode payload, ecdsa_key, 'ES256' # eyJhbGciOiJFUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.AlLW--kaF7EX1NMX9WJRuIW8NeRJbn2BLXHns7Q5TZr7Hy3lF6MOpMlp7GoxBFRLISQ6KrD0CJOrR8aogEsPeg puts token decoded_token = JWT.decode token, ecdsa_public, true, { algorithm: 'ES256' } # Array # [ # {"test"=>"data"}, # payload # {"alg"=>"ES256"} # header # ] puts decoded_token ``` **EDDSA** In order to use this algorithm you need to add the `RbNaCl` gem to you `Gemfile`. ```ruby gem 'rbnacl' ``` For more detailed installation instruction check the official [repository](https://github.com/cryptosphere/rbnacl) on GitHub. * ED25519 ```ruby private_key = RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF') public_key = private_key.verify_key token = JWT.encode payload, private_key, 'ED25519' # eyJhbGciOiJFRDI1NTE5In0.eyJkYXRhIjoidGVzdCJ9.6xIztXyOupskddGA_RvKU76V9b2dCQUYhoZEVFnRimJoPYIzZ2Fm47CWw8k2NTCNpgfAuxg9OXjaiVK7MvrbCQ puts token decoded_token = JWT.decode token, public_key, true, { algorithm: 'ED25519' } # Array # [ # {"test"=>"data"}, # payload # {"alg"=>"ED25519"} # header # ] ``` **RSASSA-PSS** In order to use this algorithm you need to add the `openssl` gem to you `Gemfile` with a version greater or equal to `2.1`. ```ruby gem 'openssl', '~> 2.1' ``` * PS256 - RSASSA-PSS using SHA-256 hash algorithm * PS384 - RSASSA-PSS using SHA-384 hash algorithm * PS512 - RSASSA-PSS using SHA-512 hash algorithm ```ruby rsa_private = OpenSSL::PKey::RSA.generate 2048 rsa_public = rsa_private.public_key token = JWT.encode payload, rsa_private, 'PS256' # eyJhbGciOiJQUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.KEmqagMUHM-NcmXo6818ZazVTIAkn9qU9KQFT1c5Iq91n0KRpAI84jj4ZCdkysDlWokFs3Dmn4MhcXP03oJKLFgnoPL40_Wgg9iFr0jnIVvnMUp1kp2RFUbL0jqExGTRA3LdAhuvw6ZByGD1bkcWjDXygjQw-hxILrT1bENjdr0JhFd-cB0-ps5SB0mwhFNcUw-OM3Uu30B1-mlFaelUY8jHJYKwLTZPNxHzndt8RGXF8iZLp7dGb06HSCKMcVzhASGMH4ZdFystRe2hh31cwcvnl-Eo_D4cdwmpN3Abhk_8rkxawQJR3duh8HNKc4AyFPo7SabEaSu2gLnLfN3yfg puts token decoded_token = JWT.decode token, rsa_public, true, { algorithm: 'PS256' } # Array # [ # {"data"=>"test"}, # payload # {"alg"=>"PS256"} # header # ] puts decoded_token ``` ## Support for reserved claim names JSON Web Token defines some reserved claim names and defines how they should be used. JWT supports these reserved claim names: - 'exp' (Expiration Time) Claim - 'nbf' (Not Before Time) Claim - 'iss' (Issuer) Claim - 'aud' (Audience) Claim - 'jti' (JWT ID) Claim - 'iat' (Issued At) Claim - 'sub' (Subject) Claim ## Add custom header fields Ruby-jwt gem supports custom [header fields](https://tools.ietf.org/html/rfc7519#section-5) To add custom header fields you need to pass `header_fields` parameter ```ruby token = JWT.encode payload, key, algorithm='HS256', header_fields={} ``` **Example:** ```ruby require 'jwt' payload = { data: 'test' } # IMPORTANT: set nil as password parameter token = JWT.encode payload, nil, 'none', { typ: 'JWT' } # eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJkYXRhIjoidGVzdCJ9. puts token # Set password to nil and validation to false otherwise this won't work decoded_token = JWT.decode token, nil, false # Array # [ # {"data"=>"test"}, # payload # {"typ"=>"JWT", "alg"=>"none"} # header # ] puts decoded_token ``` ### Expiration Time Claim From [Oauth JSON Web Token 4.1.4. "exp" (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4): > The `exp` (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing. The processing of the `exp` claim requires that the current date/time MUST be before the expiration date/time listed in the `exp` claim. Implementers MAY provide for some small `leeway`, usually no more than a few minutes, to account for clock skew. Its value MUST be a number containing a ***NumericDate*** value. Use of this claim is OPTIONAL. **Handle Expiration Claim** ```ruby exp = Time.now.to_i + 4 * 3600 exp_payload = { data: 'data', exp: exp } token = JWT.encode exp_payload, hmac_secret, 'HS256' begin decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' } rescue JWT::ExpiredSignature # Handle expired token, e.g. logout user or deny access end ``` **Adding Leeway** ```ruby exp = Time.now.to_i - 10 leeway = 30 # seconds exp_payload = { data: 'data', exp: exp } # build expired token token = JWT.encode exp_payload, hmac_secret, 'HS256' begin # add leeway to ensure the token is still accepted decoded_token = JWT.decode token, hmac_secret, true, { exp_leeway: leeway, algorithm: 'HS256' } rescue JWT::ExpiredSignature # Handle expired token, e.g. logout user or deny access end ``` ### Not Before Time Claim From [Oauth JSON Web Token 4.1.5. "nbf" (Not Before) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.5): > The `nbf` (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. The processing of the `nbf` claim requires that the current date/time MUST be after or equal to the not-before date/time listed in the `nbf` claim. Implementers MAY provide for some small `leeway`, usually no more than a few minutes, to account for clock skew. Its value MUST be a number containing a ***NumericDate*** value. Use of this claim is OPTIONAL. **Handle Not Before Claim** ```ruby nbf = Time.now.to_i - 3600 nbf_payload = { data: 'data', nbf: nbf } token = JWT.encode nbf_payload, hmac_secret, 'HS256' begin decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' } rescue JWT::ImmatureSignature # Handle invalid token, e.g. logout user or deny access end ``` **Adding Leeway** ```ruby nbf = Time.now.to_i + 10 leeway = 30 nbf_payload = { data: 'data', nbf: nbf } # build expired token token = JWT.encode nbf_payload, hmac_secret, 'HS256' begin # add leeway to ensure the token is valid decoded_token = JWT.decode token, hmac_secret, true, { nbf_leeway: leeway, algorithm: 'HS256' } rescue JWT::ImmatureSignature # Handle invalid token, e.g. logout user or deny access end ``` ### Issuer Claim From [Oauth JSON Web Token 4.1.1. "iss" (Issuer) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.1): > The `iss` (issuer) claim identifies the principal that issued the JWT. The processing of this claim is generally application specific. The `iss` value is a case-sensitive string containing a ***StringOrURI*** value. Use of this claim is OPTIONAL. You can pass multiple allowed issuers as an Array, verification will pass if one of them matches the `iss` value in the payload. ```ruby iss = 'My Awesome Company Inc. or https://my.awesome.website/' iss_payload = { data: 'data', iss: iss } token = JWT.encode iss_payload, hmac_secret, 'HS256' begin # Add iss to the validation to check if the token has been manipulated decoded_token = JWT.decode token, hmac_secret, true, { iss: iss, verify_iss: true, algorithm: 'HS256' } rescue JWT::InvalidIssuerError # Handle invalid token, e.g. logout user or deny access end ``` ### Audience Claim From [Oauth JSON Web Token 4.1.3. "aud" (Audience) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.3): > The `aud` (audience) claim identifies the recipients that the JWT is intended for. Each principal intended to process the JWT MUST identify itself with a value in the audience claim. If the principal processing the claim does not identify itself with a value in the `aud` claim when this claim is present, then the JWT MUST be rejected. In the general case, the `aud` value is an array of case-sensitive strings, each containing a ***StringOrURI*** value. In the special case when the JWT has one audience, the `aud` value MAY be a single case-sensitive string containing a ***StringOrURI*** value. The interpretation of audience values is generally application specific. Use of this claim is OPTIONAL. ```ruby aud = ['Young', 'Old'] aud_payload = { data: 'data', aud: aud } token = JWT.encode aud_payload, hmac_secret, 'HS256' begin # Add aud to the validation to check if the token has been manipulated decoded_token = JWT.decode token, hmac_secret, true, { aud: aud, verify_aud: true, algorithm: 'HS256' } rescue JWT::InvalidAudError # Handle invalid token, e.g. logout user or deny access puts 'Audience Error' end ``` ### JWT ID Claim From [Oauth JSON Web Token 4.1.7. "jti" (JWT ID) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.7): > The `jti` (JWT ID) claim provides a unique identifier for the JWT. The identifier value MUST be assigned in a manner that ensures that there is a negligible probability that the same value will be accidentally assigned to a different data object; if the application uses multiple issuers, collisions MUST be prevented among values produced by different issuers as well. The `jti` claim can be used to prevent the JWT from being replayed. The `jti` value is a case-sensitive string. Use of this claim is OPTIONAL. ```ruby # Use the secret and iat to create a unique key per request to prevent replay attacks jti_raw = [hmac_secret, iat].join(':').to_s jti = Digest::MD5.hexdigest(jti_raw) jti_payload = { data: 'data', iat: iat, jti: jti } token = JWT.encode jti_payload, hmac_secret, 'HS256' begin # If :verify_jti is true, validation will pass if a JTI is present #decoded_token = JWT.decode token, hmac_secret, true, { verify_jti: true, algorithm: 'HS256' } # Alternatively, pass a proc with your own code to check if the JTI has already been used decoded_token = JWT.decode token, hmac_secret, true, { verify_jti: proc { |jti| my_validation_method(jti) }, algorithm: 'HS256' } rescue JWT::InvalidJtiError # Handle invalid token, e.g. logout user or deny access puts 'Error' end ``` ### Issued At Claim From [Oauth JSON Web Token 4.1.6. "iat" (Issued At) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.6): > The `iat` (issued at) claim identifies the time at which the JWT was issued. This claim can be used to determine the age of the JWT. The `leeway` option is not taken into account when verifying this claim. The `iat_leeway` option was removed in version 2.2.0. Its value MUST be a number containing a ***NumericDate*** value. Use of this claim is OPTIONAL. **Handle Issued At Claim** ```ruby iat = Time.now.to_i iat_payload = { data: 'data', iat: iat } token = JWT.encode iat_payload, hmac_secret, 'HS256' begin # Add iat to the validation to check if the token has been manipulated decoded_token = JWT.decode token, hmac_secret, true, { verify_iat: true, algorithm: 'HS256' } rescue JWT::InvalidIatError # Handle invalid token, e.g. logout user or deny access end ``` ### Subject Claim From [Oauth JSON Web Token 4.1.2. "sub" (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2): > The `sub` (subject) claim identifies the principal that is the subject of the JWT. The Claims in a JWT are normally statements about the subject. The subject value MUST either be scoped to be locally unique in the context of the issuer or be globally unique. The processing of this claim is generally application specific. The sub value is a case-sensitive string containing a ***StringOrURI*** value. Use of this claim is OPTIONAL. ```ruby sub = 'Subject' sub_payload = { data: 'data', sub: sub } token = JWT.encode sub_payload, hmac_secret, 'HS256' begin # Add sub to the validation to check if the token has been manipulated decoded_token = JWT.decode token, hmac_secret, true, { sub: sub, verify_sub: true, algorithm: 'HS256' } rescue JWT::InvalidSubError # Handle invalid token, e.g. logout user or deny access end ``` ### JSON Web Key (JWK) JWK is a JSON structure representing a cryptographic key. Currently only supports RSA public keys. ```ruby jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048)) payload, headers = { data: 'data' }, { kid: jwk.kid } token = JWT.encode(payload, jwk.keypair, 'RS512', headers) # The jwk loader would fetch the set of JWKs from a trusted source jwk_loader = ->(options) do @cached_keys = nil if options[:invalidate] # need to reload the keys @cached_keys ||= { keys: [jwk.export] } end begin JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwk_loader}) rescue JWT::JWKError # Handle problems with the provided JWKs rescue JWT::DecodeError # Handle other decode related issues e.g. no kid in header, no matching public key found etc. end ``` # Development and Tests We depend on [Bundler](http://rubygems.org/gems/bundler) for defining gemspec and performing releases to rubygems.org, which can be done with ```bash rake release ``` The tests are written with rspec. Given you have installed the dependencies via bundler, you can run tests with ```bash bundle exec rspec ``` **If you want a release cut with your PR, please include a version bump according to [Semantic Versioning](http://semver.org/)** ## Contributors See `AUTHORS` file. ## License See `LICENSE` file. ruby-jwt-2.2.2/Rakefile000066400000000000000000000003721371667752300147700ustar00rootroot00000000000000require 'bundler/gem_tasks' begin require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:test) task default: :test rescue LoadError puts 'RSpec rake tasks not available. Please run "bundle install" to install missing dependencies.' end ruby-jwt-2.2.2/bin/000077500000000000000000000000001371667752300140715ustar00rootroot00000000000000ruby-jwt-2.2.2/bin/console.rb000077500000000000000000000005231371667752300160630ustar00rootroot00000000000000#!/usr/bin/env ruby require "bundler/setup" require "jwt" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start(__FILE__) ruby-jwt-2.2.2/gemfiles/000077500000000000000000000000001371667752300151145ustar00rootroot00000000000000ruby-jwt-2.2.2/gemfiles/rails_5.0.gemfile000066400000000000000000000001641371667752300201430ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 5.0.0" gemspec path: "../" ruby-jwt-2.2.2/gemfiles/rails_5.1.gemfile000066400000000000000000000001641371667752300201440ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 5.1.0" gemspec path: "../" ruby-jwt-2.2.2/gemfiles/rails_5.2.gemfile000066400000000000000000000001641371667752300201450ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 5.2.0" gemspec path: "../" ruby-jwt-2.2.2/gemfiles/rails_6.0.gemfile000066400000000000000000000001641371667752300201440ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 6.0.0" gemspec path: "../" ruby-jwt-2.2.2/gemfiles/standalone.gemfile000066400000000000000000000001331371667752300205730ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gemspec path: "../" ruby-jwt-2.2.2/lib/000077500000000000000000000000001371667752300140675ustar00rootroot00000000000000ruby-jwt-2.2.2/lib/jwt.rb000066400000000000000000000013571371667752300152260ustar00rootroot00000000000000# frozen_string_literal: true require 'jwt/base64' require 'jwt/json' require 'jwt/decode' require 'jwt/default_options' require 'jwt/encode' require 'jwt/error' require 'jwt/jwk' # JSON Web Token implementation # # Should be up to date with the latest spec: # https://tools.ietf.org/html/rfc7519 module JWT include JWT::DefaultOptions module_function def encode(payload, key, algorithm = 'HS256', header_fields = {}) Encode.new(payload: payload, key: key, algorithm: algorithm, headers: header_fields).segments end def decode(jwt, key = nil, verify = true, options = {}, &keyfinder) Decode.new(jwt, key, verify, DEFAULT_OPTIONS.merge(options), &keyfinder).decode_segments end end ruby-jwt-2.2.2/lib/jwt/000077500000000000000000000000001371667752300146735ustar00rootroot00000000000000ruby-jwt-2.2.2/lib/jwt/algos/000077500000000000000000000000001371667752300160005ustar00rootroot00000000000000ruby-jwt-2.2.2/lib/jwt/algos/ecdsa.rb000066400000000000000000000023411371667752300174040ustar00rootroot00000000000000module JWT module Algos module Ecdsa module_function SUPPORTED = %w[ES256 ES384 ES512].freeze NAMED_CURVES = { 'prime256v1' => 'ES256', 'secp384r1' => 'ES384', 'secp521r1' => 'ES512' }.freeze def sign(to_sign) algorithm, msg, key = to_sign.values key_algorithm = NAMED_CURVES[key.group.curve_name] if algorithm != key_algorithm raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided" end digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha')) SecurityUtils.asn1_to_raw(key.dsa_sign_asn1(digest.digest(msg)), key) end def verify(to_verify) algorithm, public_key, signing_input, signature = to_verify.values key_algorithm = NAMED_CURVES[public_key.group.curve_name] if algorithm != key_algorithm raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided" end digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha')) public_key.dsa_verify_asn1(digest.digest(signing_input), SecurityUtils.raw_to_asn1(signature, public_key)) end end end end ruby-jwt-2.2.2/lib/jwt/algos/eddsa.rb000066400000000000000000000020741371667752300174100ustar00rootroot00000000000000module JWT module Algos module Eddsa module_function SUPPORTED = %w[ED25519].freeze def sign(to_sign) algorithm, msg, key = to_sign.values raise EncodeError, "Key given is a #{key.class} but has to be an RbNaCl::Signatures::Ed25519::SigningKey" if key.class != RbNaCl::Signatures::Ed25519::SigningKey raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key.primitive} signing key was provided" if algorithm.downcase.to_sym != key.primitive key.sign(msg) end def verify(to_verify) algorithm, public_key, signing_input, signature = to_verify.values raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{public_key.primitive} verification key was provided" if algorithm.downcase.to_sym != public_key.primitive raise DecodeError, "key given is a #{public_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey" if public_key.class != RbNaCl::Signatures::Ed25519::VerifyKey public_key.verify(signature, signing_input) end end end end ruby-jwt-2.2.2/lib/jwt/algos/hmac.rb000066400000000000000000000021401371667752300172320ustar00rootroot00000000000000module JWT module Algos module Hmac module_function SUPPORTED = %w[HS256 HS512256 HS384 HS512].freeze def sign(to_sign) algorithm, msg, key = to_sign.values key ||= '' authenticator, padded_key = SecurityUtils.rbnacl_fixup(algorithm, key) if authenticator && padded_key authenticator.auth(padded_key, msg.encode('binary')) else OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg) end end def verify(to_verify) algorithm, public_key, signing_input, signature = to_verify.values authenticator, padded_key = SecurityUtils.rbnacl_fixup(algorithm, public_key) if authenticator && padded_key begin authenticator.verify(padded_key, signature.encode('binary'), signing_input.encode('binary')) rescue RbNaCl::BadAuthenticatorError false end else SecurityUtils.secure_compare(signature, sign(JWT::Signature::ToSign.new(algorithm, signing_input, public_key))) end end end end end ruby-jwt-2.2.2/lib/jwt/algos/ps.rb000066400000000000000000000023121371667752300167450ustar00rootroot00000000000000module JWT module Algos module Ps # RSASSA-PSS signing algorithms module_function SUPPORTED = %w[PS256 PS384 PS512].freeze def sign(to_sign) require_openssl! algorithm, msg, key = to_sign.values key_class = key.class raise EncodeError, "The given key is a #{key_class}. It has to be an OpenSSL::PKey::RSA instance." if key_class == String translated_algorithm = algorithm.sub('PS', 'sha') key.sign_pss(translated_algorithm, msg, salt_length: :digest, mgf1_hash: translated_algorithm) end def verify(to_verify) require_openssl! SecurityUtils.verify_ps(to_verify.algorithm, to_verify.public_key, to_verify.signing_input, to_verify.signature) end def require_openssl! if Object.const_defined?('OpenSSL') major, minor = OpenSSL::VERSION.split('.').first(2) unless major.to_i >= 2 && minor.to_i >= 1 raise JWT::RequiredDependencyError, "You currently have OpenSSL #{OpenSSL::VERSION}. PS support requires >= 2.1" end else raise JWT::RequiredDependencyError, 'PS signing requires OpenSSL +2.1' end end end end end ruby-jwt-2.2.2/lib/jwt/algos/rsa.rb000066400000000000000000000010731371667752300171130ustar00rootroot00000000000000module JWT module Algos module Rsa module_function SUPPORTED = %w[RS256 RS384 RS512].freeze def sign(to_sign) algorithm, msg, key = to_sign.values raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance." if key.class == String key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg) end def verify(to_verify) SecurityUtils.verify_rsa(to_verify.algorithm, to_verify.public_key, to_verify.signing_input, to_verify.signature) end end end end ruby-jwt-2.2.2/lib/jwt/algos/unsupported.rb000066400000000000000000000005721371667752300207210ustar00rootroot00000000000000module JWT module Algos module Unsupported module_function SUPPORTED = Object.new.tap { |object| object.define_singleton_method(:include?) { |*| true } } def verify(*) raise JWT::VerificationError, 'Algorithm not supported' end def sign(*) raise NotImplementedError, 'Unsupported signing method' end end end end ruby-jwt-2.2.2/lib/jwt/base64.rb000066400000000000000000000005511371667752300163050ustar00rootroot00000000000000# frozen_string_literal: true require 'base64' module JWT # Base64 helpers class Base64 class << self def url_encode(str) ::Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '') end def url_decode(str) str += '=' * (4 - str.length.modulo(4)) ::Base64.decode64(str.tr('-_', '+/')) end end end end ruby-jwt-2.2.2/lib/jwt/claims_validator.rb000066400000000000000000000012141371667752300205330ustar00rootroot00000000000000require_relative './error' module JWT class ClaimsValidator INTEGER_CLAIMS = %i[ exp iat nbf ].freeze def initialize(payload) @payload = payload.each_with_object({}) { |(k, v), h| h[k.to_sym] = v } end def validate! validate_int_claims true end private def validate_int_claims INTEGER_CLAIMS.each do |claim| validate_is_int(claim) if @payload.key?(claim) end end def validate_is_int(claim) raise InvalidPayload, "#{claim} claim must be an Integer but it is a #{@payload[claim].class}" unless @payload[claim].is_a?(Integer) end end end ruby-jwt-2.2.2/lib/jwt/decode.rb000066400000000000000000000054071371667752300164510ustar00rootroot00000000000000# frozen_string_literal: true require 'json' require 'jwt/signature' require 'jwt/verify' # JWT::Decode module module JWT # Decoding logic for JWT class Decode def initialize(jwt, key, verify, options, &keyfinder) raise(JWT::DecodeError, 'Nil JSON web token') unless jwt @jwt = jwt @key = key @options = options @segments = jwt.split('.') @verify = verify @signature = '' @keyfinder = keyfinder end def decode_segments validate_segment_count! if @verify decode_crypto verify_signature verify_claims end raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload [payload, header] end private def verify_signature raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') if allowed_algorithms.empty? raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') unless options_includes_algo_in_header? @key = find_key(&@keyfinder) if @keyfinder @key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks]).key_for(header['kid']) if @options[:jwks] Signature.verify(header['alg'], @key, signing_input, @signature) end def options_includes_algo_in_header? allowed_algorithms.include? header['alg'] end def allowed_algorithms # Order is very important - first check for string keys, next for symbols if @options.key?('algorithm') [@options['algorithm']] elsif @options.key?(:algorithm) [@options[:algorithm]] elsif @options.key?('algorithms') @options['algorithms'] || [] elsif @options.key?(:algorithms) @options[:algorithms] || [] else [] end end def find_key(&keyfinder) key = (keyfinder.arity == 2 ? yield(header, payload) : yield(header)) raise JWT::DecodeError, 'No verification key available' unless key key end def verify_claims Verify.verify_claims(payload, @options) end def validate_segment_count! return if segment_length == 3 return if !@verify && segment_length == 2 # If no verifying required, the signature is not needed raise(JWT::DecodeError, 'Not enough or too many segments') end def segment_length @segments.count end def decode_crypto @signature = JWT::Base64.url_decode(@segments[2]) end def header @header ||= parse_and_decode @segments[0] end def payload @payload ||= parse_and_decode @segments[1] end def signing_input @segments.first(2).join('.') end def parse_and_decode(segment) JWT::JSON.parse(JWT::Base64.url_decode(segment)) rescue ::JSON::ParserError raise JWT::DecodeError, 'Invalid segment encoding' end end end ruby-jwt-2.2.2/lib/jwt/default_options.rb000066400000000000000000000004721371667752300204220ustar00rootroot00000000000000module JWT module DefaultOptions DEFAULT_OPTIONS = { verify_expiration: true, verify_not_before: true, verify_iss: false, verify_iat: false, verify_jti: false, verify_aud: false, verify_sub: false, leeway: 0, algorithms: ['HS256'] }.freeze end end ruby-jwt-2.2.2/lib/jwt/encode.rb000066400000000000000000000027261371667752300164640ustar00rootroot00000000000000# frozen_string_literal: true require_relative './claims_validator' # JWT::Encode module module JWT # Encoding logic for JWT class Encode ALG_NONE = 'none'.freeze ALG_KEY = 'alg'.freeze def initialize(options) @payload = options[:payload] @key = options[:key] @algorithm = options[:algorithm] @headers = options[:headers].each_with_object({}) { |(key, value), headers| headers[key.to_s] = value } end def segments @segments ||= combine(encoded_header_and_payload, encoded_signature) end private def encoded_header @encoded_header ||= encode_header end def encoded_payload @encoded_payload ||= encode_payload end def encoded_signature @encoded_signature ||= encode_signature end def encoded_header_and_payload @encoded_header_and_payload ||= combine(encoded_header, encoded_payload) end def encode_header @headers[ALG_KEY] = @algorithm encode(@headers) end def encode_payload if @payload && @payload.is_a?(Hash) ClaimsValidator.new(@payload).validate! end encode(@payload) end def encode_signature return '' if @algorithm == ALG_NONE JWT::Base64.url_encode(JWT::Signature.sign(@algorithm, encoded_header_and_payload, @key)) end def encode(data) JWT::Base64.url_encode(JWT::JSON.generate(data)) end def combine(*parts) parts.join('.') end end end ruby-jwt-2.2.2/lib/jwt/error.rb000066400000000000000000000012231371667752300163470ustar00rootroot00000000000000# frozen_string_literal: true module JWT class EncodeError < StandardError; end class DecodeError < StandardError; end class RequiredDependencyError < StandardError; end class VerificationError < DecodeError; end class ExpiredSignature < DecodeError; end class IncorrectAlgorithm < DecodeError; end class ImmatureSignature < DecodeError; end class InvalidIssuerError < DecodeError; end class InvalidIatError < DecodeError; end class InvalidAudError < DecodeError; end class InvalidSubError < DecodeError; end class InvalidJtiError < DecodeError; end class InvalidPayload < DecodeError; end class JWKError < DecodeError; end end ruby-jwt-2.2.2/lib/jwt/json.rb000066400000000000000000000003711371667752300161720ustar00rootroot00000000000000# frozen_string_literal: true require 'json' module JWT # JSON wrapper class JSON class << self def generate(data) ::JSON.generate(data) end def parse(data) ::JSON.parse(data) end end end end ruby-jwt-2.2.2/lib/jwt/jwk.rb000066400000000000000000000013451371667752300160160ustar00rootroot00000000000000# frozen_string_literal: true require_relative 'jwk/rsa' require_relative 'jwk/key_finder' module JWT module JWK MAPPINGS = { 'RSA' => ::JWT::JWK::RSA, OpenSSL::PKey::RSA => ::JWT::JWK::RSA }.freeze class << self def import(jwk_data) raise JWT::JWKError, 'Key type (kty) not provided' unless jwk_data[:kty] MAPPINGS.fetch(jwk_data[:kty].to_s) do |kty| raise JWT::JWKError, "Key type #{kty} not supported" end.import(jwk_data) end def create_from(keypair) MAPPINGS.fetch(keypair.class) do |klass| raise JWT::JWKError, "Cannot create JWK from a #{klass.name}" end.new(keypair) end alias new create_from end end end ruby-jwt-2.2.2/lib/jwt/jwk/000077500000000000000000000000001371667752300154665ustar00rootroot00000000000000ruby-jwt-2.2.2/lib/jwt/jwk/key_finder.rb000066400000000000000000000021721371667752300201340ustar00rootroot00000000000000# frozen_string_literal: true module JWT module JWK class KeyFinder def initialize(options) jwks_or_loader = options[:jwks] @jwks = jwks_or_loader if jwks_or_loader.is_a?(Hash) @jwk_loader = jwks_or_loader if jwks_or_loader.respond_to?(:call) end def key_for(kid) raise ::JWT::DecodeError, 'No key id (kid) found from token headers' unless kid jwk = resolve_key(kid) raise ::JWT::DecodeError, "Could not find public key for kid #{kid}" unless jwk ::JWT::JWK.import(jwk).keypair end private def resolve_key(kid) jwk = find_key(kid) return jwk if jwk if reloadable? load_keys(invalidate: true) return find_key(kid) end nil end def jwks return @jwks if @jwks load_keys @jwks end def load_keys(opts = {}) @jwks = @jwk_loader.call(opts) end def find_key(kid) Array(jwks[:keys]).find { |key| key[:kid] == kid } end def reloadable? @jwk_loader end end end end ruby-jwt-2.2.2/lib/jwt/jwk/rsa.rb000066400000000000000000000027771371667752300166150ustar00rootroot00000000000000# frozen_string_literal: true module JWT module JWK class RSA attr_reader :keypair BINARY = 2 KTY = 'RSA'.freeze def initialize(keypair) raise ArgumentError, 'keypair must be of type OpenSSL::PKey::RSA' unless keypair.is_a?(OpenSSL::PKey::RSA) @keypair = keypair end def private? keypair.private? end def public_key keypair.public_key end def kid sequence = OpenSSL::ASN1::Sequence([OpenSSL::ASN1::Integer.new(public_key.n), OpenSSL::ASN1::Integer.new(public_key.e)]) OpenSSL::Digest::SHA256.hexdigest(sequence.to_der) end def export { kty: KTY, n: ::Base64.urlsafe_encode64(public_key.n.to_s(BINARY), padding: false), e: ::Base64.urlsafe_encode64(public_key.e.to_s(BINARY), padding: false), kid: kid } end def self.import(jwk_data) imported_key = OpenSSL::PKey::RSA.new if imported_key.respond_to?(:set_key) imported_key.set_key(OpenSSL::BN.new(::Base64.urlsafe_decode64(jwk_data[:n]), BINARY), OpenSSL::BN.new(::Base64.urlsafe_decode64(jwk_data[:e]), BINARY), nil) else imported_key.n = OpenSSL::BN.new(::Base64.urlsafe_decode64(jwk_data[:n]), BINARY) imported_key.e = OpenSSL::BN.new(::Base64.urlsafe_decode64(jwk_data[:e]), BINARY) end self.new(imported_key) end end end end ruby-jwt-2.2.2/lib/jwt/security_utils.rb000066400000000000000000000036661371667752300203220ustar00rootroot00000000000000module JWT # Collection of security methods # # @see: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/security_utils.rb module SecurityUtils module_function def secure_compare(left, right) left_bytesize = left.bytesize return false unless left_bytesize == right.bytesize unpacked_left = left.unpack "C#{left_bytesize}" result = 0 right.each_byte { |byte| result |= byte ^ unpacked_left.shift } result.zero? end def verify_rsa(algorithm, public_key, signing_input, signature) public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input) end def verify_ps(algorithm, public_key, signing_input, signature) formatted_algorithm = algorithm.sub('PS', 'sha') public_key.verify_pss(formatted_algorithm, signature, signing_input, salt_length: :auto, mgf1_hash: formatted_algorithm) end def asn1_to_raw(signature, public_key) byte_size = (public_key.group.degree + 7) / 8 OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join end def raw_to_asn1(signature, private_key) byte_size = (private_key.group.degree + 7) / 8 sig_bytes = signature[0..(byte_size - 1)] sig_char = signature[byte_size..-1] || '' OpenSSL::ASN1::Sequence.new([sig_bytes, sig_char].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der end def rbnacl_fixup(algorithm, key) algorithm = algorithm.sub('HS', 'SHA').to_sym return [] unless defined?(RbNaCl) && RbNaCl::HMAC.constants(false).include?(algorithm) authenticator = RbNaCl::HMAC.const_get(algorithm) # Fall back to OpenSSL for keys larger than 32 bytes. return [] if key.bytesize > authenticator.key_bytes [ authenticator, key.bytes.fill(0, key.bytesize...authenticator.key_bytes).pack('C*') ] end end end ruby-jwt-2.2.2/lib/jwt/signature.rb000066400000000000000000000026211371667752300172220ustar00rootroot00000000000000# frozen_string_literal: true require 'jwt/security_utils' require 'openssl' require 'jwt/algos/hmac' require 'jwt/algos/eddsa' require 'jwt/algos/ecdsa' require 'jwt/algos/rsa' require 'jwt/algos/ps' require 'jwt/algos/unsupported' begin require 'rbnacl' rescue LoadError raise if defined?(RbNaCl) end # JWT::Signature module module JWT # Signature logic for JWT module Signature extend self ALGOS = [ Algos::Hmac, Algos::Ecdsa, Algos::Rsa, Algos::Eddsa, Algos::Ps, Algos::Unsupported ].freeze ToSign = Struct.new(:algorithm, :msg, :key) ToVerify = Struct.new(:algorithm, :public_key, :signing_input, :signature) def sign(algorithm, msg, key) algo = ALGOS.find do |alg| alg.const_get(:SUPPORTED).include? algorithm end algo.sign ToSign.new(algorithm, msg, key) end def verify(algorithm, key, signing_input, signature) raise JWT::DecodeError, 'No verification key available' unless key algo = ALGOS.find do |alg| alg.const_get(:SUPPORTED).include? algorithm end verified = algo.verify(ToVerify.new(algorithm, key, signing_input, signature)) raise(JWT::VerificationError, 'Signature verification raised') unless verified rescue OpenSSL::PKey::PKeyError raise JWT::VerificationError, 'Signature verification raised' ensure OpenSSL.errors.clear end end end ruby-jwt-2.2.2/lib/jwt/verify.rb000066400000000000000000000053421371667752300165300ustar00rootroot00000000000000# frozen_string_literal: true require 'jwt/error' module JWT # JWT verify methods class Verify DEFAULTS = { leeway: 0 }.freeze class << self %w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub].each do |method_name| define_method method_name do |payload, options| new(payload, options).send(method_name) end end def verify_claims(payload, options) options.each do |key, val| next unless key.to_s =~ /verify/ Verify.send(key, payload, options) if val end end end def initialize(payload, options) @payload = payload @options = DEFAULTS.merge(options) end def verify_aud return unless (options_aud = @options[:aud]) aud = @payload['aud'] raise(JWT::InvalidAudError, "Invalid audience. Expected #{options_aud}, received #{aud || ''}") if ([*aud] & [*options_aud]).empty? end def verify_expiration return unless @payload.include?('exp') raise(JWT::ExpiredSignature, 'Signature has expired') if @payload['exp'].to_i <= (Time.now.to_i - exp_leeway) end def verify_iat return unless @payload.include?('iat') iat = @payload['iat'] raise(JWT::InvalidIatError, 'Invalid iat') if !iat.is_a?(Numeric) || iat.to_f > Time.now.to_f end def verify_iss return unless (options_iss = @options[:iss]) iss = @payload['iss'] return if Array(options_iss).map(&:to_s).include?(iss.to_s) raise(JWT::InvalidIssuerError, "Invalid issuer. Expected #{options_iss}, received #{iss || ''}") end def verify_jti options_verify_jti = @options[:verify_jti] jti = @payload['jti'] if options_verify_jti.respond_to?(:call) verified = options_verify_jti.arity == 2 ? options_verify_jti.call(jti, @payload) : options_verify_jti.call(jti) raise(JWT::InvalidJtiError, 'Invalid jti') unless verified elsif jti.to_s.strip.empty? raise(JWT::InvalidJtiError, 'Missing jti') end end def verify_not_before return unless @payload.include?('nbf') raise(JWT::ImmatureSignature, 'Signature nbf has not been reached') if @payload['nbf'].to_i > (Time.now.to_i + nbf_leeway) end def verify_sub return unless (options_sub = @options[:sub]) sub = @payload['sub'] raise(JWT::InvalidSubError, "Invalid subject. Expected #{options_sub}, received #{sub || ''}") unless sub.to_s == options_sub.to_s end private def global_leeway @options[:leeway] end def exp_leeway @options[:exp_leeway] || global_leeway end def nbf_leeway @options[:nbf_leeway] || global_leeway end end end ruby-jwt-2.2.2/lib/jwt/version.rb000066400000000000000000000007041371667752300167060ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true # Moments version builder module module JWT def self.gem_version Gem::Version.new VERSION::STRING end # Moments version builder module module VERSION # major version MAJOR = 2 # minor version MINOR = 2 # tiny version TINY = 2 # alpha, beta, etc. tag PRE = nil # Build version string STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end end ruby-jwt-2.2.2/ruby-jwt.gemspec000066400000000000000000000024601371667752300164530ustar00rootroot00000000000000lib = File.expand_path('../lib/', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'jwt/version' Gem::Specification.new do |spec| spec.name = 'jwt' spec.version = JWT.gem_version spec.authors = [ 'Tim Rudat' ] spec.email = 'timrudat@gmail.com' spec.summary = 'JSON Web Token implementation in Ruby' spec.description = 'A pure ruby implementation of the RFC 7519 OAuth JSON Web Token (JWT) standard.' spec.homepage = 'https://github.com/jwt/ruby-jwt' spec.license = 'MIT' spec.required_ruby_version = '>= 2.1' spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|gemfiles|coverage|bin)/}) } spec.executables = [] spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = %w[lib] spec.add_development_dependency 'appraisal' spec.add_development_dependency 'bundler' spec.add_development_dependency 'rake' spec.add_development_dependency 'rspec' spec.add_development_dependency 'simplecov', '< 0.18' spec.add_development_dependency 'simplecov-json' spec.add_development_dependency 'codeclimate-test-reporter' spec.add_development_dependency 'codacy-coverage' spec.add_development_dependency 'rbnacl' # RSASSA-PSS support provided by OpenSSL +2.1 spec.add_development_dependency 'openssl', '~> 2.1' end ruby-jwt-2.2.2/spec/000077500000000000000000000000001371667752300142535ustar00rootroot00000000000000ruby-jwt-2.2.2/spec/fixtures/000077500000000000000000000000001371667752300161245ustar00rootroot00000000000000ruby-jwt-2.2.2/spec/fixtures/certs/000077500000000000000000000000001371667752300172445ustar00rootroot00000000000000ruby-jwt-2.2.2/spec/fixtures/certs/ec256-private.pem000066400000000000000000000004561371667752300222500ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BggqhkjOPQMBBw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIJmVse5uPfj6B4TcXrUAvf9/8pJh+KrKKYLNcmOnp/vPoAoGCCqGSM49 AwEHoUQDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc/DX1wuhIMu8dQzOLSt0tpqK9 MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w== -----END EC PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec256-public.pem000066400000000000000000000002621371667752300220470ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc /DX1wuhIMu8dQzOLSt0tpqK9MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w== -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec256-wrong-private.pem000066400000000000000000000004461371667752300234010ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQACg== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MHQCAQEEICfA4AaomONdmPTzeyrx5U/jugYXTERyb5U3ETTv7Hx7oAcGBSuBBAAK oUQDQgAEPmuXZT3jpJnEMVPOW6RMsmxeGLOCE1PN6fwvUwOsxv7YnyoQ5/bpo64n +Jp4slSl1aUNoCBF2oz9bS0iyBo3jg== -----END EC PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec256-wrong-public.pem000066400000000000000000000002561371667752300232040ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPmuXZT3jpJnEMVPOW6RMsmxeGLOCE1PN 6fwvUwOsxv7YnyoQ5/bpo64n+Jp4slSl1aUNoCBF2oz9bS0iyBo3jg== -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec384-private.pem000066400000000000000000000005471371667752300222530ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQAIg== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIGkAgEBBDDxOljqUKw9YNhkluSJIBAYO1YXcNtS+vckd5hpTZ5toxsOlwbmyrnU Tn+D5Xma1m2gBwYFK4EEACKhZANiAASQwYTiRvXu1hMHceSosMs/8uf50sJI3jvK kdSkvuRAPxSzhtrUvCQDnVsThFq4aOdZZY1qh2ErJGtzmrx+pEsJvJnvfOTG3NGU KRalek+LQfVqAUSvDMKlxdkz2e67tso= -----END EC PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec384-public.pem000066400000000000000000000003271371667752300220530ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkMGE4kb17tYTB3HkqLDLP/Ln+dLCSN47 ypHUpL7kQD8Us4ba1LwkA51bE4RauGjnWWWNaodhKyRrc5q8fqRLCbyZ73zkxtzR lCkWpXpPi0H1agFErwzCpcXZM9nuu7bK -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec384-wrong-private.pem000066400000000000000000000005471371667752300234050ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQAIg== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIGkAgEBBDAfZW47dSKnC5JkSVOk1ERxCIi/IJ1p1WBnVGx4hnrNHy+dxtaZJaF+ YLInFQ/QbYegBwYFK4EEACKhZANiAAQwXkx4BFBGLXbzl5yVrfxK7er8hSi38iDE K2+7cdrR137Wn5JUnL4WTwXTzkyUgfBOL3sHNozwfgU03GD/EOUEKqzsIJiz2cbP bFALd4hS+8T4szDLVC9Jl1W6k0CAtmM= -----END EC PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec384-wrong-public.pem000066400000000000000000000003271371667752300232050ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEMF5MeARQRi1285ecla38Su3q/IUot/Ig xCtvu3Ha0dd+1p+SVJy+Fk8F085MlIHwTi97BzaM8H4FNNxg/xDlBCqs7CCYs9nG z2xQC3eIUvvE+LMwy1QvSZdVupNAgLZj -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec512-private.pem000066400000000000000000000006641371667752300222440ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQAIw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIHcAgEBBEIB0/+ffxEj7j62xvGaB5pvzk888e412ESO/EK/K0QlS9dSF8+Rj1rG zqpRB8fvDnoe8xdmkW/W5GKzojMyv7YQYumgBwYFK4EEACOhgYkDgYYABAEw74Yw aTbPY6TtWmxx6LJDzCX2nKWCPnKdZcEH9Ncu8g5RjRBRq2yacja3OoS6nA2YeDng reBJxZr376P6Ns6XcQFWDA6K/MCTrEBCsPxXZNxd8KR9vMGWhgNtWRrcKzwJfQkr suyehZkbbYyFnAWyARKHZuV7VUXmeEmRS/f93MPqVA== -----END EC PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec512-public.pem000066400000000000000000000004141371667752300220410ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBMO+GMGk2z2Ok7VpsceiyQ8wl9pyl gj5ynWXBB/TXLvIOUY0QUatsmnI2tzqEupwNmHg54K3gScWa9++j+jbOl3EBVgwO ivzAk6xAQrD8V2TcXfCkfbzBloYDbVka3Cs8CX0JK7LsnoWZG22MhZwFsgESh2bl e1VF5nhJkUv3/dzD6lQ= -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec512-wrong-private.pem000066400000000000000000000006601371667752300233720ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQAIw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIHbAgEBBEG/KbA2oCbiCT6L3V8XSz2WKBy0XhGvIFbl/ZkXIXnkYt+1B7wViSVo KCHuMFsi6xU/5nE1EuDG2UsQJmKeAMkIOKAHBgUrgQQAI6GBiQOBhgAEAG0TFWe5 cZ5DZIyfuysrCoQySTNxd+aT8sPIxsx7mW6YBTsuO6rEgxyegd2Auy4xtikxpzKv soMXR02999Aaus2jAAt/wxrhhr41BDP4MV0b6Zngb72hna0pcGqit5OyU8AbOJUZ +rdyowRGsOY+aPbOyVhdNcsEdxYC8GdIyCQLBC1H -----END EC PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/ec512-wrong-public.pem000066400000000000000000000004141371667752300231730ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAbRMVZ7lxnkNkjJ+7KysKhDJJM3F3 5pPyw8jGzHuZbpgFOy47qsSDHJ6B3YC7LjG2KTGnMq+ygxdHTb330Bq6zaMAC3/D GuGGvjUEM/gxXRvpmeBvvaGdrSlwaqK3k7JTwBs4lRn6t3KjBEaw5j5o9s7JWF01 ywR3FgLwZ0jIJAsELUc= -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/rsa-1024-private.pem000066400000000000000000000015731371667752300225760ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDO/ahgFDvniFoQ1dm+MdnkBi+Ts5W9AtQNgw4ZHIdPnqEzSgW7 0opKEu8hnlLqsIyU2BC2op/xOanipdbXObuFlA6bth1cYRI+YJlR3BbPGOIL6YbJ ud9m0gIsBlCDLm4e/E45ZS+emudISP7/SF7zxvxZlnr1z7HTm7nIIVBvuQIDAQAB AoGBAMzFQAccvU6GI6O4C5sOsiHUxMh3xtCftaxQVGgfQvVPVuXoeteep1Q0ewFl IV4vnkO5pH8pTtVTWG9x5KIy6QCql4qvr2jkOm4mo9uogrpNklvBl2lN4Lxubj0N mGRXaM3hckZl8+JT6uzfBfjy+pd8AOigJGPQCOZn4gmANW7pAkEA82Nh4wpj6ZRU NBiBq3ONZuH4xJm59MI2FWRJsGUFUYdSaFwyKKim52/13d8iUb7v9utWQFRatCXz Lqw9fQyVrwJBANm3dBOVxpUPrYEQsG0q2rdP+u6U3woylxwtQgJxImZKZmmJlPr8 9v23rhydvCe1ERPYe7EjF4RGWVPN3KLdExcCQDdzNfL3BApMS97OkoRQQC/nXbjU 2SPlN1MqVQuGCG8pqGG0V40h11y1CkvxMS10ldEojq77SOrwFnZUsXGS82sCQQC6 XdO7QCaxSq5XIRYlHN4EtS40NLOIYy3/LK6osHel4GIyTVd+UjSLk0QzssJxqwln V5TqWQO0cxPcLQiFUYEZAkEA2G84ilb9QXOgbNyoE1VifNk49hhodbSskLb86uwY Vgtzq1ZsqoPBCasr4WRiXt270n+mo5dNYRlZwiUn9lH78Q== -----END RSA PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/rsa-1024-public.pem000066400000000000000000000004201371667752300223700ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO/ahgFDvniFoQ1dm+MdnkBi+T s5W9AtQNgw4ZHIdPnqEzSgW70opKEu8hnlLqsIyU2BC2op/xOanipdbXObuFlA6b th1cYRI+YJlR3BbPGOIL6YbJud9m0gIsBlCDLm4e/E45ZS+emudISP7/SF7zxvxZ lnr1z7HTm7nIIVBvuQIDAQAB -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/rsa-2048-private.pem000066400000000000000000000032171371667752300226020ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA4GzZTLU48c4WbyvHi+QKrB71x+T0eq5hqDbQqnlYjhD1Ika7 io1iplsdJWJuyxfYbUkb2Ol0fj4koZ/GS6lgCZr4+8UHbr1qf0Eu5HZSpszs2YxY 8U5RHnrpw67co7hlgAR9HbyNf5XIYgLV9ldHH/eazwnc3F/hgNsV0xjScVilejgo cJ4zcsyymvW8t42lteM7bI867ZuJhGop/V+Y0HFyrMsPoQyLuCUpr6ulOfrkr7ZO dhAIG8r1HcjOp/AUjM15vfXcbUZjkM/VloifX1YitU3upMGJ8/DpFGffMOImrn5r 6BT494V8rRyN2qvQoAkLJpqZ0avLxwiR2lgVQQIDAQABAoIBAEH0Ozgr2fxWEInD V/VooypKPvjr9F1JejGxSkmPN9MocKIOH3dsbZ1uEXa3ItBUxan4XlK06SNgp+tH xULfF/Y6sQlsse59hBq50Uoa69dRShn1AP6JgZVvkduMPBNxUYL5zrs6emsQXb9Q DglDRQfEAJ7vyxSIqQDxYcyT8uSUF70dqFe+E9B2VE3D6ccHc98k41pJrAFAUFH1 wwvDhfyYr7/Ultut9wzpZvU1meF3Vna3GOUHfxrG6wu1G+WIWHGjouzThsc1qiVI BtMCJxuCt5fOXRbU4STbMqhB6sZHiOh6J/dZU6JwRYt+IS8FB6kCNFSEWZWQledJ XqtYSQECgYEA9nmnFTRj3fTBq9zMXfCRujkSy6X2bOb39ftNXzHFuc+I6xmv/3Bs P9tDdjueP/SnCb7i/9hXkpEIcxjrjiqgcvD2ym1hE4q+odMzRAXYMdnmzI34SVZE U5hYJcYsXNKrTTleba7QgqdORmyJ9FwqLO40udvmrZMY223XDwgRkOkCgYEA6RkO 5wjjrWWp/G1YN3KXZTS1m2/eGrUThohXKAfAjbWWiouNLW2msXrxEWsPRL6xKiHu X9cwZwzi3MstAgk+bphUGUVUkGKNDjWHJA25tDYjbPtkd6xbL4eCHsKpNL3HNYr9 N0CIvgn7qjaHRBem0iK7T6keY4axaSVddEwYapkCgYEA13K5qaB1F4Smcpt8DTWH vPe8xUUaZlFzOJLmLCsuwmB2N8Ppg2j7RspcaxJsH021YaB5ftjWm+ipMSr8ZPY/ 8JlPsNzxuYpTXtNmAbT2KYVm6THEch61dTk6/DIBf1YrpUJbl5by7vJeStL/uBmE SGgksL5XIyzs0opuLdaIvFkCgYAyBLWE8AxjFfCvAQuwAj/ocLITo6KmWnrRIIqL RXaVMgUWv7FQsTnW1cnK8g05tC2yG8vZ9wQk6Mf5lwOWb0NdWgSZ0528ydj41pWk L+nMeN2LMjqxz2NVxJ8wWJcUgTCxFZ0WcRumo9/D+6V1ABpE9zz4cBLcSnfhVypB nV6T6QKBgQCSZNCQ9HPxjAgYcsqc5sjNwuN1GHQZSav3Tye3k6zHENe1lsteT9K8 xciGIuhybKZBvB4yImIIHCtnH+AS+mHAGqHarjNDMfvjOq0dMibPx4+bkIiHdBIH Xz+j5kmntvFiUnzr0Z/Tcqo+r8FvyCo1YWgwqGP8XoFrswD7gy7cZw== -----END RSA PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/rsa-2048-public.pem000066400000000000000000000007031371667752300224030ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4GzZTLU48c4WbyvHi+QK rB71x+T0eq5hqDbQqnlYjhD1Ika7io1iplsdJWJuyxfYbUkb2Ol0fj4koZ/GS6lg CZr4+8UHbr1qf0Eu5HZSpszs2YxY8U5RHnrpw67co7hlgAR9HbyNf5XIYgLV9ldH H/eazwnc3F/hgNsV0xjScVilejgocJ4zcsyymvW8t42lteM7bI867ZuJhGop/V+Y 0HFyrMsPoQyLuCUpr6ulOfrkr7ZOdhAIG8r1HcjOp/AUjM15vfXcbUZjkM/Vloif X1YitU3upMGJ8/DpFGffMOImrn5r6BT494V8rRyN2qvQoAkLJpqZ0avLxwiR2lgV QQIDAQAB -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/rsa-2048-wrong-private.pem000066400000000000000000000032171371667752300237340ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAzHAVGaW9j4l3/b4ngcjjoIoIcnsQEWOMqErb5VhLZMGIq1gE O5qxPDAwooKsNotzcAOB3ZyLn7p5D+dmOrNUYkYWgYITNGeSifrnVqQugd5Fh1L8 K7zOGltUo2UtjbN4uJ56tzxBMZp2wejs2/Qu0eu0xZK3To+YkDcWOk92rmNgmUSQ C/kNyIOj+yBvOo3wTk6HvbhoIarCgJ6Lay1v/hMLyQLzwRY/Qfty1FTIDyTv2dch 47FsfkZ1KAL+MbUnHuCBPzGxRjXa8Iy9Z7YGxrYasUt1b0um64bscxoIiCu8yLL8 jlg01Rwrjr/MTwKRhwXlMp8B7HTonwtaG6arJwIDAQABAoIBAGFR4dmJusl/qW1T fj8cQLAFxaupxaZhe24J5NAyzgEy2Dqo9ariIwkB78UM66ozjEqAgOvcP+NTw5m8 kD/VapA1yTTxlO7XdzzUAhiOo80S4IphCMZRZNPLMmluGtdf3lIUr1pXBrn0TCBX H5o9jaREzpNXGof9d6T/dEdh2J9+uE/p1xE5GSxQfaPheZzCG7636La/DcArg/UR +TusPqp62BEmk96pE/KKJRmEeH+WnPfSh6sMpLxi3hkEU7AynpliGT6Z6xV4csBI S/rdpkcj5DWpbnQzkwdrnL2Q+POEq/vlx5/NlezvtQPNLvQWDyY4yBCoMKGb3EbX xrxP7MECgYEA/kwe4P0Mqk+087IyhjDBGPfcMt8gfYc9nzNfIYSWdSwuSag/hqHq I4GwHQzUV9ix3iM6w5hin10yAzWxCYZg9hquV+lSvNNpGB76FX6oOqwuAhyQMRwv eW+VUyfFXeJugwL5JuIaNTvwPpQVDHYtELLifie+uzJ5HC6dhg/XchcCgYEAzc5/ +IXjOlExd/mBgFk/5Y87ifA0ZOgbaJXifYgU0aNSgz1piHxU3n2p4jJ9lSdwwCl2 Fb5EN7666t20PL5QcXJ5ZdaTRLzRlYiqTWzfYHBgttbB1Jl3Ed9GsKuzRgaRqGFC ANJSqZlKG0NZ3keRtuKdFwq+IVOnsQr9g0TZiXECgYEAqUgtCiMKCloTIGMQpSnR cXiWWjsUmturls4Q1vQ3YHrvuVLKLyqb/dT4Uu5WcMAs765OESThCit0/pQAbVHK PCpYwubskAzAGjGM00BEZwJ1gixXhIm5xMIWCowgI7Z3ULlq+IptXeCvtkjHlksZ BtO+WLLGkkEwRCV38WWcSzMCgYA/Xxqgl/mD94RYAQgTUWgPc69Nph08BQyLg7ue E8z1UGkT6FEaqc4oRGGPOSTaTK63PQ0TXOb8k0pTD7l0CtYSWMFwzkXCoLGYbeCi vqd5tqDRLAe7QxYa9rl5pSUqptMrGeeNATZa6sya4H5Hp5oCyny8n54z/OJh7ZRq W0TwwQKBgQDDP7ksm2pcqadaVAmODdOlaDHbaEcxp8wN7YVz0lM3UpJth96ukbj7 S39eJhXYWOn6oJQb/lN9fGOYqjg3y6IchGZDp67ATvWYvn/NY0R7mt4K4oHx5TuN rSQlP3WmOGv8Kemw892uRfW/jZyBEHhsfS213WDttVPn9F635GdNWw== -----END RSA PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/rsa-2048-wrong-public.pem000066400000000000000000000007031371667752300235350ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzHAVGaW9j4l3/b4ngcjj oIoIcnsQEWOMqErb5VhLZMGIq1gEO5qxPDAwooKsNotzcAOB3ZyLn7p5D+dmOrNU YkYWgYITNGeSifrnVqQugd5Fh1L8K7zOGltUo2UtjbN4uJ56tzxBMZp2wejs2/Qu 0eu0xZK3To+YkDcWOk92rmNgmUSQC/kNyIOj+yBvOo3wTk6HvbhoIarCgJ6Lay1v /hMLyQLzwRY/Qfty1FTIDyTv2dch47FsfkZ1KAL+MbUnHuCBPzGxRjXa8Iy9Z7YG xrYasUt1b0um64bscxoIiCu8yLL8jlg01Rwrjr/MTwKRhwXlMp8B7HTonwtaG6ar JwIDAQAB -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/rsa-4096-private.pem000066400000000000000000000062531371667752300226120ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIJJwIBAAKCAgEAqETmgWBi5rCmb7euJplA/9xs65+bncc9Yvs5zjyycXSW82Jf RuyguGm0OvA2wog24dR4N2kT/87DcGtp5JqJWADVFNr+2V2r6i57/OMLruRpn3p2 r95dmo0COE+BxPFl7XEBT8JbH57ZtpgcB3/xkS14nLOWFf96hrXPlXJC+VMVKVZm A8k2LRh42vT5wUf4U0Doy/p7yFNSFFa6Q8wwe4TBy/z/f+rhFD1w8rxlYjallee/ ocm7bjZCwbJGMm7orLViqWfsFX3O35PeoJ5h/7uJ7iRwvTFERkTdwWP/0BeKBeIt BR3YFc2mut+V9W+WKRkMSL6Crc+oVSx3p8aB7j9SZFzQiRtes4BYETpX1xl2mgIq 5hvsFbLw7ESrlIodiwUMTrSIid2DQ6q80kv1zXPr4+Id6L0sJLxPCaXnTmNtasSw yedJJYxLjwhHJwtzFAeaq18H3O791YKhjAJ6YxK3zJ59jTE6Pkvqjq183f2PGHVR vgSN7aCmI6MBUUB5wDP2K8zX2sh40/uPDVSd6ei1vl3DpPk+h8iExx6AzbohfqZ+ 5RUUNx127L3MaQvOVC5TxV+R99gwKW++wzcVuO3m2KqVUj+K1uYBy3KBCUMBbckp EWGbN++jcdV5oJX6fsC66nOmKlntYwCL/pRww+oLsbzF8J3dxeDbKNF9JDsCAwEA AQKCAgBJF8TZJjlP5CQoGy227pNhkSpvH6HFY6qyuFZf09XfmrmHd4/Tiy41bRUx FO90iR7t8hFWYHqjf/k9eCtDdi164MGukYJqgVoQG6kYLLgCfI21DMlJk9otLFtu gnroRcP05EWhk9dpYONJgcGLMHSKj6n4x7nGTHe41HkbfcrB6ukiT7l4o4q5BAxb cFadMtoXr/ZvxJrIZgkddJ7snGHjBcP5DCkgM7MZy6aoilWv1/UNrOF9MdgNA9zz rrD3b136x7/XvqC6pS+bxuvJ8YK4R4qeu42NYT07GOcK/pk8lz0JWTodIt2eevqV 6lGFj7c2mv7PCpJRVgbVGL/RTVVap/+jbcRVLdnYKsII/dANG7iXnfwRgkLWet5D OOsPuvIuyiSaJIwcdRE3SSO+tZhKLt+gh/oLxBPw5Ex0FwsVTtYn3Q/X3EAx+Wph eFcRr3TVkDg0MfdWWkgk16DvYB5cWc29coTaH1g+2juadNHbtVAigwJorKc6sxH3 QGsW0WQJ8ZRZgJkSUuu3nr7QD3ZrgHptONQAh1RWGnIWi6OlMfaPdMo+SDnnL5SG mpOPjWadDc1XvMFnKQYMYB5GWU/ZNmnZmDLyg1Pc0Y+qRUc0s83nZFHN60KnUrSz 0MZDspSFtr0fMx0b2/EB4EbuXd3QjQURF6P6HtWBu6oFnzu1AQKCAQEA2R9BKJgJ vNP+DUu8NBzwmi0cKlAiaxt+w90i5DWq1XWPKgi+RVLkaQSJqHoYQVNgEwL/cWxp s2r3GCMNIdOrGdcm8dX/6UYFpRaFcViTycVEA7cwZOMppgqr2Q+ZYX42K7HObUVL JGvdEWWWfSsynUGsrG87DC1gl94ANxCdqkZdbW5d3X0w5v7M/1tlrmAeskZSZpeT 8BwwM6REb0U/B4/i8TLtLi/PGmMTOIxW41uKS/S6kq/gwyv+jNNO0ljhPt25iSbV K5ZHS4YuPKLl0tZMaOkPco9s6t4ES/Y317zQoTzUkAAkkFO4QPzRZL0ESqVBNR0h Ao7FLmFZzFHpoQKCAQEAxmZBn0UrJLXkD7bw66y4RwzjQYmxLlkEl3uvjrvVSuL1 mAHDW58aGIpFFZ8QSTtNewIBQYNifp/cdFHAagqtl/iMGEegaOpJAKu/ykrkfZUp 7mYDNng4ZWpypeKaGMAQoNzZiUpF+BDnqbeb/kgYu6sNlh9gRHR79rgAuZQxZ/1B tE8WcUFi4CnTq2QLqX4LwMuZHWXAJQoMoW3K5av+J544lIM6GdMJuIONtBBkKVQD ErrJ0bqYeykrFS6pKl/NBCZLGo5xFFRiYEdZ1GlA3uW3EGKppz6PS7194+x5UVts xZPUfkgdFjWCczkl4JDoWfaNn5sgXtiVbGh1n3gYWwKCAQB7vHEg1kyuXU4qe5/d PyTraIvlnVeQHNJIgy0QS3l5Pw8A0IzG6y+anehpqHNMP1zAWPQEytkOVAZPriIc xgl7p37dUa0PX0V2SPhxmR5YXeCeEXc197PTmb9H67jos8nhauqOoW/qaMJK2M9D tCubLUNf3eAT14R16CHNP93qnUE/TSeXQ3JsIofne0neb47u4F6zcuzvaNEbjSEn HJqID7sw5GoA6WQo0I+yqWAXICMXmHf/gtYfxGHEFeSUwexULH5BKG1R8sncw7J0 Ag3h8xkGrNON4SkcTLy8Iay/eS6YxRcKndo4mk2mU65tr77TX4xi3Z/jWkQLY5WO eJwhAoIBABO17wkSxyGDjJ/fDfpsE3bDmgRV2KuBHoqqOBvXH26sM7ghXLZKjT4o 5ooqXmTYJm91GIjYs71exnkr8hDW9L4nbEuxOgeSVyRg69H+NMshOaQ8sE8GDJxO wgsnAyY4Vq6UomwYW/E0RL/AxRezM/nZGaVzgo3qgLJXP4MwbOQm7hMq1FD2LQuW PDhH3Ty+kA5ca97W0Asd/3k+Pi0pNDvdZUOj8e7E369cKoTcKAdPGGsQ8aILhsCd q3EUTKwwDl8+KrH9utBJPejQzeTjfBVo/xH6q145QeVFcy9ku/zQN3M9p5vQMEuX j1lBMTkpTFw7uYBE2idyHw5BJoZsWQcCggEADfZTChqnOncItSflzGoaAACrr4/x KyT/4A+cPMCs11JN9J+EWsCezya2o1l/NF7YPcBR4qjCmFMEiq5GxH5fGLQp0aa7 V13mHA8XBQ25OW2K7BGJhMHdbuvTnl6jsOfC4+t7P2bUAYxoP6/ncxTzZ5OlBN5k aMv9firWl1kSKK75ww9DWn6j0rQ4dBetwX45EMcs+iKIdydg0fmJxR2EJ+uQsCFy xcWBEDqV7qLUi6UrAPL3v/DXUv9wKcKOTbKw/aNE8+YTWMUO330GCJ5cVU1eTL5t UrcNKOJkFIj7jJUCzv6vcy++hMJEbNXnnTVRnky6e9C2vwzMl33njntapg== -----END RSA PRIVATE KEY----- ruby-jwt-2.2.2/spec/fixtures/certs/rsa-4096-public.pem000066400000000000000000000014401371667752300224070ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqETmgWBi5rCmb7euJplA /9xs65+bncc9Yvs5zjyycXSW82JfRuyguGm0OvA2wog24dR4N2kT/87DcGtp5JqJ WADVFNr+2V2r6i57/OMLruRpn3p2r95dmo0COE+BxPFl7XEBT8JbH57ZtpgcB3/x kS14nLOWFf96hrXPlXJC+VMVKVZmA8k2LRh42vT5wUf4U0Doy/p7yFNSFFa6Q8ww e4TBy/z/f+rhFD1w8rxlYjallee/ocm7bjZCwbJGMm7orLViqWfsFX3O35PeoJ5h /7uJ7iRwvTFERkTdwWP/0BeKBeItBR3YFc2mut+V9W+WKRkMSL6Crc+oVSx3p8aB 7j9SZFzQiRtes4BYETpX1xl2mgIq5hvsFbLw7ESrlIodiwUMTrSIid2DQ6q80kv1 zXPr4+Id6L0sJLxPCaXnTmNtasSwyedJJYxLjwhHJwtzFAeaq18H3O791YKhjAJ6 YxK3zJ59jTE6Pkvqjq183f2PGHVRvgSN7aCmI6MBUUB5wDP2K8zX2sh40/uPDVSd 6ei1vl3DpPk+h8iExx6AzbohfqZ+5RUUNx127L3MaQvOVC5TxV+R99gwKW++wzcV uO3m2KqVUj+K1uYBy3KBCUMBbckpEWGbN++jcdV5oJX6fsC66nOmKlntYwCL/pRw w+oLsbzF8J3dxeDbKNF9JDsCAwEAAQ== -----END PUBLIC KEY----- ruby-jwt-2.2.2/spec/integration/000077500000000000000000000000001371667752300165765ustar00rootroot00000000000000ruby-jwt-2.2.2/spec/integration/readme_examples_spec.rb000066400000000000000000000156321371667752300232770ustar00rootroot00000000000000# frozen_string_literal: true require_relative '../spec_helper' require 'jwt' describe 'README.md code test' do context 'algorithm usage' do let(:payload) { { data: 'test' } } it 'NONE' do token = JWT.encode payload, nil, 'none' decoded_token = JWT.decode token, nil, false expect(token).to eq 'eyJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.' expect(decoded_token).to eq [ { 'data' => 'test' }, { 'alg' => 'none' } ] end it 'decodes with HMAC algorithm with secret key' do token = JWT.encode payload, 'my$ecretK3y', 'HS256' decoded_token = JWT.decode token, 'my$ecretK3y', false expect(token).to eq 'eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.pNIWIL34Jo13LViZAJACzK6Yf0qnvT_BuwOxiMCPE-Y' expect(decoded_token).to eq [ { 'data' => 'test' }, { 'alg' => 'HS256' } ] end it 'decodes with HMAC algorithm without secret key' do token = JWT.encode payload, nil, 'HS256' decoded_token = JWT.decode token, nil, false expect(token).to eq 'eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.pVzcY2dX8JNM3LzIYeP2B1e1Wcpt1K3TWVvIYSF4x-o' expect(decoded_token).to eq [ { 'data' => 'test' }, { 'alg' => 'HS256' } ] end it 'RSA' do rsa_private = OpenSSL::PKey::RSA.generate 2048 rsa_public = rsa_private.public_key token = JWT.encode payload, rsa_private, 'RS256' decoded_token = JWT.decode token, rsa_public, true, algorithm: 'RS256' expect(decoded_token).to eq [ { 'data' => 'test' }, { 'alg' => 'RS256' } ] end it 'ECDSA' do ecdsa_key = OpenSSL::PKey::EC.new 'prime256v1' ecdsa_key.generate_key ecdsa_public = OpenSSL::PKey::EC.new ecdsa_key ecdsa_public.private_key = nil token = JWT.encode payload, ecdsa_key, 'ES256' decoded_token = JWT.decode token, ecdsa_public, true, algorithm: 'ES256' expect(decoded_token).to eq [ { 'data' => 'test' }, { 'alg' => 'ES256' } ] end it 'RSASSA-PSS' do rsa_private = OpenSSL::PKey::RSA.generate 2048 rsa_public = rsa_private.public_key token = JWT.encode payload, rsa_private, 'PS256' decoded_token = JWT.decode token, rsa_public, true, algorithm: 'PS256' expect(decoded_token).to eq [ { 'data' => 'test' }, { 'alg' => 'PS256' } ] end end context 'claims' do let(:hmac_secret) { 'MyP4ssW0rD' } context 'exp' do it 'without leeway' do exp = Time.now.to_i + 4 * 3600 exp_payload = { data: 'data', exp: exp } token = JWT.encode exp_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, algorithm: 'HS256' end.not_to raise_error end it 'with leeway' do exp = Time.now.to_i - 10 leeway = 30 # seconds exp_payload = { data: 'data', exp: exp } token = JWT.encode exp_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, leeway: leeway, algorithm: 'HS256' end.not_to raise_error end end context 'nbf' do it 'without leeway' do nbf = Time.now.to_i - 3600 nbf_payload = { data: 'data', nbf: nbf } token = JWT.encode nbf_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, algorithm: 'HS256' end.not_to raise_error end it 'with leeway' do nbf = Time.now.to_i + 10 leeway = 30 nbf_payload = { data: 'data', nbf: nbf } token = JWT.encode nbf_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, leeway: leeway, algorithm: 'HS256' end.not_to raise_error end end it 'iss' do iss = 'My Awesome Company Inc. or https://my.awesome.website/' iss_payload = { data: 'data', iss: iss } token = JWT.encode iss_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, iss: iss, algorithm: 'HS256' end.not_to raise_error end context 'aud' do it 'array' do aud = %w[Young Old] aud_payload = { data: 'data', aud: aud } token = JWT.encode aud_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, aud: %w[Old Young], verify_aud: true, algorithm: 'HS256' end.not_to raise_error end it 'string' do aud = 'Kids' aud_payload = { data: 'data', aud: aud } token = JWT.encode aud_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, aud: 'Kids', verify_aud: true, algorithm: 'HS256' end.not_to raise_error end end it 'jti' do iat = Time.now.to_i hmac_secret = 'test' jti_raw = [hmac_secret, iat].join(':').to_s jti = Digest::MD5.hexdigest(jti_raw) jti_payload = { data: 'data', iat: iat, jti: jti } token = JWT.encode jti_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, verify_jti: true, algorithm: 'HS256' end.not_to raise_error end context 'iat' do it 'without leeway' do iat = Time.now.to_i iat_payload = { data: 'data', iat: iat } token = JWT.encode iat_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, verify_iat: true, algorithm: 'HS256' end.not_to raise_error end it 'with leeway' do iat = Time.now.to_i - 7 iat_payload = { data: 'data', iat: iat, leeway: 10 } token = JWT.encode iat_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, verify_iat: true, algorithm: 'HS256' end.not_to raise_error end end context 'custom header fields' do it 'with custom field' do payload = { data: 'test' } token = JWT.encode payload, nil, 'none', typ: 'JWT' _, header = JWT.decode token, nil, false expect(header['typ']).to eq 'JWT' end end it 'sub' do sub = 'Subject' sub_payload = { data: 'data', sub: sub } token = JWT.encode sub_payload, hmac_secret, 'HS256' expect do JWT.decode token, hmac_secret, true, 'sub' => sub, :verify_sub => true, :algorithm => 'HS256' end.not_to raise_error end it 'JWK' do jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048)) payload, headers = { data: 'data' }, { kid: jwk.kid } token = JWT.encode(payload, jwk.keypair, 'RS512', headers) # The jwk loader would fetch the set of JWKs from a trusted source jwk_loader = ->(options) do @cached_keys = nil if options[:invalidate] # need to reload the keys @cached_keys ||= { keys: [jwk.export] } end expect do JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwk_loader}) end.not_to raise_error end end end ruby-jwt-2.2.2/spec/jwk/000077500000000000000000000000001371667752300150465ustar00rootroot00000000000000ruby-jwt-2.2.2/spec/jwk/decode_with_jwk_spec.rb000066400000000000000000000051471371667752300215450ustar00rootroot00000000000000# frozen_string_literal: true require_relative '../spec_helper' require 'jwt' describe JWT do describe '.decode for JWK usecase' do let(:keypair) { OpenSSL::PKey::RSA.new(2048) } let(:jwk) { JWT::JWK.new(keypair) } let(:public_jwks) { { keys: [jwk.export, { kid: 'not_the_correct_one' }] } } let(:token_payload) { {'data' => 'something'} } let(:token_headers) { { kid: jwk.kid } } let(:signed_token) { described_class.encode(token_payload, jwk.keypair, 'RS512', token_headers) } context 'when JWK features are used manually' do it 'is able to decode the token' do payload, _header = described_class.decode(signed_token, nil, true, { algorithms: ['RS512'] }) do |header, _payload| JWT::JWK.import(public_jwks[:keys].find { |key| key[:kid] == header['kid'] }).keypair end expect(payload).to eq(token_payload) end end context 'when jwk keys are given as an array' do context 'and kid is in the set' do it 'is able to decode the token' do payload, _header = described_class.decode(signed_token, nil, true, { algorithms: ['RS512'], jwks: public_jwks}) expect(payload).to eq(token_payload) end end context 'and kid is not in the set' do before do public_jwks[:keys].first[:kid] = 'NOT_A_MATCH' end it 'raises an exception' do expect { described_class.decode(signed_token, nil, true, { algorithms: ['RS512'], jwks: public_jwks}) }.to raise_error( JWT::DecodeError, /Could not find public key for kid .*/ ) end end context 'token does not know the kid' do let(:token_headers) { {} } it 'raises an exception' do expect { described_class.decode(signed_token, nil, true, { algorithms: ['RS512'], jwks: public_jwks}) }.to raise_error( JWT::DecodeError, 'No key id (kid) found from token headers' ) end end end context 'when jwk keys are loaded using a proc/lambda' do it 'decodes the token' do payload, _header = described_class.decode(signed_token, nil, true, { algorithms: ['RS512'], jwks: lambda { |_opts| public_jwks }}) expect(payload).to eq(token_payload) end end context 'when jwk keys are rotated' do it 'decodes the token' do key_loader = ->(options) { options[:invalidate] ? public_jwks : { keys: [] } } payload, _header = described_class.decode(signed_token, nil, true, { algorithms: ['RS512'], jwks: key_loader}) expect(payload).to eq(token_payload) end end end end ruby-jwt-2.2.2/spec/jwk/rsa_spec.rb000066400000000000000000000032171371667752300171750ustar00rootroot00000000000000# frozen_string_literal: true require_relative '../spec_helper' require 'jwt' describe JWT::JWK::RSA do let(:rsa_key) { OpenSSL::PKey::RSA.new(2048) } describe '.new' do subject { described_class.new(keypair) } context 'when a keypair with both keys given' do let(:keypair) { rsa_key } it 'creates an instance of the class' do expect(subject).to be_a described_class expect(subject.private?).to eq true end end context 'when a keypair with only public key is given' do let(:keypair) { rsa_key.public_key } it 'creates an instance of the class' do expect(subject).to be_a described_class expect(subject.private?).to eq false end end end describe '#export' do subject { described_class.new(keypair).export } context 'when keypair with private key is exported' do let(:keypair) { rsa_key } it 'returns a hash with the public parts of the key' do expect(subject).to be_a Hash expect(subject).to include(:kty, :n, :e, :kid) expect(subject).not_to include(:d) end end context 'when keypair with public key is exported' do let(:keypair) { rsa_key.public_key } it 'returns a hash with the public parts of the key' do expect(subject).to be_a Hash expect(subject).to include(:kty, :n, :e, :kid) expect(subject).not_to include(:d) end end context 'when unsupported keypair is given' do let(:keypair) { 'key' } it 'raises an error' do expect { subject }.to raise_error(ArgumentError, 'keypair must be of type OpenSSL::PKey::RSA') end end end end ruby-jwt-2.2.2/spec/jwk_spec.rb000066400000000000000000000021021371667752300164000ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'jwt' describe JWT::JWK do let(:rsa_key) { OpenSSL::PKey::RSA.new(2048) } describe '.import' do let(:keypair) { rsa_key.public_key } let(:params) { described_class.new(keypair).export } subject { described_class.import(params) } it 'creates a ::JWT::JWK::RSA instance' do expect(subject).to be_a ::JWT::JWK::RSA expect(subject.export).to eq(params) end context 'when keytype is not supported' do let(:params) { { kty: 'unsupported' } } it 'raises an error' do expect { subject }.to raise_error(JWT::JWKError) end end end describe '.to_jwk' do subject { described_class.new(keypair) } context 'when RSA key is given' do let(:keypair) { rsa_key } it { is_expected.to be_a ::JWT::JWK::RSA } end context 'when unsupported key is given' do let(:keypair) { 'key' } it 'raises an error' do expect { subject }.to raise_error(::JWT::JWKError, 'Cannot create JWK from a String') end end end end ruby-jwt-2.2.2/spec/jwt/000077500000000000000000000000001371667752300150575ustar00rootroot00000000000000ruby-jwt-2.2.2/spec/jwt/claims_validator_spec.rb000066400000000000000000000026701371667752300217400ustar00rootroot00000000000000require 'spec_helper' require 'jwt/claims_validator' RSpec.describe JWT::ClaimsValidator do describe '#validate!' do it 'returns true if the payload is valid' do valid_payload = { 'exp' => 12345 } subject = described_class.new(valid_payload) expect(subject.validate!).to eq(true) end shared_examples_for 'an integer claim' do |claim| it "raises an error when the value of the #{claim} claim is a string" do subject = described_class.new({ claim => '1' }) expect { subject.validate! }.to raise_error JWT::InvalidPayload end it "raises an error when the value of the #{claim} claim is a Time object" do subject = described_class.new({ claim => Time.now }) expect { subject.validate! }.to raise_error JWT::InvalidPayload end it "validates the #{claim} claim when the key is either a string or a symbol" do symbol = described_class.new({ claim.to_sym => true }) expect { symbol.validate! }.to raise_error JWT::InvalidPayload string = described_class.new({ claim.to_s => true }) expect { string.validate! }.to raise_error JWT::InvalidPayload end end context 'exp claim' do it_should_behave_like 'an integer claim', :exp end context 'iat claim' do it_should_behave_like 'an integer claim', :iat end context 'nbf claim' do it_should_behave_like 'an integer claim', :nbf end end end ruby-jwt-2.2.2/spec/jwt/verify_spec.rb000066400000000000000000000203011371667752300177160ustar00rootroot00000000000000# frozen_string_literal: true require 'spec_helper' require 'jwt/verify' module JWT RSpec.describe Verify do let(:base_payload) { { 'user_id' => 'some@user.tld' } } let(:options) { { leeway: 0 } } context '.verify_aud(payload, options)' do let(:scalar_aud) { 'ruby-jwt-aud' } let(:array_aud) { %w[ruby-jwt-aud test-aud ruby-ruby-ruby] } let(:scalar_payload) { base_payload.merge('aud' => scalar_aud) } let(:array_payload) { base_payload.merge('aud' => array_aud) } it 'must raise JWT::InvalidAudError when the singular audience does not match' do expect do Verify.verify_aud(scalar_payload, options.merge(aud: 'no-match')) end.to raise_error JWT::InvalidAudError end it 'must raise JWT::InvalidAudError when the payload has an array and none match the supplied value' do expect do Verify.verify_aud(array_payload, options.merge(aud: 'no-match')) end.to raise_error JWT::InvalidAudError end it 'must allow a matching singular audience to pass' do Verify.verify_aud(scalar_payload, options.merge(aud: scalar_aud)) end it 'must allow an array with any value matching the one in the options' do Verify.verify_aud(array_payload, options.merge(aud: array_aud.first)) end it 'must allow an array with any value matching any value in the options array' do Verify.verify_aud(array_payload, options.merge(aud: array_aud)) end it 'must allow a singular audience payload matching any value in the options array' do Verify.verify_aud(scalar_payload, options.merge(aud: array_aud)) end end context '.verify_expiration(payload, options)' do let(:payload) { base_payload.merge('exp' => (Time.now.to_i - 5)) } it 'must raise JWT::ExpiredSignature when the token has expired' do expect do Verify.verify_expiration(payload, options) end.to raise_error JWT::ExpiredSignature end it 'must allow some leeway in the expiration when global leeway is configured' do Verify.verify_expiration(payload, options.merge(leeway: 10)) end it 'must allow some leeway in the expiration when exp_leeway is configured' do Verify.verify_expiration(payload, options.merge(exp_leeway: 10)) end it 'must be expired if the exp claim equals the current time' do payload['exp'] = Time.now.to_i expect do Verify.verify_expiration(payload, options) end.to raise_error JWT::ExpiredSignature end context 'when leeway is not specified' do let(:options) { {} } it 'used a default leeway of 0' do expect do Verify.verify_expiration(payload, options) end.to raise_error JWT::ExpiredSignature end end end context '.verify_iat(payload, options)' do let(:iat) { Time.now.to_f } let(:payload) { base_payload.merge('iat' => iat) } it 'must allow a valid iat' do Verify.verify_iat(payload, options) end it 'must ignore configured leeway' do expect{Verify.verify_iat(payload.merge('iat' => (iat + 60)), options.merge(leeway: 70)) } .to raise_error(JWT::InvalidIatError) end it 'must properly handle integer times' do Verify.verify_iat(payload.merge('iat' => Time.now.to_i), options) end it 'must raise JWT::InvalidIatError when the iat value is not Numeric' do expect do Verify.verify_iat(payload.merge('iat' => 'not a number'), options) end.to raise_error JWT::InvalidIatError end it 'must raise JWT::InvalidIatError when the iat value is in the future' do expect do Verify.verify_iat(payload.merge('iat' => (iat + 120)), options) end.to raise_error JWT::InvalidIatError end end context '.verify_iss(payload, options)' do let(:iss) { 'ruby-jwt-gem' } let(:payload) { base_payload.merge('iss' => iss) } let(:invalid_token) { JWT.encode base_payload, payload[:secret] } context 'when iss is a String' do it 'must raise JWT::InvalidIssuerError when the configured issuer does not match the payload issuer' do expect do Verify.verify_iss(payload, options.merge(iss: 'mismatched-issuer')) end.to raise_error JWT::InvalidIssuerError end it 'must raise JWT::InvalidIssuerError when the payload does not include an issuer' do expect do Verify.verify_iss(base_payload, options.merge(iss: iss)) end.to raise_error(JWT::InvalidIssuerError, /received /) end it 'must allow a matching issuer to pass' do Verify.verify_iss(payload, options.merge(iss: iss)) end end context 'when iss is an Array' do it 'must raise JWT::InvalidIssuerError when no matching issuers in array' do expect do Verify.verify_iss(payload, options.merge(iss: %w[first second])) end.to raise_error JWT::InvalidIssuerError end it 'must raise JWT::InvalidIssuerError when the payload does not include an issuer' do expect do Verify.verify_iss(base_payload, options.merge(iss: %w[first second])) end.to raise_error(JWT::InvalidIssuerError, /received /) end it 'must allow an array with matching issuer to pass' do Verify.verify_iss(payload, options.merge(iss: ['first', iss, 'third'])) end end end context '.verify_jti(payload, options)' do let(:payload) { base_payload.merge('jti' => 'some-random-uuid-or-whatever') } it 'must allow any jti when the verfy_jti key in the options is truthy but not a proc' do Verify.verify_jti(payload, options.merge(verify_jti: true)) end it 'must raise JWT::InvalidJtiError when the jti is missing' do expect do Verify.verify_jti(base_payload, options) end.to raise_error JWT::InvalidJtiError, /missing/i end it 'must raise JWT::InvalidJtiError when the jti is an empty string' do expect do Verify.verify_jti(base_payload.merge('jti' => ' '), options) end.to raise_error JWT::InvalidJtiError, /missing/i end it 'must raise JWT::InvalidJtiError when verify_jti proc returns false' do expect do Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { false })) end.to raise_error JWT::InvalidJtiError, /invalid/i end it 'true proc should not raise JWT::InvalidJtiError' do Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { true })) end it 'it should not throw arguement error with 2 args' do expect do Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti, pl) { true })) end.to_not raise_error end it 'should have payload as second param in proc' do Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti, pl) { expect(pl).to eq(payload) })) end end context '.verify_not_before(payload, options)' do let(:payload) { base_payload.merge('nbf' => (Time.now.to_i + 5)) } it 'must raise JWT::ImmatureSignature when the nbf in the payload is in the future' do expect do Verify.verify_not_before(payload, options) end.to raise_error JWT::ImmatureSignature end it 'must allow some leeway in the token age when global leeway is configured' do Verify.verify_not_before(payload, options.merge(leeway: 10)) end it 'must allow some leeway in the token age when nbf_leeway is configured' do Verify.verify_not_before(payload, options.merge(nbf_leeway: 10)) end end context '.verify_sub(payload, options)' do let(:sub) { 'ruby jwt subject' } it 'must raise JWT::InvalidSubError when the subjects do not match' do expect do Verify.verify_sub(base_payload.merge('sub' => 'not-a-match'), options.merge(sub: sub)) end.to raise_error JWT::InvalidSubError end it 'must allow a matching sub' do Verify.verify_sub(base_payload.merge('sub' => sub), options.merge(sub: sub)) end end end end ruby-jwt-2.2.2/spec/jwt_spec.rb000066400000000000000000000404041371667752300164200ustar00rootroot00000000000000require 'spec_helper' require 'jwt' require 'jwt/encode' require 'jwt/decode' describe JWT do let(:payload) { { 'user_id' => 'some@user.tld' } } let :data do { :secret => 'My$ecretK3y', :rsa_private => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-private.pem'))), :rsa_public => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-public.pem'))), :wrong_rsa_private => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))), :wrong_rsa_public => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))), 'ES256_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-private.pem'))), 'ES256_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-public.pem'))), 'ES384_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-private.pem'))), 'ES384_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-public.pem'))), 'ES512_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-private.pem'))), 'ES512_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-public.pem'))), 'ED25519_private' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF'), 'ED25519_public' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF').verify_key, 'NONE' => 'eyJhbGciOiJub25lIn0.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.', 'HS256' => 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.kWOVtIOpWcG7JnyJG0qOkTDbOy636XrrQhMm_8JrRQ8', 'HS512256' => 'eyJhbGciOiJIUzUxMjI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Ds_4ibvf7z4QOBoKntEjDfthy3WJ-3rKMspTEcHE2bA', 'HS384' => 'eyJhbGciOiJIUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.VuV4j4A1HKhWxCNzEcwc9qVF3frrEu-BRLzvYPkbWO0LENRGy5dOiBQ34remM3XH', 'HS512' => 'eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.8zNtCBTJIZTHpZ-BkhR-6sZY1K85Nm5YCKqV3AxRdsBJDt_RR-REH2db4T3Y0uQwNknhrCnZGvhNHrvhDwV1kA', 'RS256' => 'eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.eSXvWP4GViiwUALj_-qTxU68I1oM0XjgDsCZBBUri2Ghh9d75QkVDoZ_v872GaqunN5A5xcnBK0-cOq-CR6OwibgJWfOt69GNzw5RrOfQ2mz3QI3NYEq080nF69h8BeqkiaXhI24Q51joEgfa9aj5Y-oitLAmtDPYTm7vTcdGufd6AwD3_3jajKBwkh0LPSeMtbe_5EyS94nFoEF9OQuhJYjUmp7agsBVa8FFEjVw5jEgVqkvERSj5hSY4nEiCAomdVxIKBfykyi0d12cgjhI7mBFwWkPku8XIPGZ7N8vpiSLdM68BnUqIK5qR7NAhtvT7iyLFgOqhZNUQ6Ret5VpQ', 'RS384' => 'eyJhbGciOiJSUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Sfgk56moPghtsjaP4so6tOy3I553mgwX-5gByMC6dX8lpeWgsxSeAd_K8IyO7u4lwYOL0DSftnqO1HEOuN1AKyBbDvaTXz3u2xNA2x4NYLdW4AZA6ritbYcKLO5BHTXw5ueMbtA1jjGXP0zI_aK2iJTMBmB8SCF88RYBUH01Tyf4PlLj98pGL-v3prZd6kZkIeRJ3326h04hslcB5HQKmgeBk24QNLIoIC-CD329HPjJ7TtGx01lj-ehTBnwVbBGzYFAyoalV5KgvL_MDOfWPr1OYHnR5s_Fm6_3Vg4u6lBljvHOrmv4Nfx7d8HLgbo8CwH4qn1wm6VQCtuDd-uhRg', 'RS512' => 'eyJhbGciOiJSUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.LIIAUEuCkGNdpYguOO5LoW4rZ7ED2POJrB0pmEAAchyTdIK4HKh1jcLxc6KyGwZv40njCgub3y72q6vcQTn7oD0zWFCVQRIDW1911Ii2hRNHuigiPUnrnZh1OQ6z65VZRU6GKs8omoBGU9vrClBU0ODqYE16KxYmE_0n4Xw2h3D_L1LF0IAOtDWKBRDa3QHwZRM9sHsHNsBuD5ye9KzDYN1YALXj64LBfA-DoCKfpVAm9NkRPOyzjR2X2C3TomOSJgqWIVHJucudKDDAZyEbO4RA5pI-UFYy1370p9bRajvtDyoBuLDCzoSkMyQ4L2DnLhx5CbWcnD7Cd3GUmnjjTA', 'ES256' => '', 'ES384' => '', 'ES512' => '', 'PS256' => '', 'PS384' => '', 'PS512' => '' } end after(:each) do expect(OpenSSL.errors).to be_empty end context 'alg: NONE' do let(:alg) { 'none' } it 'should generate a valid token' do token = JWT.encode payload, nil, alg expect(token).to eq data['NONE'] end it 'should decode a valid token' do jwt_payload, header = JWT.decode data['NONE'], nil, false expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end end context 'payload validation' do it 'validates the payload with the ClaimsValidator if the payload is a hash' do validator = double() expect(JWT::ClaimsValidator).to receive(:new) { validator } expect(validator).to receive(:validate!) { true } payload = {} JWT.encode payload, "secret", JWT::Algos::Hmac::SUPPORTED.sample end it 'does not validate the payload if it is not present' do validator = double() expect(JWT::ClaimsValidator).not_to receive(:new) { validator } payload = nil JWT.encode payload, "secret", JWT::Algos::Hmac::SUPPORTED.sample end end %w[HS256 HS512256 HS384 HS512].each do |alg| context "alg: #{alg}" do it 'should generate a valid token' do token = JWT.encode payload, data[:secret], alg expect(token).to eq data[alg] end it 'should decode a valid token' do jwt_payload, header = JWT.decode data[alg], data[:secret], true, algorithm: alg expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end it 'wrong secret should raise JWT::DecodeError' do expect do JWT.decode data[alg], 'wrong_secret', true, algorithm: alg end.to raise_error JWT::VerificationError end it 'wrong secret and verify = false should not raise JWT::DecodeError' do expect do JWT.decode data[alg], 'wrong_secret', false end.not_to raise_error end end end %w[RS256 RS384 RS512].each do |alg| context "alg: #{alg}" do it 'should generate a valid token' do token = JWT.encode payload, data[:rsa_private], alg expect(token).to eq data[alg] end it 'should decode a valid token' do jwt_payload, header = JWT.decode data[alg], data[:rsa_public], true, algorithm: alg expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end it 'should decode a valid token using algorithm hash string key' do jwt_payload, header = JWT.decode data[alg], data[:rsa_public], true, 'algorithm' => alg expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end it 'wrong key should raise JWT::DecodeError' do key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem')) expect do JWT.decode data[alg], key, true, algorithm: alg end.to raise_error JWT::DecodeError end it 'wrong key and verify = false should not raise JWT::DecodeError' do key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem')) expect do JWT.decode data[alg], key, false end.not_to raise_error end end end %w[ED25519].each do |alg| context "alg: #{alg}" do before(:each) do data[alg] = JWT.encode payload, data["#{alg}_private"], alg end let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) } it 'should generate a valid token' do jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end it 'should decode a valid token' do jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end it 'wrong key should raise JWT::DecodeError' do expect do JWT.decode data[alg], wrong_key end.to raise_error JWT::DecodeError end it 'wrong key and verify = false should not raise JWT::DecodeError' do expect do JWT.decode data[alg], wrong_key, false end.not_to raise_error end end end %w[ES256 ES384 ES512].each do |alg| context "alg: #{alg}" do before(:each) do data[alg] = JWT.encode payload, data["#{alg}_private"], alg end let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) } it 'should generate a valid token' do jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end it 'should decode a valid token' do jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end it 'wrong key should raise JWT::DecodeError' do expect do JWT.decode data[alg], wrong_key end.to raise_error JWT::DecodeError end it 'wrong key and verify = false should not raise JWT::DecodeError' do expect do JWT.decode data[alg], wrong_key, false end.not_to raise_error end end end %w[PS256 PS384 PS512].each do |alg| context "alg: #{alg}" do before(:each) do data[alg] = JWT.encode payload, data[:rsa_private], alg end let(:wrong_key) { data[:wrong_rsa_public] } it 'should generate a valid token' do token = data[alg] header, body, signature = token.split('.') expect(header).to eql(Base64.strict_encode64({ alg: alg }.to_json)) expect(body).to eql(Base64.strict_encode64(payload.to_json)) # Validate signature is made of up header and body of JWT translated_alg = alg.gsub('PS', 'sha') valid_signature = data[:rsa_public].verify_pss( translated_alg, JWT::Base64.url_decode(signature), [header, body].join('.'), salt_length: :auto, mgf1_hash: translated_alg ) expect(valid_signature).to be true end it 'should decode a valid token' do jwt_payload, header = JWT.decode data[alg], data[:rsa_public], true, algorithm: alg expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end it 'wrong key should raise JWT::DecodeError' do expect do JWT.decode data[alg], wrong_key end.to raise_error JWT::DecodeError end it 'wrong key and verify = false should not raise JWT::DecodeError' do expect do JWT.decode data[alg], wrong_key, false end.not_to raise_error end end end context 'Invalid' do it 'algorithm should raise NotImplementedError' do expect do JWT.encode payload, 'secret', 'HS255' end.to raise_error NotImplementedError end it 'raises "No verification key available" error' do token = JWT.encode({}, 'foo') expect { JWT.decode(token, nil, true) }.to raise_error(JWT::DecodeError, 'No verification key available') end it 'ECDSA curve_name should raise JWT::IncorrectAlgorithm' do key = OpenSSL::PKey::EC.new 'secp256k1' key.generate_key expect do JWT.encode payload, key, 'ES256' end.to raise_error JWT::IncorrectAlgorithm token = JWT.encode payload, data['ES256_private'], 'ES256' key.private_key = nil expect do JWT.decode token, key end.to raise_error JWT::IncorrectAlgorithm end end context 'Verify' do context 'algorithm' do it 'should raise JWT::IncorrectAlgorithm on mismatch' do token = JWT.encode payload, data[:secret], 'HS256' expect do JWT.decode token, data[:secret], true, algorithm: 'HS384' end.to raise_error JWT::IncorrectAlgorithm expect do JWT.decode token, data[:secret], true, algorithm: 'HS256' end.not_to raise_error end it 'should raise JWT::IncorrectAlgorithm on mismatch prior to kid public key network call' do token = JWT.encode payload, data[:rsa_private], 'RS256' expect do JWT.decode(token, nil, true, { algorithms: ['RS384'] }) do |_,_| # unsuccessful keyfinder public key network call here end end.to raise_error JWT::IncorrectAlgorithm expect do JWT.decode(token, nil, true, { 'algorithms' => ['RS384'] }) do |_,_| # unsuccessful keyfinder public key network call here end end.to raise_error JWT::IncorrectAlgorithm end it 'should raise JWT::IncorrectAlgorithm when algorithms array does not contain algorithm' do token = JWT.encode payload, data[:secret], 'HS512' expect do JWT.decode token, data[:secret], true, algorithms: ['HS384'] end.to raise_error JWT::IncorrectAlgorithm expect do JWT.decode token, data[:secret], true, 'algorithms' => ['HS384'] end.to raise_error JWT::IncorrectAlgorithm expect do JWT.decode token, data[:secret], true, algorithms: ['HS512', 'HS384'] end.not_to raise_error expect do JWT.decode token, data[:secret], true, 'algorithms' => ['HS512', 'HS384'] end.not_to raise_error end context 'no algorithm provided' do it 'should use the default decode algorithm' do token = JWT.encode payload, data[:rsa_public].to_s jwt_payload, header = JWT.decode token, data[:rsa_public].to_s expect(header['alg']).to eq 'HS256' expect(jwt_payload).to eq payload end end end context 'issuer claim' do let(:iss) { 'ruby-jwt-gem' } let(:invalid_token) { JWT.encode payload, data[:secret] } let :token do iss_payload = payload.merge(iss: iss) JWT.encode iss_payload, data[:secret] end it 'if verify_iss is set to false (default option) should not raise JWT::InvalidIssuerError' do expect do JWT.decode token, data[:secret], true, iss: iss, algorithm: 'HS256' end.not_to raise_error end end end context 'a token with no segments' do it 'raises JWT::DecodeError' do expect { JWT.decode('ThisIsNotAValidJWTToken', nil, true) }.to raise_error(JWT::DecodeError, 'Not enough or too many segments') end end context 'a token with not enough segments' do it 'raises JWT::DecodeError' do expect { JWT.decode('ThisIsNotAValidJWTToken.second', nil, true) }.to raise_error(JWT::DecodeError, 'Not enough or too many segments') end end context 'a token with not too many segments' do it 'raises JWT::DecodeError' do expect { JWT.decode('ThisIsNotAValidJWTToken.second.third.signature', nil, true) }.to raise_error(JWT::DecodeError, 'Not enough or too many segments') end end context 'a token with two segments but does not require verifying' do it 'raises something else than "Not enough or too many segments"' do expect { JWT.decode('ThisIsNotAValidJWTToken.second', nil, false) }.to raise_error(JWT::DecodeError, 'Invalid segment encoding') end end context 'Base64' do it 'urlsafe replace + / with - _' do allow(Base64).to receive(:encode64) { 'string+with/non+url-safe/characters_' } expect(JWT::Base64.url_encode('foo')).to eq('string-with_non-url-safe_characters_') end end it 'should not verify token even if the payload has claims' do head = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9' load = 'eyJ1c2VyX2lkIjo1NCwiZXhwIjoxNTA0MzkwODA0fQ' sign = 'Skpi6FfYMbZ-DwW9ocyRIosNMdPMAIWRLYxRO68GTQk' expect do JWT.decode([head, load, sign].join('.'), '', false) end.not_to raise_error end it 'should not raise InvalidPayload exception if payload is an array' do expect do JWT.encode(['my', 'payload'], 'secret') end.not_to raise_error end it 'should encode string payloads' do expect do JWT.encode 'Hello World', 'secret' end.not_to raise_error end context 'when the alg value is given as a header parameter' do it 'does not override the actual algorithm used' do headers = JSON.parse(::JWT::Base64.url_decode(JWT.encode('Hello World', 'secret', 'HS256', { alg: 'HS123'}).split('.').first)) expect(headers['alg']).to eq('HS256') end it "should generate the same token" do expect(JWT.encode('Hello World', 'secret', 'HS256', { alg: 'HS256'})).to eq JWT.encode('Hello World', 'secret', 'HS256') end end context 'when hmac algorithm is used without secret key' do it 'encodes payload' do payload = { a: 1, b: 'b'} token = JWT.encode(payload, '', 'HS256') expect do token_without_secret = JWT.encode(payload, nil, 'HS256') expect(token).to eq(token_without_secret) end.not_to raise_error end end end ruby-jwt-2.2.2/spec/spec_helper.rb000066400000000000000000000011541371667752300170720ustar00rootroot00000000000000require 'rspec' require 'simplecov' require 'simplecov-json' require 'codeclimate-test-reporter' require 'codacy-coverage' Codacy::Reporter.start SimpleCov.configure do root File.join(File.dirname(__FILE__), '..') project_name 'Ruby JWT - Ruby JSON Web Token implementation' add_filter 'spec' end SimpleCov.start if ENV['COVERAGE'] CERT_PATH = File.join(File.dirname(__FILE__), 'fixtures', 'certs') RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = %i[should expect] end config.run_all_when_everything_filtered = true config.filter_run :focus config.order = 'random' end