json_web_token 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 973c4dc365edec01a991491309d0332b3898dd57
4
- data.tar.gz: 05d71d73011230c2b2f074eed6d2ea86bf0be1cf
3
+ metadata.gz: a1bab6670404e2a3185dabc1944f130891cb6de6
4
+ data.tar.gz: 142fb6257f61b6c906e29519af046289ba085508
5
5
  SHA512:
6
- metadata.gz: 640c8738d52377295275bc4c5498b02a7fd427ffdf2b8d14b5765acc90fd8868c401799f0ccbb0535d37143ee90138ff5f80621edee6c902344106a5f1727786
7
- data.tar.gz: fa2e818be12da6b351eb202b4ca2de9ab0efdd48f789d1e61e2e3683ae7fa9f50026e716d69578eb2c850266f72b5cc6bac4c94d570148cd4194d06ceb67b49f
6
+ metadata.gz: 263eb8d5f5855937117026134f7dce4f76c37c48a3c0ef955d4c21d47e41395793cc3c55bea20de613f56c1808cc6ae55af919d16bfae214a81b1a8ec9f1d840
7
+ data.tar.gz: 29073ba554234ce1581d0608e29e17e12885c962ecbda6f402564c7bc85aa18669c9a47039bd817ce09e42e6def463623fd97f554bccff2b76049f610af85bd5
@@ -1,5 +1,10 @@
1
1
  ## Changelog
2
2
 
3
+ ### v0.2.0 (2015-08-02)
4
+
5
+ * backward incompatible changes
6
+ * Top level API now #sign and #verify
7
+
3
8
  ### v0.1.2 (2015-08-02)
4
9
 
5
10
  * enhancements
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # JSON Web Token [![travis][ci_img]][travis] [![yard docs][yd_img]][yard_docs] [![code climate][cc_img]][code_climate]
2
2
 
3
- ## A JSON Web Token implementation for Ruby
3
+ ## A JSON Web Token (JWT) implementation for Ruby
4
4
 
5
5
  ### Description
6
- A Ruby implementation of the JSON Web Token (JWT) Standards Track [RFC 7519][rfc7519]
6
+ A Ruby implementation of the JSON Web Token standard [RFC 7519][rfc7519]
7
7
 
8
8
  ## Installation
9
9
  gem install json_web_token
