tok_access 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6aec725ecefd64e58d1fafa64d9450372b0fb705
4
+ data.tar.gz: 2200ef5494e6da6552f6ff8469a0251ade70a559
5
+ SHA512:
6
+ metadata.gz: 40ed63785ecef8c0b50810ee00729e9e856c9de2f67b9dac6e2dd327c1b7b1291bc73c5a82bab07dedd951840b265abe38fba4fd5349dcf41c1cc0021bdc6e9f
7
+ data.tar.gz: 8608c7e8ad2c4599ba9b410c3961cba4b7249d45bf3bd3b0eccc1fa3976e5dd77e20870afd9f7174dae4ab0ddb0c34e409794cf24129cfb7b8ef1da9c20fed6a
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Yonga
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # TokAccess
2
+ Handle authentication of your users using tokens.
3
+ Every 'tokified' user will have a association named
4
+ toks.
5
+
6
+ A tok is an object that consist of two attributes: token, devise_token.
7
+
8
+ You should use the devise_token to identify the user devices
9
+ in which the user has logged in and the token to authenticate the
10
+ user request.
11
+
12
+ TokAccess use bcrypt has_secure_password and has_secure_token methods to handle the authentication process and tokens generation
13
+
14
+ ## Usage
15
+
16
+ #### Imagine you have a User model and a mobile app in which a user want to sign up.
17
+
18
+ ```ruby
19
+ # somewhere in a controller that handle the users registration
20
+
21
+ def sign_up
22
+ user = User.new(user_params)
23
+ if user.save
24
+ # if the user is saved, an associated tok is created
25
+ # and you can access that tok using the following methods
26
+ token = user.get_token
27
+ devise_token = user.get_devise_token
28
+ # return the tokens to the front-end.
29
+ else
30
+ # code if the user can't be saved
31
+ end
32
+ end
33
+ ```
34
+ #### So, now the user is logged in one device and start browsing the app. How to identify the user that sign up previously?
35
+
36
+ ```ruby
37
+ # somewhere in your code, probably in you ApplicationController
38
+ # let's say that you are sending a token in a header named
39
+ # APP_TOKEN
40
+
41
+ def current_user
42
+ @current_user ||= User.validate_access(token: request.headers["HTTP_APP_TOKEN"])
43
+ end
44
+
45
+ def user_signed_in?
46
+ !current_user.nil?
47
+ end
48
+
49
+ def current_token
50
+ current_user ? current_user.get_token : nil
51
+ end
52
+
53
+ def current_devise_token
54
+ current_user ? current_user.get_devise_token : nil
55
+ end
56
+
57
+ # After 15 minutes, the next user request will refresh the tokens.
58
+ # it is necessary to send the tokens to the front-end again
59
+
60
+ def tokens_refreshed?
61
+ if current_user and current_user.refreshed?
62
+ # Some code that allows you to send the tokens to the front-end
63
+ end
64
+ end
65
+ ```
66
+
67
+
68
+ #### Now the previous user wants to login in a new device
69
+
70
+ ```ruby
71
+ # somewhere in a controller that handle the users sign in
72
+
73
+ def sign_in
74
+ user = User.find_by(email: params[:email])
75
+ if user.tok_auth(params[:password])
76
+ # if the user is authenticated successfully, a new tok is created
77
+ # and you can access that tok using the following methods
78
+ token = user.get_token
79
+ devise_token = user.get_devise_token
80
+ # then you should return to the front-end the tokens.
81
+ else
82
+ # code if the user authentication fails
83
+ end
84
+ end
85
+ ```
86
+
87
+ #### Now the previous user wants to login in an old device
88
+
89
+ ```ruby
90
+ # somewhere in a controller that handle the users sign in
91
+ # let's say that you are sending a devise_token in a header named
92
+ # APP_DEVISE_TOKEN
93
+
94
+ def sign_in
95
+ user = User.find_by(email: params[:email])
96
+ if user.tok_auth(params[:password], request.headers["HTTP_APP_DEVISE_TOKEN"])
97
+ # if the user is authenticated successfully and the tok related to the
98
+ # given devise_token is found, the token and devise_token are regenerated
99
+ # and you can access that tok using the get_token and get_devise_token
100
+ # methods.
101
+ # if the user is authenticated successfully and the tok related to the
102
+ # given devise_token wasn't found, a new tok is created and you can access
103
+ # that tok using the get_token and get_devise_token
104
+ # methods.
105
+ token = user.get_token
106
+ devise_token = user.get_devise_token
107
+ # then you should return to the front-end the tokens.
108
+ else
109
+ # code if the user authentication fails
110
+ end
111
+ end
112
+ ```
113
+
114
+ #### Accessing the toks from the user.
115
+ ```ruby
116
+
117
+ user = User.validate_access(token: request.headers["HTTP_APP_TOKEN"])
118
+ user.toks # UserTok collection.
119
+
120
+ ```
121
+
122
+
123
+ ## Installation
124
+ Add this line to your application's Gemfile:
125
+
126
+ ```ruby
127
+ gem 'tok_access'
128
+ ```
129
+
130
+ And then execute:
131
+ ```bash
132
+ $ bundle
133
+ ```
134
+
135
+ ### Generating models
136
+
137
+ Generating a User model.
138
+
139
+ ```bash
140
+ $ rails g tok_access:model User email:string nickname:string
141
+ ```
142
+ The above command will generate two models: User and UserTok
143
+
144
+ The migration generated to create the User model will add a column named
145
+ password_digest to store the password.
146
+
147
+ #### IMPORTANT: If you already have a User model, the command will generate just the migration to add the password_digest column
148
+
149
+ #### NOTE: You can generate any model to be 'tokified' just pass the name of the model
150
+
151
+ ```bash
152
+ $ rails g tok_access:model Person email:string nickname:string
153
+ ```
154
+ The above command will generate two models: Person and PersonTok
155
+
156
+ #### IMPORTANT: If you use the tok_access:model generator to destroy the model, the Model and ModelTok will be destroyed. It's a better choice to do it manually
157
+
158
+ ```bash
159
+ $ rails d model user
160
+ $ rails d model user_tok
161
+ ```
162
+
163
+ Also, remember to remove the migrations...
164
+
165
+
166
+ ## License
167
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'TokAccess'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+
33
+ task default: :test
@@ -0,0 +1,33 @@
1
+ Description:
2
+ Use this generator to create the models that you want give access through tokens
3
+ It will generate the a migration to add a password_digest attribute to the model.
4
+ If the model does not exist, will generate it.
5
+ Also generates a model to handle the related toks. If your model name
6
+ is User, the associated tok model name will be UserTok.
7
+
8
+ Example:
9
+ rails generate tok_access:model User email:string nickname:string birth:date -f
10
+
11
+ This will be the output:
12
+ create db/migrate/20170913173053_tok_access_create_users.rb
13
+ create app/models/user.rb
14
+ invoke test_unit
15
+ create test/models/user_test.rb
16
+ create test/fixtures/users.yml
17
+ create db/migrate/20170913173054_create_user_toks.rb
18
+ create app/models/user_tok.rb
19
+ invoke test_unit
20
+ insert app/models/user.rb
21
+ insert app/models/user_tok.rb
22
+
23
+ If the model already exists, this will be the output:
24
+ create db/migrate/20170913173229_add_tok_access_to_users.rb
25
+ identical app/models/user.rb
26
+ invoke test_unit
27
+ identical test/models/user_test.rb
28
+ force test/fixtures/users.yml
29
+ create db/migrate/20170913173230_create_user_toks.rb
30
+ create app/models/user_tok.rb
31
+ invoke test_unit
32
+ insert app/models/user.rb
33
+ insert app/models/user_tok.rb
@@ -0,0 +1,48 @@
1
+ require 'generators/tok_access/orm_helper'
2
+ require 'rails/generators/active_record/model/model_generator'
3
+
4
+ module TokAccess
5
+ module Generators
6
+ class ModelGenerator < ActiveRecord::Generators::ModelGenerator
7
+ include TokAccess::Generators::OrmHelper
8
+ source_root File.join(File.dirname(ActiveRecord::Generators::ModelGenerator.instance_method(:create_migration_file).source_location.first), "templates")
9
+
10
+
11
+ def create_migration_file
12
+ return unless options[:migration] && options[:parent].nil?
13
+ attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
14
+ if behavior == :invoke
15
+ if model_exists? or migration_exists?(table_name)
16
+ migration_template "#{__FILE__}/../templates/migration_existing_for.rb", "db/migrate/add_tok_access_to_#{table_name}.rb", migration_version: migration_version
17
+ else
18
+ migration_template "#{__FILE__}/../templates/migration_for.rb", "db/migrate/tok_access_create_#{table_name}.rb", migration_version: migration_version
19
+ end
20
+ end
21
+ if behavior == :revoke
22
+ migration_template "#{__FILE__}/../templates/migration_existing_for.rb", "db/migrate/add_tok_access_to_#{table_name}.rb", migration_version: migration_version
23
+ migration_template "#{__FILE__}/../templates/migration_for.rb", "db/migrate/tok_access_create_#{table_name}.rb", migration_version: migration_version
24
+ end
25
+ end
26
+
27
+ def generate_tok_model
28
+ tok_model_table_name = "#{table_name.singularize}_tok"
29
+ tok_model_class_name = "#{table_name.singularize}_tok".camelize
30
+ if behavior == :invoke
31
+ if !File.exist?(Rails.root.join("app", "models", "#{tok_model_table_name}.rb"))
32
+ invoke "active_record:model", [tok_model_class_name, "token:string","devise_token:string", "object_id:integer"]
33
+ end
34
+ inject_into_class(Rails.root.join("app", "models", "#{table_name.singularize}.rb"), Object.const_get(table_name.singularize.camelize)) do
35
+ %Q{\ttokify\n}
36
+ end
37
+ inject_into_class(Rails.root.join("app", "models", "#{tok_model_table_name}.rb"), Object.const_get(tok_model_class_name)) do
38
+ %Q{\tdefine_toks :#{table_name.singularize}\n}
39
+ end
40
+ end
41
+ if behavior == :revoke
42
+ system "rails d model #{table_name.singularize.camelize}"
43
+ system "rails d model #{tok_model_class_name}"
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ module TokAccess
2
+ module Generators
3
+ module OrmHelper
4
+
5
+ private
6
+
7
+ def model_exists?
8
+ File.exist?(File.join(destination_root, model_path))
9
+ end
10
+
11
+ def migration_exists?(table_name)
12
+ Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/\d+_add_tok_access_to_#{table_name}.rb$/).first
13
+ end
14
+
15
+ def migration_path
16
+ @migration_path ||= File.join("db", "migrate")
17
+ end
18
+
19
+ def model_path
20
+ @model_path ||= File.join("app", "models", "#{file_path}.rb")
21
+ end
22
+
23
+ def migration_version
24
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
25
+ end
26
+
27
+ def migration_data
28
+ <<-RUBY.strip_heredoc
29
+ t.string :password_digest, null: false, default: ""
30
+ RUBY
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ class AddTokAccessTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+
4
+ change_table :<%= table_name %> do |t|
5
+ <%= migration_data %>
6
+ <% attributes.each do |attribute| %>
7
+ t.<%= attribute.type %> :<%= attribute.name %>
8
+ <% end %>
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,12 @@
1
+ class TokAccessCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+
4
+ create_table :<%= table_name %> do |t|
5
+ <%= migration_data %>
6
+ <% attributes.each do |attribute| %>
7
+ t.<%= attribute.type %> :<%= attribute.name %>
8
+ <% end %>
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,7 @@
1
+ module TokAccess
2
+ module Generators
3
+ class TokAccessGenerator < Rails::Generators::Base
4
+ #namespace "tok_access"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :tok_access do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,135 @@
1
+ module TokAccess
2
+
3
+ module TokAuthenticable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+
8
+ # before create an tokified object, setup the toks
9
+ before_create :setup_access_tok
10
+
11
+ # Return nil if you haven't authenticated the object
12
+ # using the method #tok_auth or the method #tok_auth failed the
13
+ # authentication process. Otherwise, return the token attribute of one
14
+ # of the associated object toks.
15
+ def get_token
16
+ @_token
17
+ end
18
+
19
+ # Return nil if you haven't authenticated the object
20
+ # using the method #tok_auth or the method #tok_auth failed the
21
+ # authentication process. Otherwise, return the devise_token attribute
22
+ # of one of the associated object toks.
23
+ def get_devise_token
24
+ @_devise_token
25
+ end
26
+
27
+ # Return nil if you haven't use the method TokAccess.validate_access.
28
+ # After the TokAccess.validate_access method is called, if the access was validated
29
+ # successfuly, this method will return true if the token was regenerated, otherwise
30
+ # return nil
31
+ def refreshed?
32
+ @refreshed
33
+ end
34
+
35
+
36
+ # Authenticate the object with the given password .
37
+ # If the authentication process is successful return the object and the
38
+ # methods #get_tok and #get_devise_tok will return the tokens
39
+ # Return nil if the authentication process fails
40
+ # You can pass as a parameter a devise_token. If the object has a tok that
41
+ # match the devise_token given, will regenerate the tok. If you do not
42
+ # pass the devise_token parameter, the method will create a new tok
43
+ # associated with the object. If the object.toks.size is equal to the
44
+ # toks_limit, the method will destroy one of the toks and create a new one
45
+ def tok_auth(password, devise_token = nil )
46
+ if self.authenticate(password)
47
+ generate_access_toks(devise_token)
48
+ return self
49
+ end
50
+ nil
51
+ end
52
+
53
+ # If the object is associated to the tok given the method will return
54
+ # the object and the methods #get_tok and #get_devise_tok will
55
+ # return the tokens. Otherwise return nil
56
+ def provide_access(tok)
57
+ if self.toks.find_by(id: tok.id)
58
+ refresh tok
59
+ set_token tok.token
60
+ set_devise_token tok.devise_token
61
+ return self
62
+ end
63
+ nil
64
+ end
65
+
66
+ private
67
+
68
+ def refresh(tok)
69
+ if tok.updated_at >= 15.minutes.ago
70
+ tok.touch
71
+ @refreshed = true
72
+ end
73
+ end
74
+
75
+ def set_token(token)
76
+ @_token = token
77
+ end
78
+
79
+ def set_devise_token(token)
80
+ @_devise_token = token
81
+ end
82
+
83
+ def setup_access_tok
84
+ self.toks.build()
85
+ end
86
+
87
+ def generate_access_toks(devise_token = nil)
88
+ if !devise_token
89
+ self.toks.order(updated_at: :asc).first.destroy if self.toks.count == TokAccess.config.tokens_limit
90
+ tok = self.toks.create
91
+ else
92
+ tok = self.toks.find_by(devise_token: devise_token)
93
+ tok.regenerate_token if tok
94
+ tok.regenerate_devise_token if tok
95
+ end
96
+ if tok
97
+ @refreshed = true
98
+ set_token tok.token
99
+ set_devise_token tok.devise_token
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ module ClassMethods
106
+
107
+ # object: The object to authenticate
108
+ # password: The password to authenticate the object with
109
+ # if the object is authenticatred successfully, returns the object with
110
+ # => the get_token and get_devise_token methods returning the access
111
+ # => tokens.
112
+ # otherwise return nil
113
+ def tok_authentication(object, password)
114
+ return object.tok_auth(password)
115
+ end
116
+
117
+ # tokens: hash with a devise_token key or token key
118
+ # if any of the tokens is found. Provide access to the related
119
+ # object calling the method provide_access
120
+ # otherwise return nil
121
+ def validate_access(tokens = {})
122
+ toks_class = Object.const_get("#{self.name.camelize}Tok")
123
+ tok = toks_class.find_by(devise_token: tokens[:devise_token]) if tokens[:devise_token]
124
+ tok = toks_class.find_by(token: tokens[:token]) if tokens[:token] and !tok
125
+ if tok
126
+ return tok._tok_object.provide_access(tok)
127
+ end
128
+ nil
129
+ end
130
+
131
+ end
132
+
133
+ end
134
+
135
+ end
@@ -0,0 +1,52 @@
1
+ module TokAccess
2
+
3
+ class TokConfig
4
+
5
+ attr_accessor :tokens_limit
6
+ @tokens_limit = nil
7
+
8
+ def initialize()
9
+ @tokens_limit = 10
10
+ end
11
+
12
+ end
13
+
14
+ @config = TokConfig.new
15
+
16
+ def config
17
+ @config
18
+ end
19
+ module_function :config
20
+
21
+ def configure(&block)
22
+ if block_given?
23
+ yield @config
24
+ end
25
+ end
26
+ module_function :configure
27
+
28
+ Object.class_eval do
29
+ def tokify
30
+ class_eval do
31
+ include TokAccess::TokAuthenticable
32
+ has_secure_password
33
+ has_many :toks, class_name: "#{self}Tok", foreign_key: "object_id", autosave: true
34
+ end
35
+ end
36
+
37
+ def define_toks(association = nil)
38
+ class_eval do
39
+ belongs_to association,
40
+ class_name: "#{self.to_s.gsub(/Tok\z/,'')}",
41
+ foreign_key: "object_id" if association
42
+ belongs_to :_tok_object,
43
+ class_name: "#{self.to_s.gsub(/Tok\z/,'')}",
44
+ foreign_key: "object_id" if association
45
+ has_secure_token
46
+ has_secure_token :devise_token
47
+ validates :token, :devise_token, presence: true, on: :update
48
+ end
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,3 @@
1
+ module TokAccess
2
+ VERSION = '1.0.0'
3
+ end
data/lib/tok_access.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'tok_access/tok_config'
2
+ require 'tok_access/tok_authenticable'
3
+
4
+ ## TokAccess
5
+ # The TokAcess module
6
+ module TokAccess
7
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tok_access
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Yonga9121
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-22 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: 5.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bcrypt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.1.7
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.1.7
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Handle authentication of your users using tokens.
56
+ email:
57
+ - jorgeggayon@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - lib/generators/tok_access/USAGE
66
+ - lib/generators/tok_access/model_generator.rb
67
+ - lib/generators/tok_access/orm_helper.rb
68
+ - lib/generators/tok_access/templates/migration_existing_for.rb
69
+ - lib/generators/tok_access/templates/migration_for.rb
70
+ - lib/generators/tok_access/tok_access_generator.rb
71
+ - lib/tasks/tok_access_tasks.rake
72
+ - lib/tok_access.rb
73
+ - lib/tok_access/tok_authenticable.rb
74
+ - lib/tok_access/tok_config.rb
75
+ - lib/tok_access/version.rb
76
+ homepage: https://yonga9121.github.io/tok_access/
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.6.13
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Handle authentication of your users using tokens.
100
+ test_files: []