henlo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +15 -0
- data/lib/generators/henlo/install_generator.rb +17 -0
- data/lib/generators/henlo/migrations_generator.rb +33 -0
- data/lib/generators/templates/henlo_initializer.rb +23 -0
- data/lib/generators/templates/migrations/add_jti_column.rb +16 -0
- data/lib/generators/templates/migrations/create_blacklisted_tokens.rb.erb +21 -0
- data/lib/henlo.rb +46 -0
- data/lib/henlo/authenticable.rb +90 -0
- data/lib/henlo/helpers/util.rb +17 -0
- data/lib/henlo/identifiable.rb +26 -0
- data/lib/henlo/refreshable.rb +33 -0
- data/lib/henlo/revocable.rb +28 -0
- data/lib/henlo/version.rb +3 -0
- metadata +156 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 51d705728f88bb4c77b243d887d05f729d2a2019
|
4
|
+
data.tar.gz: 968ea1f50cecc17d754fe04617e117a02e6d9c88
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e30c6ffaf47154ffe110b3218d7a4ad7f972ddc1a4d5b6b27940342cd23dd7a98d0bc8ae96fa6a1476d0c215ecbd149a0588662609e4bd41715f4a27de96b6d4
|
7
|
+
data.tar.gz: 19986364a62c80e02052f7cdbbbc98043a54ba37351afff6d616275cfa69d53fb05641c92226db268f1bc513527c559466236123d7079d940cccaa41a4aa9dc5
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
10
|
+
load 'rails/tasks/engine.rake'
|
11
|
+
|
12
|
+
|
13
|
+
Bundler::GemHelper.install_tasks
|
14
|
+
|
15
|
+
task default: :test
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Henlo
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("../../templates", __FILE__)
|
7
|
+
desc "Installs Henlo."
|
8
|
+
|
9
|
+
def copy_initializer
|
10
|
+
template "henlo_initializer.rb", "config/initializers/henlo.rb"
|
11
|
+
|
12
|
+
puts "Installation complete."
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module Henlo
|
4
|
+
module Generators
|
5
|
+
class MigrationsGenerator < ActiveRecord::Generators::Base
|
6
|
+
source_root File.expand_path("../../templates", __FILE__)
|
7
|
+
desc "Generates the necessary migration for the model"
|
8
|
+
argument :table_name, type: :string, default: "User"
|
9
|
+
|
10
|
+
|
11
|
+
def create_migrations
|
12
|
+
puts "Generating migrations for model #{table_name}.downcase"
|
13
|
+
migration_template "migrations/add_jti_column.rb", "db/migrate/add_jti_column_to_#{table_name.downcase.pluralize}.rb"
|
14
|
+
migration_template 'migrations/create_blacklisted_tokens.rb.erb', 'db/migrate/create_blacklisted_tokens.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
def migration_data
|
18
|
+
<<RUBY
|
19
|
+
t.string :refresh_token_jti
|
20
|
+
t.boolean :blacklist_check, default: false
|
21
|
+
RUBY
|
22
|
+
end
|
23
|
+
|
24
|
+
def migration_index_data
|
25
|
+
<<RUBY
|
26
|
+
add_index "#{table_name.downcase.pluralize.to_sym}", :blacklist_check
|
27
|
+
add_index "#{table_name.downcase.pluralize.to_sym}", :refresh_token_jti
|
28
|
+
RUBY
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Henlo.setup do |config|
|
2
|
+
|
3
|
+
## All expiration claims use seconds as unit
|
4
|
+
|
5
|
+
## Refresh token expiration claim
|
6
|
+
## ----------------
|
7
|
+
##
|
8
|
+
## How long before a refresh token is expired. If nil is provided, token will
|
9
|
+
## last forever.
|
10
|
+
##
|
11
|
+
## Default is 15 days
|
12
|
+
# config.refresh_token_lifetime = 15 * 86400
|
13
|
+
|
14
|
+
## Id token expiration claim
|
15
|
+
## ----------------
|
16
|
+
##
|
17
|
+
## How long before an id token is expired. If nil is provided, token will
|
18
|
+
## last forever.
|
19
|
+
## This value is provided in seconds
|
20
|
+
## Default is 15 minutes
|
21
|
+
# config.id_token_lifetime = 60 * 15
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<%
|
2
|
+
parent_class = ActiveRecord::Migration
|
3
|
+
parent_class = parent_class[parent_class.current_version] if Rails::VERSION::MAJOR >= 5
|
4
|
+
-%>
|
5
|
+
class AddJtiColumnTo<%= table_name.camelize %>s < <%= parent_class.to_s %>
|
6
|
+
def self.up
|
7
|
+
change_table(:<%= table_name.downcase.pluralize %>) do |t|
|
8
|
+
<%= migration_data %>
|
9
|
+
end
|
10
|
+
<%= migration_index_data%>
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
raise ActiveRecord::IrreversibleMigration
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<%
|
2
|
+
parent_class = ActiveRecord::Migration
|
3
|
+
parent_class = parent_class[parent_class.current_version] if Rails::VERSION::MAJOR >= 5
|
4
|
+
-%>
|
5
|
+
class CreateBlacklistedTokens < <%= parent_class.to_s %>
|
6
|
+
def self.up
|
7
|
+
create_table :blacklisted_tokens do |t|
|
8
|
+
t.string :token_jti
|
9
|
+
<%- if Rails::VERSION::MAJOR >= 5 -%>
|
10
|
+
t.integer :exp_in_unix
|
11
|
+
t.timestamps
|
12
|
+
<%- else -%>
|
13
|
+
t.timestamps null: false
|
14
|
+
<%- end -%>
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.down
|
19
|
+
drop_table :blacklisted_tokens
|
20
|
+
end
|
21
|
+
end
|
data/lib/henlo.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "henlo/version"
|
2
|
+
require "henlo/refreshable"
|
3
|
+
require "henlo/identifiable"
|
4
|
+
require "henlo/authenticable"
|
5
|
+
require "henlo/revocable"
|
6
|
+
require "knock"
|
7
|
+
|
8
|
+
#
|
9
|
+
## Defines default initializing values and main method for generating tokens
|
10
|
+
module Henlo
|
11
|
+
|
12
|
+
#
|
13
|
+
## Generates refresh and access tokens when method is called, allows the passing in of
|
14
|
+
## additional key value pairs to be encoded in the jwt payload
|
15
|
+
## Returns the jwt identifier of the refresh token, as well as the expiry time in unix
|
16
|
+
## seconds of the id token.
|
17
|
+
def self.generate_henlos(options={})
|
18
|
+
claim = options || nil
|
19
|
+
refresh_token_and_jti = Refreshable.generate_refreshable(options)
|
20
|
+
id_token_and_exp = Identifiable.generate_identifiable(options)
|
21
|
+
tokens = Hash[
|
22
|
+
id_token: id_token_and_exp[:token],
|
23
|
+
refresh_token: refresh_token_and_jti[:token]
|
24
|
+
]
|
25
|
+
henlos = Hash[
|
26
|
+
tokens: tokens,
|
27
|
+
jti: refresh_token_and_jti[:jti],
|
28
|
+
exp: id_token_and_exp[:exp]
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
mattr_accessor :refresh_token_lifetime
|
33
|
+
self.refresh_token_lifetime = 15 * 86400
|
34
|
+
|
35
|
+
mattr_accessor :id_token_lifetime
|
36
|
+
self.id_token_lifetime = 60 * 15
|
37
|
+
|
38
|
+
# Default way to setup Henlo. Run `rails generate henlo:install` to create
|
39
|
+
## a fresh initializer with all configuration values.
|
40
|
+
def self.setup
|
41
|
+
yield self
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "henlo/helpers/util"
|
2
|
+
require 'active_record/errors'
|
3
|
+
#
|
4
|
+
## Module
|
5
|
+
module Henlo::Authenticable
|
6
|
+
|
7
|
+
#
|
8
|
+
## Retrieve the token type from the jwt payload
|
9
|
+
def self.parse_token_type(token, options={})
|
10
|
+
claim = Knock::AuthToken.new(token: token, verify_options: options).payload
|
11
|
+
claim["type"]
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
## Match the token jwt identifier with what is stored in the database for the resource,
|
16
|
+
## a lack of match indicates suspicious activities
|
17
|
+
def self.jti_match?(payload, resource)
|
18
|
+
payload["jti"] === resource.refresh_token_jti
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
## Check the resource to see if it has been flagged for blacklist check
|
23
|
+
def self.it_suspicious?(resource)
|
24
|
+
resource.blacklist_check?
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
## Check the blacklisted tokens table to see whether the token's jwt identifier has been
|
29
|
+
## blacklisted
|
30
|
+
def self.it_not_fren?(resource)
|
31
|
+
BlacklistedToken.where(token_jti: resource.refresh_token_jti).first
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
## Parse the resource as identified by the id encoded in the jwt with the key "sub"
|
36
|
+
def self.parse_resource(payload, model)
|
37
|
+
resource = model.capitalize.constantize.where(id: payload["sub"]).first
|
38
|
+
if resource.nil?
|
39
|
+
raise ActiveRecord::RecordNotFound
|
40
|
+
end
|
41
|
+
resource
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
## Authenticates resource by first determining the treatment based on the type of token.
|
46
|
+
## Requests with valid id tokens will be processed.
|
47
|
+
## Requests with refresh tokens will be checked for 1) whether the resource has been flagged
|
48
|
+
## for blacklist check and if yes, 2) whether the token's jwt identifier has been flaglisted.
|
49
|
+
## If neither 1) nor 2) is established, the token will be checked for a match of the jwt identifier
|
50
|
+
## The resource is returned if all these checks are passed.
|
51
|
+
def self.it_me?(token, model)
|
52
|
+
type = parse_token_type(token)
|
53
|
+
payload = Knock::AuthToken.new(token: token).payload
|
54
|
+
resource = parse_resource(payload, model)
|
55
|
+
case type
|
56
|
+
when "id"
|
57
|
+
resource
|
58
|
+
when "refresh"
|
59
|
+
if it_suspicious?(resource) && it_not_fren?(resource)
|
60
|
+
nil
|
61
|
+
else
|
62
|
+
if jti_match?(payload, resource)
|
63
|
+
resource
|
64
|
+
else
|
65
|
+
Henlo::Revocable.token_blockt(payload, resource)
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
else
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
## This method is to be called before `it_me?` is called, so that expired tokens are treated before
|
76
|
+
## the authentication begins. Requests made with expired id tokens are rejected with an error.
|
77
|
+
## Requests made with expired refresh tokens are then processed with "reauthentication_strategy.
|
78
|
+
## This method is passed as an argument to `it_expired` by the app. You can define how
|
79
|
+
## users are reauthenticated in your own app.
|
80
|
+
def self.it_expired(reauthenticate_strategy, token, model)
|
81
|
+
token = Knock::AuthToken.new(token: token, verify_options: {verify_expiration: false}).token
|
82
|
+
claim = Knock::AuthToken.new(token: token, verify_options: {verify_expiration: false}).payload
|
83
|
+
resource = parse_resource(claim, model)
|
84
|
+
if claim["type"] == "id"
|
85
|
+
raise ActionController::InvalidAuthenticityToken
|
86
|
+
else
|
87
|
+
reauthenticate_strategy
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
## Helper methods
|
4
|
+
module Henlo
|
5
|
+
module Helpers
|
6
|
+
module Util
|
7
|
+
|
8
|
+
#
|
9
|
+
## Generates a random string in the format of "a5391f26-1136-46f3-a3d3-ea4e1e558f06"
|
10
|
+
## to use as a unique jwt identifier.
|
11
|
+
def self.generate_jti
|
12
|
+
SecureRandom.uuid
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "henlo/helpers/util"
|
2
|
+
|
3
|
+
#
|
4
|
+
## Generates id token. The id token is used to identify and authenticate the user before
|
5
|
+
## responding to a request
|
6
|
+
module Henlo::Identifiable
|
7
|
+
|
8
|
+
# Generates id token and returns both the token, with the optional payload encoded, and the
|
9
|
+
## token expiry time in unix seconds
|
10
|
+
def self.generate_identifiable(options={})
|
11
|
+
claim = options || nil
|
12
|
+
|
13
|
+
claim.merge!({
|
14
|
+
exp: Time.now.utc.to_i + Henlo.id_token_lifetime,
|
15
|
+
jti: Henlo::Helpers::Util.generate_jti,
|
16
|
+
type: "id"
|
17
|
+
})
|
18
|
+
|
19
|
+
Hash[
|
20
|
+
token: Knock::AuthToken.new(payload: claim).token,
|
21
|
+
exp: claim[:exp]
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "henlo/helpers/util"
|
2
|
+
|
3
|
+
#
|
4
|
+
## Module for generating refresh tokens
|
5
|
+
|
6
|
+
module Henlo::Refreshable
|
7
|
+
|
8
|
+
#
|
9
|
+
## Generate refreshable token with a unix time for expiry, the type of token
|
10
|
+
## and the jwt identifier (a random string) encoded in the payload in addition to
|
11
|
+
## whatever was passed as payload when `generate_henlos` was called
|
12
|
+
def self.generate_refreshable(options={})
|
13
|
+
claim = options || nil
|
14
|
+
|
15
|
+
claim.merge!({
|
16
|
+
exp: Time.now.utc.to_i + Henlo.refresh_token_lifetime,
|
17
|
+
jti: Henlo::Helpers::Util.generate_jti,
|
18
|
+
type: "refresh"
|
19
|
+
})
|
20
|
+
|
21
|
+
Hash[
|
22
|
+
token: Knock::AuthToken.new(payload: claim).token,
|
23
|
+
jti: claim[:jti]
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
## Store jwt identifier in the app's database, in the table of the resource
|
29
|
+
def self.store_jti(resource, jti)
|
30
|
+
resource.update_attribute(:refresh_token_jti, jti)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#
|
2
|
+
## Module allows the blacklist of tokens as identified by the jti (jwt identifier)
|
3
|
+
## Blacklisted refresh tokens cannot be used to generate new id tokens
|
4
|
+
module Henlo::Revocable
|
5
|
+
|
6
|
+
#
|
7
|
+
## Method called when the identifier as encoded in the token payload does not match what was stored in the database
|
8
|
+
## or when the revoke token route is called by the user in cases of breach such as device loss
|
9
|
+
## the token is blacklisted and the resource is flagged as needing blacklist checks
|
10
|
+
def self.token_blockt(payload, resource)
|
11
|
+
resource.blacklist_check == true
|
12
|
+
resource.save!
|
13
|
+
|
14
|
+
blacklisted_token = BlacklistedToken.create(
|
15
|
+
token_jti: payload["jti"],
|
16
|
+
exp_in_unix: payload["exp"]
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
## Call this period in a scheduled task to clean expired tokens from the database
|
22
|
+
def self.token_rekt
|
23
|
+
BlacklistedToken.each do |token|
|
24
|
+
token.destroy unless Time.now.utc < token.exp_in_unix
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: henlo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- nombiezinja
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-01-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jwt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: knock
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.1.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.1.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.15'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.15'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rdoc
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Based on the Knock gem, offers options to further customize secure authentication
|
112
|
+
practices
|
113
|
+
email:
|
114
|
+
- tianyizhang1987@gmail.com
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- Rakefile
|
120
|
+
- lib/generators/henlo/install_generator.rb
|
121
|
+
- lib/generators/henlo/migrations_generator.rb
|
122
|
+
- lib/generators/templates/henlo_initializer.rb
|
123
|
+
- lib/generators/templates/migrations/add_jti_column.rb
|
124
|
+
- lib/generators/templates/migrations/create_blacklisted_tokens.rb.erb
|
125
|
+
- lib/henlo.rb
|
126
|
+
- lib/henlo/authenticable.rb
|
127
|
+
- lib/henlo/helpers/util.rb
|
128
|
+
- lib/henlo/identifiable.rb
|
129
|
+
- lib/henlo/refreshable.rb
|
130
|
+
- lib/henlo/revocable.rb
|
131
|
+
- lib/henlo/version.rb
|
132
|
+
homepage: https://github.com/nombiezinja/henlo
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 2.4.0
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: JWT based authentication with access and id tokens
|
156
|
+
test_files: []
|