toktok 0.1.0 → 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: e16666f292ece7bb076c8ed7672f4141102b2afc
4
- data.tar.gz: a99deed7551d520bec1d258d70d9e4a356a68130
3
+ metadata.gz: 36cfc1bad83de1c2e52e5d88aacb87736494dba2
4
+ data.tar.gz: b2c0cd4d24b8c645914bef1c330339f4e21b3de8
5
5
  SHA512:
6
- metadata.gz: 38b8a5680cf95497c2ef012a9f32573d2f8d6627462da97b39eca53a49c651d75f7cd66499e68f5abb9d31cbe5fa20288734eb3afea5558c60d32810fdb4fc87
7
- data.tar.gz: 9f3b3878cc38ff13e1c8253102e9fbc33155f1e0881016a67e4da89f0f95a351c5324a36be27b6499a4c0411087e76ec212c9c1e703225468f970083e4969dd3
6
+ metadata.gz: 165c1721d1a581d28eb3f85a3c07a75bb7e1cc812cc23a6a8f553340337d9bca66702b4ce153a591f44ca805a24c1cbd65d413a1ee508f3adf5e0d8c9cb3dd80
7
+ data.tar.gz: 77001d5cad59b16980ab0e7adab15272de0ca1e993e6049f45afa300c70e904c68491d3041064fc74b49db8a5ce01f720dedc5f18ca70fdf6c2f5cc6751a269d
data/.editorconfig CHANGED
@@ -7,6 +7,9 @@ indent_style = space
7
7
  insert_final_newline = true
8
8
  trim_trailing_whitespace = true
9
9
 
10
+ [*.md]
11
+ trim_trailing_whitespace = false
12
+
10
13
  [Makefile]
11
14
  indent_size = 4
12
15
  indent_style = tab
