propelauth 0.1.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 +7 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +19 -0
- data/Rakefile +4 -0
- data/lib/propelauth/client.rb +216 -0
- data/lib/propelauth/error.rb +15 -0
- data/lib/propelauth/version.rb +5 -0
- data/lib/propelauth.rb +185 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0a7cc390a774dbb31aff77f68ecfd1e070a8dc2d510c2e401c5bb9a8562b191b
|
4
|
+
data.tar.gz: d9008aedbfd21019624a3ca5ca043d54646cb52db87e1e9b391dd1b7e60be928
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5175acc0f03eeb540dd378ddb2dfd52f7a0594701cba8801872ed0538b6c147c48ada8e28314c7c9a136dbfb0dca47ca9eb5215ff6224dfaf8751cf85792ae77
|
7
|
+
data.tar.gz: 9c156a6ec7d1741af3d5980069b67552863832524bb908f27f01eaa14fa5205f09d6e1b4a0377efefa9a4e617284d9229314b9047b251ac4a16aa027e7a54c87
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2022 Andrew Israel
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<a href="https://www.propelauth.com?ref=github" target="_blank" align="center">
|
3
|
+
<img src="https://propelauth-logos.s3.us-west-2.amazonaws.com/logo-only.png" width="100">
|
4
|
+
</a>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
# PropelAuth Rails Gem
|
8
|
+
|
9
|
+
A gem for managing authentication, backed by [PropelAuth](https://www.propelauth.com?ref=github).
|
10
|
+
|
11
|
+
[PropelAuth](https://www.propelauth.com?ref=github) is a prebuilt, hosted authentication solution focused on a great developer experience.
|
12
|
+
|
13
|
+
## Documentation
|
14
|
+
|
15
|
+
- Getting started guides for PropelAuth are [here](https://docs.propelauth.com/)
|
16
|
+
|
17
|
+
## Questions?
|
18
|
+
|
19
|
+
Feel free to reach out at support@propelauth.com
|
data/Rakefile
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
module PropelAuth
|
5
|
+
module Client
|
6
|
+
class << self
|
7
|
+
def fetch_user_metadata_by_user_id(user_id, include_orgs: false)
|
8
|
+
fetch_user_metadata_by_query(user_id, { include_orgs: include_orgs })
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch_user_metadata_by_email(email, include_orgs: false)
|
12
|
+
fetch_user_metadata_by_query("email", { email: email, include_orgs: include_orgs })
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch_user_metadata_by_username(username, include_orgs: false)
|
16
|
+
fetch_user_metadata_by_query("username", { username: username, include_orgs: include_orgs })
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch_batch_user_metadata_by_user_ids(user_ids, include_orgs: false)
|
20
|
+
fetch_batch_user_metadata("user_ids", user_ids, -> (x) { x["user_id"] }, include_orgs)
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch_batch_user_metadata_by_emails(emails, include_orgs: false)
|
24
|
+
fetch_batch_user_metadata("emails", emails, -> (x) { x["email"] }, include_orgs)
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch_batch_user_metadata_by_usernames(usernames, include_orgs: false)
|
28
|
+
fetch_batch_user_metadata("usernames", usernames, -> (x) { x["username"] }, include_orgs)
|
29
|
+
end
|
30
|
+
|
31
|
+
def fetch_org(org_id)
|
32
|
+
response = connection.get("/api/backend/v1/org/#{org_id}", {}, { "Authorization" => "Bearer #{api_key}" })
|
33
|
+
if response.status == 200
|
34
|
+
response.body
|
35
|
+
elsif response.status == 404
|
36
|
+
nil
|
37
|
+
elsif response.status == 401
|
38
|
+
raise PropelAuth::InvalidApiKey.new
|
39
|
+
elsif response.status == 426
|
40
|
+
raise PropelAuth::B2BSupportDisabled.new
|
41
|
+
else
|
42
|
+
raise PropelAuth::UnexpectedError.new
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_orgs_by_query(page_size: 10, page_number: 0, order_by: OrgOrderBy::CREATED_AT_ASC)
|
47
|
+
json_body = {
|
48
|
+
page_size: page_size,
|
49
|
+
page_number: page_number,
|
50
|
+
order_by: order_by,
|
51
|
+
}.to_json
|
52
|
+
response = connection.post "/api/backend/v1/org/query", json_body, {
|
53
|
+
"Authorization" => "Bearer #{api_key}",
|
54
|
+
"Content-Type" => "application/json",
|
55
|
+
}
|
56
|
+
if response.status == 200
|
57
|
+
response.body
|
58
|
+
elsif response.status == 400
|
59
|
+
raise PropelAuth::BadRequest.new response.body
|
60
|
+
elsif response.status == 401
|
61
|
+
raise PropelAuth::InvalidApiKey.new
|
62
|
+
elsif response.status == 426
|
63
|
+
raise PropelAuth::B2BSupportDisabled.new
|
64
|
+
else
|
65
|
+
raise PropelAuth::UnexpectedError.new
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def fetch_users_by_query(page_size: 10, page_number: 0, order_by: UserOrderBy::CREATED_AT_ASC, email_or_username: nil, include_orgs: false)
|
70
|
+
params = {
|
71
|
+
page_size: page_size,
|
72
|
+
page_number: page_number,
|
73
|
+
order_by: order_by,
|
74
|
+
email_or_username: email_or_username,
|
75
|
+
include_orgs: include_orgs,
|
76
|
+
}
|
77
|
+
response = connection.get "/api/backend/v1/user/query", params, { "Authorization" => "Bearer #{api_key}" }
|
78
|
+
if response.status == 200
|
79
|
+
response.body
|
80
|
+
elsif response.status == 400
|
81
|
+
raise PropelAuth::BadRequest.new response.body
|
82
|
+
elsif response.status == 401
|
83
|
+
raise PropelAuth::InvalidApiKey.new
|
84
|
+
elsif response.status == 426
|
85
|
+
raise PropelAuth::B2BSupportDisabled.new
|
86
|
+
else
|
87
|
+
raise PropelAuth::UnexpectedError.new
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def fetch_users_in_org(org_id, page_size: 10, page_number: 0, include_orgs: false)
|
92
|
+
params = {
|
93
|
+
page_size: page_size,
|
94
|
+
page_number: page_number,
|
95
|
+
include_orgs: include_orgs,
|
96
|
+
}
|
97
|
+
response = connection.get "/api/backend/v1/user/org/#{org_id}", params, { "Authorization" => "Bearer #{api_key}" }
|
98
|
+
if response.status == 200
|
99
|
+
response.body
|
100
|
+
elsif response.status == 400
|
101
|
+
raise PropelAuth::BadRequest.new response.body
|
102
|
+
elsif response.status == 401
|
103
|
+
raise PropelAuth::InvalidApiKey.new
|
104
|
+
elsif response.status == 426
|
105
|
+
raise PropelAuth::B2BSupportDisabled.new
|
106
|
+
else
|
107
|
+
raise PropelAuth::UnexpectedError.new
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def create_user(email, email_confirmed: false, send_email_to_confirm_email_address: false, password: nil,
|
112
|
+
username: nil, first_name: nil, last_name: nil)
|
113
|
+
json_body = {
|
114
|
+
email: email,
|
115
|
+
email_confirmed: email_confirmed,
|
116
|
+
send_email_to_confirm_email_address: send_email_to_confirm_email_address,
|
117
|
+
password: password,
|
118
|
+
username: username,
|
119
|
+
first_name: first_name,
|
120
|
+
last_name: last_name,
|
121
|
+
}.to_json
|
122
|
+
|
123
|
+
response = connection.post "/api/backend/v1/user/", json_body, {
|
124
|
+
"Authorization" => "Bearer #{api_key}",
|
125
|
+
"Content-Type" => "application/json",
|
126
|
+
}
|
127
|
+
if response.status >= 200 && response.status < 300
|
128
|
+
response.body
|
129
|
+
elsif response.status == 400
|
130
|
+
raise PropelAuth::BadRequest.new response.body
|
131
|
+
elsif response.status == 401
|
132
|
+
raise PropelAuth::InvalidApiKey.new
|
133
|
+
else
|
134
|
+
raise PropelAuth::UnexpectedError.new
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
private def connection
|
139
|
+
@connection ||= Faraday.new do |conn|
|
140
|
+
auth_url = PropelAuth.configuration.auth_url
|
141
|
+
if auth_url.nil? || PropelAuth.configuration.api_key.nil?
|
142
|
+
raise PropelAuth::PropelAuthNotConfigured.new
|
143
|
+
end
|
144
|
+
|
145
|
+
conn.url_prefix = auth_url
|
146
|
+
conn.request :json
|
147
|
+
conn.response :json, content_type: "application/json"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private def api_key
|
152
|
+
PropelAuth.configuration.api_key
|
153
|
+
end
|
154
|
+
|
155
|
+
private def fetch_user_metadata_by_query(path_param, query)
|
156
|
+
response = connection.get("/api/backend/v1/user/#{path_param}", query, { "Authorization" => "Bearer #{api_key}" })
|
157
|
+
if response.status == 200
|
158
|
+
response.body
|
159
|
+
elsif response.status == 404
|
160
|
+
nil
|
161
|
+
elsif response.status == 401
|
162
|
+
raise PropelAuth::InvalidApiKey.new
|
163
|
+
else
|
164
|
+
raise PropelAuth::UnexpectedError.new
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
private def fetch_batch_user_metadata(type, values, key_function, include_orgs)
|
169
|
+
json_body = {}
|
170
|
+
json_body[type] = values
|
171
|
+
json_body = json_body.to_json
|
172
|
+
response = connection.post "/api/backend/v1/user/#{type}" do |req|
|
173
|
+
req.body = json_body
|
174
|
+
req.headers[:authorization] = "Bearer #{api_key}"
|
175
|
+
req.headers[:content_type] = "application/json"
|
176
|
+
req.params[:include_orgs] = include_orgs
|
177
|
+
end
|
178
|
+
|
179
|
+
if response.status == 401
|
180
|
+
raise PropelAuth::InvalidApiKey.new
|
181
|
+
elsif response.status == 400
|
182
|
+
raise PropelAuth::BadRequest.new response.body
|
183
|
+
elsif response.status == 200
|
184
|
+
user_by_key = {}
|
185
|
+
|
186
|
+
response.body.each { |user|
|
187
|
+
key = key_function.call(user)
|
188
|
+
unless key.nil?
|
189
|
+
user_by_key[key_function.call(user)] = user
|
190
|
+
end
|
191
|
+
}
|
192
|
+
|
193
|
+
user_by_key
|
194
|
+
else
|
195
|
+
raise PropelAuth::UnexpectedError.new
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
module OrgOrderBy
|
203
|
+
CREATED_AT_ASC = "CREATED_AT_ASC"
|
204
|
+
CREATED_AT_DESC = "CREATED_AT_DESC"
|
205
|
+
NAME = "NAME"
|
206
|
+
end
|
207
|
+
|
208
|
+
module UserOrderBy
|
209
|
+
CREATED_AT_ASC = "CREATED_AT_ASC"
|
210
|
+
CREATED_AT_DESC = "CREATED_AT_DESC"
|
211
|
+
LAST_ACTIVE_AT_ASC = "LAST_ACTIVE_AT_ASC"
|
212
|
+
LAST_ACTIVE_AT_DESC = "LAST_ACTIVE_AT_DESC"
|
213
|
+
EMAIL = "EMAIL"
|
214
|
+
USERNAME = "USERNAME"
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PropelAuth
|
2
|
+
class InvalidAuthUrl < StandardError; end
|
3
|
+
class InvalidApiKey < StandardError; end
|
4
|
+
class PropelAuthNotConfigured < StandardError; end
|
5
|
+
class B2BSupportDisabled < StandardError; end
|
6
|
+
class UnexpectedError < StandardError; end
|
7
|
+
|
8
|
+
class BadRequest < StandardError
|
9
|
+
def initialize(errors_by_field)
|
10
|
+
@errors_by_field = errors_by_field
|
11
|
+
super("Bad request #{errors_by_field}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/lib/propelauth.rb
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "propelauth/version"
|
4
|
+
require 'active_support/concern'
|
5
|
+
require 'jwt'
|
6
|
+
|
7
|
+
module PropelAuth
|
8
|
+
autoload :Client, "propelauth/client"
|
9
|
+
autoload :InvalidAuthUrl, "propelauth/error"
|
10
|
+
autoload :InvalidApiKey, "propelauth/error"
|
11
|
+
autoload :UnexpectedError, "propelauth/error"
|
12
|
+
autoload :B2BSupportDisabled, "propelauth/error"
|
13
|
+
autoload :PropelAuthNotConfigured, "propelauth/error"
|
14
|
+
autoload :BadRequest, "propelauth/error"
|
15
|
+
|
16
|
+
module AuthMethods
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
class UnauthorizedException < StandardError; end
|
20
|
+
class ForbiddenException < StandardError; end
|
21
|
+
|
22
|
+
def require_user
|
23
|
+
begin
|
24
|
+
@user = extract_and_validate_user_from_access_token
|
25
|
+
rescue UnauthorizedException
|
26
|
+
render status: 401
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def optional_user
|
31
|
+
begin
|
32
|
+
@user = extract_and_validate_user_from_access_token
|
33
|
+
rescue UnauthorizedException
|
34
|
+
@user = nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def require_org_member(required_org_id, minimum_required_role: nil)
|
39
|
+
begin
|
40
|
+
@org = require_org_member_inner(required_org_id, minimum_required_role: minimum_required_role)
|
41
|
+
rescue UnauthorizedException
|
42
|
+
render status: 401
|
43
|
+
rescue ForbiddenException
|
44
|
+
render status: 403
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private def extract_and_validate_user_from_access_token
|
49
|
+
token = extract_token_from_authorization_header(request.headers['Authorization'])
|
50
|
+
user = validate_access_token(token)
|
51
|
+
if user.nil?
|
52
|
+
raise UnauthorizedException
|
53
|
+
else
|
54
|
+
user
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private def require_org_member_inner(required_org_id, minimum_required_role: nil)
|
59
|
+
@user = extract_and_validate_user_from_access_token
|
60
|
+
|
61
|
+
if required_org_id.nil?
|
62
|
+
logger.info "Required org is unspecified"
|
63
|
+
raise ForbiddenException
|
64
|
+
end
|
65
|
+
|
66
|
+
org_id_to_org_member_info = @user["org_id_to_org_member_info"]
|
67
|
+
if org_id_to_org_member_info.nil?
|
68
|
+
logger.info "User is not a member of required org"
|
69
|
+
raise ForbiddenException
|
70
|
+
end
|
71
|
+
|
72
|
+
org_member_info = org_id_to_org_member_info[required_org_id]
|
73
|
+
if org_member_info.nil?
|
74
|
+
logger.info "User is not a member of required org"
|
75
|
+
raise ForbiddenException
|
76
|
+
end
|
77
|
+
|
78
|
+
if !minimum_required_role.nil?
|
79
|
+
minimum_required_role = UserRole.to_user_role(minimum_required_role)
|
80
|
+
user_role = UserRole.to_user_role(org_member_info["user_role"])
|
81
|
+
if user_role < minimum_required_role
|
82
|
+
logger.info "User's role in org doesn't meet minimum required role"
|
83
|
+
raise ForbiddenException
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
org_member_info
|
88
|
+
end
|
89
|
+
|
90
|
+
private def validate_access_token(token)
|
91
|
+
rsa_public = PropelAuth.configuration.public_key
|
92
|
+
iss = PropelAuth.configuration.auth_url
|
93
|
+
|
94
|
+
if rsa_public.nil? || iss.nil?
|
95
|
+
raise PropelAuth::PropelAuthNotConfigured.new
|
96
|
+
end
|
97
|
+
|
98
|
+
begin
|
99
|
+
decoded_token = JWT.decode token, rsa_public, true, { iss: iss, verify_iss: true, verify_iat: true, algorithm: 'RS256' }
|
100
|
+
decoded_token_body = decoded_token[0]
|
101
|
+
HashWithIndifferentAccess.new({
|
102
|
+
user_id: decoded_token_body["user_id"],
|
103
|
+
org_id_to_org_member_info: decoded_token_body["org_id_to_org_member_info"],
|
104
|
+
})
|
105
|
+
rescue StandardError => e
|
106
|
+
logger.info e
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
private def extract_token_from_authorization_header(header)
|
112
|
+
if header.nil?
|
113
|
+
nil
|
114
|
+
else
|
115
|
+
split_header = header.split(" ", 2)
|
116
|
+
if split_header.length != 2 || split_header[0].casecmp("bearer") != 0
|
117
|
+
nil
|
118
|
+
else
|
119
|
+
return split_header[1]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
module UserRole
|
126
|
+
Member = 0
|
127
|
+
Admin = 1
|
128
|
+
Owner = 2
|
129
|
+
|
130
|
+
def UserRole.to_user_role(user_role)
|
131
|
+
if user_role == Member
|
132
|
+
Member
|
133
|
+
elsif user_role == Admin
|
134
|
+
Admin
|
135
|
+
elsif user_role == Owner
|
136
|
+
Owner
|
137
|
+
elsif user_role == "Member"
|
138
|
+
Member
|
139
|
+
elsif user_role == "Admin"
|
140
|
+
Admin
|
141
|
+
elsif user_role == "Owner"
|
142
|
+
Owner
|
143
|
+
else
|
144
|
+
raise("Invalid user role")
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class Configuration
|
150
|
+
attr_accessor :api_key
|
151
|
+
attr_reader :auth_url, :public_key
|
152
|
+
|
153
|
+
def auth_url=(auth_url)
|
154
|
+
@auth_url = validate_auth_url(auth_url)
|
155
|
+
end
|
156
|
+
|
157
|
+
def public_key=(public_key_pem)
|
158
|
+
@public_key = OpenSSL::PKey::RSA.new(public_key_pem)
|
159
|
+
end
|
160
|
+
|
161
|
+
private def validate_auth_url(auth_url)
|
162
|
+
uri = URI(auth_url)
|
163
|
+
if uri.scheme.nil? || uri.scheme.casecmp("https") != 0
|
164
|
+
raise PropelAuth::InvalidAuthUrl.new
|
165
|
+
end
|
166
|
+
|
167
|
+
if uri.host.nil?
|
168
|
+
raise PropelAuth::InvalidAuthUrl.new
|
169
|
+
end
|
170
|
+
|
171
|
+
"#{uri.scheme}://#{uri.host}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class << self
|
176
|
+
def configuration
|
177
|
+
@configuration ||= Configuration.new
|
178
|
+
end
|
179
|
+
|
180
|
+
def configure
|
181
|
+
yield(configuration)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: propelauth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Israel
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-04-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jwt
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: railties
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 4.1.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 4.1.0
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- support@propelauth.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- Gemfile
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- lib/propelauth.rb
|
67
|
+
- lib/propelauth/client.rb
|
68
|
+
- lib/propelauth/error.rb
|
69
|
+
- lib/propelauth/version.rb
|
70
|
+
homepage: https://github.com/PropelAuth/propelauth-rb
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata:
|
74
|
+
homepage_uri: https://github.com/PropelAuth/propelauth-rb
|
75
|
+
source_code_uri: https://github.com/PropelAuth/propelauth-rb
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 2.3.0
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubygems_version: 3.3.7
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: A ruby gem for managing authentication, backed by PropelAuth
|
95
|
+
test_files: []
|