@@ -30,7 +30,7 @@ Secure Cross-Origin Resource Sharing ([CORS][cors]) using the [rack-cors][rack-c
30
30
 
31
31
  ## Usage
32
32
 
33
- ### JsonWebToken.create(claims, options)
33
+ ### JsonWebToken.sign(claims, options)
34
34
 
35
35
  Returns a JSON Web Token string
36
36
 
@@ -47,7 +47,7 @@ Example
47
47
  require 'json_web_token'
48
48
 
49
49
  # sign with default algorithm, HMAC SHA256
50
- jwt = JsonWebToken.create({foo: 'bar'}, key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C')
50
+ jwt = JsonWebToken.sign({foo: 'bar'}, key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C')
51
51
 
52
52
  # sign with RSA SHA256 algorithm
53
53
  opts = {
@@ -55,14 +55,14 @@ opts = {
55
55
  key: < RSA private key >
56
56
  }
57
57
 
58
- jwt = JsonWebToken.create({foo: 'bar'}, opts)
58
+ jwt = JsonWebToken.sign({foo: 'bar'}, opts)
59
59
 
60
60
  # unsecured token (algorithm is 'none')
61
- jwt = JsonWebToken.create({foo: 'bar'}, alg: 'none')
61
+ jwt = JsonWebToken.sign({foo: 'bar'}, alg: 'none')
62
62
 
63
63
  ```
64
64
 
65
- ### JsonWebToken.validate(jwt, options)
65
+ ### JsonWebToken.verify(jwt, options)
66
66
 
67
67
  Returns either:
68
68
  * a JWT claims set string or hash, if the Message Authentication Code (MAC), or signature, is verified
@@ -83,7 +83,7 @@ require 'json_web_token'
83
83
  secure_jwt_example = 'eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt.cGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'
84
84
 
85
85
  # verify with default algorithm, HMAC SHA256
86
- claims = JsonWebToken.validate(secure_jwt_example, key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C')
86
+ claims = JsonWebToken.verify(secure_jwt_example, key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C')
87
87
 
88
88
  # verify with RSA SHA256 algorithm
89
89
  opts = {
@@ -91,12 +91,12 @@ opts = {
91
91
  key: < RSA public key >
92
92
  }
93
93
 
94
- claims = JsonWebToken.validate(jwt, opts)
94
+ claims = JsonWebToken.verify(jwt, opts)
95
95
 
96
96
  # unsecured token (algorithm is 'none')
97
97
  unsecured_jwt_example = 'eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt.'
98
98
 
99
- claims = JsonWebToken.validate(unsecured_jwt_example, alg: 'none')
99
+ claims = JsonWebToken.verify(unsecured_jwt_example, alg: 'none')
100
100
 
101
101
  ```
102
102
  ### Supported encryption algorithms
@@ -115,7 +115,7 @@ ES512 | ECDSA using P-521 and SHA-512
115
115
  none | No digital signature or MAC performed (unsecured)
116
116
 
117
117
  ### Supported Ruby Versions
118
- Ruby 2.0 and up
118
+ Ruby 2.0.0 and up
119
119
 
120
120
  ### Limitations
121
121
  Future implementation may include these features:
@@ -141,7 +141,7 @@ Future implementation may include these features:
141
141
 
142
142
  [travis]: https://travis-ci.org/garyf/json_web_token
143
143
  [ci_img]: https://travis-ci.org/garyf/json_web_token.svg?branch=master
144
- [yard_docs]: http://www.rubydoc.info/gems/json_web_token
144
+ [yard_docs]: http://www.rubydoc.info/github/garyf/json_web_token
145
145
  [yd_img]: http://img.shields.io/badge/yard-docs-blue.svg
146
146
  [code_climate]: https://codeclimate.com/github/garyf/json_web_token
147
147
  [cc_img]: https://codeclimate.com/github/garyf/json_web_token/badges/gpa.svg
@@ -16,6 +16,6 @@ Gem::Specification.new do |s|
16
16
  # optional
17
17
  s.add_runtime_dependency 'json', '~> 1.8', '>= 1.8.3'
18
18
  s.add_development_dependency 'rspec', '~> 3.3'
19
- s.description = 'Ruby implementation of the JSON Web Token standard, RFC 7519'
19
+ s.description = 'Ruby implementation of the JSON Web Token (JWT) standard, RFC 7519'
20
20
  s.required_ruby_version = '>= 2.0.0'
21
21
  end
@@ -1,14 +1,35 @@
1
1
  require 'json_web_token/jwt'
2
2
 
3
+ # Top level interface, or API, to sign and verify a JSON Web Token (JWT)
4
+ # @see http://tools.ietf.org/html/rfc7519
3
5
  module JsonWebToken
4
6
 
5
7
  module_function
6
8
 
7
- def create(claims, options = {})
9
+ # @param claims [Hash] a collection of name/value pairs asserting information about a subject
10
+ # @param options [Hash] specify the desired signing algorithm and signing key
11
+ # @return [String] a JSON Web Token, representing digitally signed claims
12
+ # @example
13
+ # claims = {iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true}
14
+ # options = {alg: 'HS256', key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'}
15
+ # JsonWebToken.sign(claims, options)
16
+ # # => 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
17
+ def sign(claims, options)
8
18
  Jwt.sign(claims, options)
9
19
  end
10
-
11
- def validate(jwt, options = {})
20
+
21
+ # @param jwt [String] a JSON Web Token
22
+ # @param options [Hash] specify the desired verifying algorithm and verifying key
23
+ # @return [Hash] a JWT claims set if the jwt verifies, or +error: 'Invalid'+ otherwise
24
+ # @example
25
+ # jwt = 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
26
+ # options = {alg: 'HS256', key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'}
27
+ # JsonWebToken.verify(jwt, options)
28
+ # # => {iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true}
29
+ def verify(jwt, options)
12
30
  Jwt.verify(jwt, options)
13
31
  end
14
32
  end
33
+
34
+ # alias
35
+ JWT = JsonWebToken
@@ -2,6 +2,12 @@ require 'openssl'
2
2
 
3
3
  module JsonWebToken
4
4
  module Format
5
+ # ASN1 data structures are usually encoded using the Distinguished Encoding Rules (DER).
6
+ # The ASN1 module provides the necessary classes that allow generation of ASN1 data
7
+ # structures and the methods to encode them using a DER encoding. The decode method allows
8
+ # parsing arbitrary DER-encoded data to a Ruby object that can then be modified and
9
+ # re-encoded at will.
10
+ # @see http://docs.ruby-lang.org/en/2.1.0/OpenSSL/ASN1.html
5
11
  module Asn1
6
12
 
7
13
  KEY_BITS = {
@@ -12,12 +18,6 @@ module JsonWebToken
12
18
 
13
19
  module_function
14
20
 
15
- # ASN1 data structures are usually encoded using the Distinguished Encoding Rules (DER).
16
- # The ASN1 module provides the necessary classes that allow generation of ASN1 data
17
- # structures and the methods to encode them using a DER encoding. The decode method allows
18
- # parsing arbitrary DER-encoded data to a Ruby object that can then be modified and
19
- # re-encoded at will. (see http://docs.ruby-lang.org/en/2.1.0/OpenSSL/ASN1.html)
20
-
21
21
  def der_to_signature(der, sha_bits)
22
22
  signature_pair = OpenSSL::ASN1.decode(der).value
23
23
  width = per_part_byte_count(sha_bits)
@@ -33,8 +33,6 @@ module JsonWebToken
33
33
  asn1_seq.to_der
34
34
  end
35
35
 
36
- # private
37
-
38
36
  def per_part_byte_count(sha_bits)
39
37
  bits = KEY_BITS[sha_bits]
40
38
  bits ? (bits + 7) / 8 : fail('Invalid sha_bits')
@@ -4,6 +4,7 @@ module JsonWebToken
4
4
  # Encode claims for transmission as a JSON object that is used as the payload of a JSON Web
5
5
  # Signature (JWS) structure, enabling the claims to be integrity protected with a Message
6
6
  # Authentication Code (MAC), to be later verified
7
+ # @see http://tools.ietf.org/html/rfc7519
7
8
  module Jwt
8
9
 
9
10
  ALG_DEFAULT = 'HS256'
@@ -19,12 +20,12 @@ module JsonWebToken
19
20
  # (e.g String for Hmac | OpenSSL::PKey::RSA | OpenSSL::PKey::EC)
20
21
  # @return [String] a JSON Web Token, representing digitally signed claims
21
22
  # @example
22
- # claims = {iss: 'joe', exp: 1300819380, 'http://example.com/is_root' => true}
23
+ # claims = {iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true}
23
24
  # options = {alg: 'HS256', key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'}
24
25
  # Jwt.sign(claims, options)
25
26
  # # => 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
26
27
  # @see http://tools.ietf.org/html/rfc7519#section-7.1
27
- def sign(claims, options = {})
28
+ def sign(claims, options)
28
29
  message = validated_message(claims)
29
30
  header = config_header(options)
30
31
  return Jws.unsecured_message(header, message) if header[:alg] == 'none'
@@ -33,14 +34,14 @@ module JsonWebToken
33
34
 
34
35
  # @param jwt [String] a JSON Web Token
35
36
  # @param options [Hash] specify the desired verifying algorithm and verifying key
36
- # @return [Hash] a JWT claims set if the jwt verifies, or +{error: 'Invalid'}+ otherwise
37
+ # @return [Hash] a JWT claims set if the jwt verifies, or +error: 'Invalid'+ otherwise
37
38
  # @example
38
39
  # jwt = 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
39
40
  # options = {alg: 'HS256', key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'}
40
41
  # Jwt.verify(jwt, options)
41
- # # => {iss: 'joe', exp: 1300819380, 'http://example.com/is_root' => true}
42
+ # # => {iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true}
42
43
  # @see see http://tools.ietf.org/html/rfc7519#section-7.2
43
- def verify(jwt, options = {})
44
+ def verify(jwt, options)
44
45
  alg = options[:alg] || ALG_DEFAULT
45
46
  jws = Jws.verify(jwt, alg, options[:key])
46
47
  jws ? Util.symbolize_keys(decoded_message_json_to_hash jws) : {error: 'invalid'}
@@ -1,22 +1,34 @@
1
1
  module JsonWebToken
2
+ # Utility methods
2
3
  module Util
3
4
 
4
5
  module_function
5
6
 
6
- # https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-3.2
7
+ # @param a [String]
8
+ # @param b [String]
9
+ # @return [Boolean] a predicate that compares two strings for equality in constant-time
10
+ # to avoid timing attacks
11
+ # @example
12
+ # Util.constant_time_compare?("a", "A")
13
+ # # => false
14
+ # @see https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-3.2
15
+ # @see cf. rails activesupport/lib/active_support/security_utils.rb
7
16
  def constant_time_compare?(a, b)
8
17
  return false if a.nil? || b.nil? || a.empty? || b.empty?
9
18
  secure_compare(a, b)
10
19
  end
11
20
 
12
- # cf. rails activesupport/lib/active_support/core_ext/hash/keys.rb
21
+ # @param hsh [Hash]
22
+ # @return [Hash] a new hash with all keys converted to symbols,
23
+ # as long as they respond to to_sym
24
+ # @example
25
+ # Util.symbolize_keys({'a' => 0, 'b' => '2', c: '3'})
26
+ # # => {a: 0, b: '2', c: '3'}
27
+ # @see cf. rails activesupport/lib/active_support/core_ext/hash/keys.rb
13
28
  def symbolize_keys(hsh)
14
29
  transform_keys(hsh) { |key| key.to_sym rescue key }
15
30
  end
16
31
 
17
- # private
18
-
19
- # cf. rails activesupport/lib/active_support/security_utils.rb
20
32
  def secure_compare(a, b)
21
33
  return false unless a.bytesize == b.bytesize
22
34
  l = a.unpack "C#{a.bytesize}"
@@ -1,3 +1,3 @@
1
1
  module JsonWebToken
2
- VERSION = '0.1.2'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -20,7 +20,7 @@ module JsonWebToken
20
20
  end
21
21
 
22
22
  context 'w claims' do
23
- let(:claims) { { iss: 'joe', exp: 1300819380, 'http://example.com/is_root': true} }
23
+ let(:claims) { { iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true} }
24
24
  context 'w HS256 keys' do
25
25
  let(:signing_key) { 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C' }
26
26
  let(:verifying_key) { signing_key }
@@ -118,7 +118,7 @@ module JsonWebToken
118
118
  describe 'w default verify alg' do
119
119
  it 'raises' do
120
120
  jwt = Jwt.sign(claims, sign_options)
121
- expect { Jwt.verify(jwt) }
121
+ expect { Jwt.verify(jwt, {alg: nil}) }
122
122
  .to raise_error(RuntimeError, "Algorithm not matching 'alg' header parameter")
123
123
  end
124
124
  end
@@ -1,12 +1,12 @@
1
1
  require 'json_web_token'
2
2
 
3
3
  describe JsonWebToken do
4
- context '#create' do
5
- let(:claims) { {exp: 'tomorrow'} }
6
- shared_examples_for 'w #validate' do
7
- it 'is verified' do
8
- jwt = JsonWebToken.create(claims, create_options)
9
- expect(JsonWebToken.validate jwt, validate_options).to include(claims)
4
+ context '#sign' do
5
+ let(:claims) { { iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true} }
6
+ shared_examples_for 'w #verify' do
7
+ it 'w a claims set' do
8
+ jwt = JsonWebToken.sign(claims, sign_options)
9
+ expect(JsonWebToken.verify jwt, verify_options).to include(claims)
10
10
  end
11
11
  end
12
12
 
@@ -15,29 +15,38 @@ describe JsonWebToken do
15
15
  let(:verifying_key) { signing_key }
16
16
 
17
17
  describe 'default alg' do
18
- let(:create_options) { {key: signing_key} }
19
- let(:validate_options) { {key: verifying_key} }
20
- it_behaves_like 'w #validate'
18
+ let(:sign_options) { {key: signing_key} }
19
+ let(:verify_options) { {key: verifying_key} }
20
+ it_behaves_like 'w #verify'
21
21
  end
22
22
 
23
23
  context "w 'alg' option" do
24
24
  describe 'HS256' do
25
- let(:create_options) { {alg: 'HS256', key: signing_key} }
26
- let(:validate_options) { {alg: 'HS256', key: verifying_key} }
27
- it_behaves_like 'w #validate'
25
+ let(:sign_options) { {alg: 'HS256', key: signing_key} }
26
+ let(:verify_options) { {alg: 'HS256', key: verifying_key} }
27
+ it_behaves_like 'w #verify'
28
28
  end
29
29
 
30
30
  describe "w alg 'none'" do
31
- let(:create_options) { {alg: 'none', key: signing_key} }
32
- let(:validate_options) { {alg: 'none', key: verifying_key} }
33
- it_behaves_like 'w #validate'
31
+ let(:sign_options) { {alg: 'none', key: signing_key} }
32
+ let(:verify_options) { {alg: 'none', key: verifying_key} }
33
+ it_behaves_like 'w #verify'
34
34
  end
35
35
  end
36
36
  end
37
37
 
38
38
  describe 'w/o key w default header alg' do
39
39
  it 'raises' do
40
- expect { JsonWebToken.create(claims) }.to raise_error(RuntimeError, 'Invalid shared key')
40
+ expect { JsonWebToken.sign(claims, {}) }.to raise_error(RuntimeError, 'Invalid shared key')
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'module alias JWT' do
46
+ describe '#sign' do
47
+ let(:claims) { { iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true} }
48
+ it 'recognized' do
49
+ expect(JsonWebToken.sign(claims, key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C')).to be
41
50
  end
42
51
  end
43
52
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_web_token
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gary Fleshman
@@ -14,45 +14,45 @@ dependencies:
14
14
  name: json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.8'
20
- - - ">="
20
+ - - '>='
21
21
  - !ruby/object:Gem::Version
22
22
  version: 1.8.3
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - "~>"
27
+ - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: '1.8'
30
- - - ">="
30
+ - - '>='
31
31
  - !ruby/object:Gem::Version
32
32
  version: 1.8.3
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: rspec
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ~>
38
38
  - !ruby/object:Gem::Version
39
39
  version: '3.3'
40
40
  type: :development
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - "~>"
44
+ - - ~>
45
45
  - !ruby/object:Gem::Version
46
46
  version: '3.3'
47
- description: Ruby implementation of the JSON Web Token standard, RFC 7519
47
+ description: Ruby implementation of the JSON Web Token (JWT) standard, RFC 7519
48
48
  email: gfleshman@newforge-tech.com
49
49
  executables: []
50
50
  extensions: []
51
51
  extra_rdoc_files: []
52
52
  files:
53
- - ".gitignore"
54
- - ".rspec"
55
- - ".travis.yml"
53
+ - .gitignore
54
+ - .rspec
55
+ - .travis.yml
56
56
  - CHANGELOG.md
57
57
  - Gemfile
58
58
  - LICENSE
@@ -93,12 +93,12 @@ require_paths:
93
93
  - lib
94
94
  required_ruby_version: !ruby/object:Gem::Requirement
95
95
  requirements:
96
- - - ">="
96
+ - - '>='
97
97
  - !ruby/object:Gem::Version
98
98
  version: 2.0.0
99
99
  required_rubygems_version: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - '>='
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  requirements: []