data/Makefile ADDED
@@ -0,0 +1,5 @@
1
+ yard_server:
2
+ open http://localhost:8808
3
+ yard server --reload
4
+
5
+ .PHONY: all
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Build Status](https://travis-ci.org/guzart/toktok.svg?branch=master)](https://travis-ci.org/guzart/toktok)
4
4
  [![codecov](https://codecov.io/gh/guzart/toktok/branch/master/graph/badge.svg)](https://codecov.io/gh/guzart/toktok)
5
5
  [![Code Climate](https://codeclimate.com/github/guzart/toktok/badges/gpa.svg)](https://codeclimate.com/github/guzart/toktok)
6
+ [![Gem Version](https://badge.fury.io/rb/toktok.svg)](https://badge.fury.io/rb/toktok)
6
7
 
7
8
 
8
9
  JWT Authentication for Ruby
@@ -30,38 +31,49 @@ TODO: Improve
30
31
  **Configuration**
31
32
 
32
33
  ```ruby
34
+ # 'none' | 'HS256' | 'RS256' | 'ES256'
33
35
  Toktok.algorithm = 'HS256'
34
- Toktok.secret_key = ENV['MY_SECRET_KEY']
36
+
37
+ # REQUIRED unless algorithm = 'none'
38
+ Toktok.secret_key = ENV['TOKTOK_SECRET_KEY']
39
+
40
+ # OPTIONAL – in seconds
41
+ Toktok.lifetime = nil
35
42
  ```
36
43
 
37
44
  **Encode/Decode**
38
45
 
39
46
  ```ruby
40
- token = Toktok::Token.new(identity: 'guzart')
47
+ token = Toktok::Token.new(identity: 'guzart', payload: { message: 'Hola' })
41
48
  puts token.jwt # 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1...'
42
49
 
43
50
  token = Toktok::Token.new(jwt: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1...')
44
51
  puts token.identity # 'guzart'
45
- puts token.payload # { sub: 'guzart' }
52
+ puts token.payload # { sub: 'guzart', message: 'Hola' }
46
53
  ```
47
54
 
48
- ## API
49
-
50
- TODO: list public api
55
+ ## Claims
51
56
 
52
- ### ::Toktok
57
+ ### Subject Claim
53
58
 
54
- ### ::Toktok::Token
59
+ Toktok uses the required `identity` argument as the payload `sub` attribute defined
60
+ by the [JWT Subject Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2).
55
61
 
56
- ## Claims
62
+ ### Expiration Time Claim
57
63
 
58
- TODO: describe relation in configuration and in token payload
64
+ Toktok automatically calculates the token expiration using the `Toktok.lifetime` configuration
65
+ value and sets the `exp` attribute defined by the
66
+ [JWT Expiration Time Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4)
59
67
 
60
68
  ## Development
61
69
 
62
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
70
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests.
71
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
63
72
 
64
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
73
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
74
+ update the version number in `version.rb`, and then run `bundle exec rake release`, which will create
75
+ a git tag for the version, push git commits and tags, and push the `.gem` file to
76
+ [rubygems.org](https://rubygems.org).
65
77
 
66
78
  ## Contributing
67
79
 
data/lib/toktok.rb CHANGED
@@ -1,21 +1,44 @@
1
- require 'toktok/version'
2
- require 'jwt'
3
-
4
1
  module Toktok
5
2
  require 'toktok/configuration'
6
3
  require 'toktok/token'
4
+ require 'toktok/version'
7
5
 
6
+ # Set the algorithm used to encode and decode JWT tokens (default: HS256)
7
+ #
8
+ # Acceptable values are:
9
+ # * none
10
+ # * HS256, HS384, HS512
11
+ # * RS256, RS384, RS512
12
+ # * ES256, ES384, ES512
13
+ #
14
+ # @param [String] value the algorithm name
15
+ # @return [String] the algorithm
8
16
  def self.algorithm=(value)
9
17
  @algorithm = value
10
18
  end
11
19
 
20
+ # Set the lifetime in seconds before a token expires (default: nil)
21
+ #
22
+ # @param [Integer, nil] value the number of seconds before a token expires
23
+ # @return [Integer, nil] the lifetime
24
+ def self.lifetime=(value)
25
+ @lifetime = value
26
+ end
27
+
28
+ # Set the secret key that will be used to encode and decode JWT tokens
29
+ # @param [String] value the secret key
30
+ # @return [String] the secret key
12
31
  def self.secret_key=(value)
13
32
  @secret_key = value
14
33
  end
15
34
 
35
+ # Gets a Toktok::Configuration instance using the module values.
36
+ #
37
+ # @return [Toktok::Configuration] the configuration
16
38
  def self.config
17
39
  ::Toktok::Configuration.new(
18
40
  algorithm: @algorithm,
41
+ lifetime: @lifetime,
19
42
  secret_key: @secret_key
20
43
  )
21
44
  end
@@ -1,11 +1,13 @@
1
1
  module Toktok
2
2
  class Configuration
3
- attr_reader :algorithm, :secret_key
3
+ attr_reader :algorithm, :lifetime, :secret_key
4
4
 
5
+ # Error raised when an algorithm is given but the secret_key is missing.
5
6
  SecretKeyMissingError = Class.new(StandardError)
6
7
 
7
- def initialize(algorithm: nil, secret_key: nil)
8
+ def initialize(algorithm: nil, lifetime: nil, secret_key: nil)
8
9
  @algorithm = algorithm || 'HS256'
10
+ @lifetime = lifetime
9
11
  @secret_key = secret_key
10
12
 
11
13
  if algorithm != 'none' && (secret_key || '') == ''
data/lib/toktok/token.rb CHANGED
@@ -1,27 +1,31 @@
1
+ require 'jwt'
2
+
1
3
  module Toktok
2
4
  InvalidIdentity = Class.new(StandardError)
5
+ InvalidSignature = Class.new(StandardError)
3
6
 
4
7
  class Token
5
8
  attr_reader :config, :jwt, :payload
6
9
 
7
- def initialize(identity: nil, jwt: nil)
10
+ def initialize(identity: nil, jwt: nil, payload: nil)
8
11
  @config = Toktok.config
9
12
  @payload = {}
10
13
  if jwt
11
14
  initialize_decode(jwt, identity)
12
15
  else
13
- initialize_encode(identity)
16
+ initialize_encode(identity, payload)
14
17
  end
15
18
  end
16
19
 
17
20
  def identity
18
- payload['sub']
21
+ payload[:sub]
19
22
  end
20
23
 
21
24
  private
22
25
 
23
- def initialize_encode(identity)
24
- @payload['sub'] = identity
26
+ def initialize_encode(identity, extra)
27
+ prepare_payload(identity, extra)
28
+ normalize_payload
25
29
  @jwt = JWT.encode(payload, config.secret_key, config.algorithm)
26
30
  end
27
31
 
@@ -29,10 +33,12 @@ module Toktok
29
33
  @jwt = jwt
30
34
  options = decode_options(identity)
31
35
  decoded_token = JWT.decode(jwt, config.secret_key, algorithm?, options)
32
- @payload = decoded_token[0]
36
+ @payload = symbolize_keys(decoded_token[0])
33
37
  @header = decoded_token[1]
34
38
  rescue JWT::InvalidSubError
35
39
  raise InvalidIdentity, "Invalid identity. Expected #{identity}"
40
+ rescue JWT::VerificationError
41
+ raise InvalidSignature, 'Invalid or manipulated signature'
36
42
  end
37
43
 
38
44
  def decode_options(identity)
@@ -44,5 +50,20 @@ module Toktok
44
50
  def algorithm?
45
51
  config.algorithm != 'none'
46
52
  end
53
+
54
+ def prepare_payload(identity, extra = nil)
55
+ @payload.merge!(symbolize_keys(extra)) if extra
56
+ @payload[:sub] = identity
57
+ @payload[:exp] = Time.now.to_i + config.lifetime if config.lifetime.to_i > 0
58
+ end
59
+
60
+ # Guarantee the order in which the keys are inserted
61
+ def normalize_payload
62
+ @payload = Hash[payload.keys.sort.map { |k| [k, payload[k]] }]
63
+ end
64
+
65
+ def symbolize_keys(hash)
66
+ Hash[hash.map { |k, v| [k.to_sym, v] }]
67
+ end
47
68
  end
48
69
  end
@@ -1,3 +1,3 @@
1
1
  module Toktok
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
data/toktok.gemspec CHANGED
@@ -34,4 +34,6 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency 'rake', '~> 10.0'
35
35
  spec.add_development_dependency 'reek', '~> 4.5'
36
36
  spec.add_development_dependency 'rspec', '~> 3.5'
37
+ spec.add_development_dependency 'timecop', '~> 0.8'
38
+ spec.add_development_dependency 'yard', '~> 0.9'
37
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toktok
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arturo Guzman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-03-15 00:00:00.000000000 Z
11
+ date: 2017-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt
@@ -136,6 +136,34 @@ dependencies:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: '3.5'
139
+ - !ruby/object:Gem::Dependency
140
+ name: timecop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.8'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.8'
153
+ - !ruby/object:Gem::Dependency
154
+ name: yard
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.9'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.9'
139
167
  description: |
140
168
  Simplify JWT token encoding and decoding for Ruby. Use a configuration initializer to standardize the use
141
169
  of JWT encoding/decoding accross your library. Simplifies the use of JWT Claims.
@@ -154,6 +182,7 @@ files:
154
182
  - Gemfile
155
183
  - Guardfile
156
184
  - LICENSE.txt
185
+ - Makefile
157
186
  - README.md
158
187
  - Rakefile
159
188
  - bin/console