jwt_auth_cognito 0.1.1 → 1.0.0.pre.beta.1
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 +4 -4
- data/.rubocop.yml +78 -0
- data/BITBUCKET-DEPLOYMENT.md +290 -0
- data/CHANGELOG.md +65 -0
- data/CLAUDE.md +189 -9
- data/Gemfile +5 -5
- data/README.md +147 -1
- data/Rakefile +108 -5
- data/VERSIONING.md +244 -0
- data/bitbucket-pipelines.yml +273 -0
- data/jwt_auth_cognito.gemspec +42 -39
- data/lib/generators/jwt_auth_cognito/install_generator.rb +25 -25
- data/lib/jwt_auth_cognito/api_key_validator.rb +79 -0
- data/lib/jwt_auth_cognito/configuration.rb +38 -21
- data/lib/jwt_auth_cognito/error_utils.rb +110 -0
- data/lib/jwt_auth_cognito/jwks_service.rb +46 -50
- data/lib/jwt_auth_cognito/jwt_validator.rb +319 -92
- data/lib/jwt_auth_cognito/railtie.rb +3 -3
- data/lib/jwt_auth_cognito/redis_service.rb +90 -51
- data/lib/jwt_auth_cognito/ssm_service.rb +109 -0
- data/lib/jwt_auth_cognito/token_blacklist_service.rb +10 -12
- data/lib/jwt_auth_cognito/user_data_service.rb +332 -0
- data/lib/jwt_auth_cognito/version.rb +2 -2
- data/lib/jwt_auth_cognito.rb +42 -10
- data/lib/tasks/jwt_auth_cognito.rake +69 -70
- metadata +63 -26
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'jwt'
|
4
4
|
|
5
5
|
module JwtAuthCognito
|
6
6
|
class JwtValidator
|
@@ -8,44 +8,221 @@ module JwtAuthCognito
|
|
8
8
|
@config = config
|
9
9
|
@jwks_service = JwksService.new(config)
|
10
10
|
@blacklist_service = TokenBlacklistService.new(config)
|
11
|
+
@api_key_validator = config.enable_api_key_validation ? ApiKeyValidator.new(config) : nil
|
12
|
+
@user_data_service = config.enable_user_data_retrieval ? UserDataService.new(nil, config.user_data_config) : nil
|
13
|
+
@initialized = false
|
11
14
|
end
|
12
15
|
|
13
|
-
def
|
16
|
+
def initialize!
|
17
|
+
return if @initialized
|
18
|
+
|
19
|
+
begin
|
20
|
+
@jwks_service.initialize!
|
21
|
+
@blacklist_service.initialize! if @blacklist_service.respond_to?(:initialize!)
|
22
|
+
@user_data_service&.initialize!
|
23
|
+
@initialized = true
|
24
|
+
rescue StandardError => e
|
25
|
+
ErrorUtils.log_error(e, 'JWT Validator initialization failed')
|
26
|
+
raise JwtAuthCognito::ConfigurationError, ErrorUtils::JWT_ERROR_MESSAGES['INITIALIZATION_FAILED']
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# ========== 🚀 MAIN VALIDATION METHOD ==========
|
31
|
+
|
32
|
+
# Main validation method - use this for most cases
|
33
|
+
# Intelligently validates tokens with all features:
|
34
|
+
# - JWT validation (basic or secure)
|
35
|
+
# - API key validation (if provided)
|
36
|
+
# - Blacklist checking
|
37
|
+
# - Automatic appId verification
|
38
|
+
# - User data enrichment (if enabled)
|
39
|
+
def validate(token, options = {})
|
14
40
|
@config.validate!
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
41
|
+
|
42
|
+
api_key = options[:api_key]
|
43
|
+
force_secure = options[:force_secure] || false
|
44
|
+
enrich_user_data = options.fetch(:enrich_user_data, true)
|
45
|
+
require_app_access = options[:require_app_access] || false
|
46
|
+
|
47
|
+
# Step 1: Validate API key if provided
|
48
|
+
api_key_data = nil
|
49
|
+
if api_key && @config.enable_api_key_validation && @api_key_validator
|
50
|
+
api_key_result = @api_key_validator.validate_api_key(api_key)
|
51
|
+
return { valid: false, error: api_key_result[:error] || 'API key validation failed' } unless api_key_result[:valid]
|
52
|
+
|
53
|
+
api_key_data = api_key_result[:key_data]
|
19
54
|
end
|
20
55
|
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
56
|
+
# Step 2: Check blacklist first
|
57
|
+
return { valid: false, error: 'Token has been revoked' } if @blacklist_service.is_blacklisted?(token)
|
58
|
+
|
59
|
+
# Step 3: Validate JWT token
|
60
|
+
validation_mode = force_secure ? :secure : @config.validation_mode
|
61
|
+
token_result = case validation_mode
|
62
|
+
when :secure
|
63
|
+
validate_token_secure(token, options)
|
64
|
+
when :basic
|
65
|
+
validate_token_basic(token, options)
|
66
|
+
else
|
67
|
+
raise ConfigurationError, "Invalid validation_mode: #{validation_mode}"
|
68
|
+
end
|
69
|
+
|
70
|
+
return token_result unless token_result[:valid] && token_result[:payload]
|
71
|
+
|
72
|
+
# Step 4: Verify appId access if API key has one
|
73
|
+
if api_key_data
|
74
|
+
app_validation = verify_app_access(api_key_data, token_result[:payload], require_app_access)
|
75
|
+
return app_validation unless app_validation[:valid]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Step 5: Enrich with user data if requested
|
79
|
+
enriched_result = token_result.dup
|
80
|
+
enriched_result[:api_key] = api_key_data if api_key_data
|
81
|
+
|
82
|
+
if enrich_user_data && @config.enable_user_data_retrieval && @user_data_service
|
83
|
+
user_id = token_result[:payload]['sub']
|
84
|
+
if user_id
|
85
|
+
begin
|
86
|
+
user_data = @user_data_service.get_comprehensive_user_data(user_id)
|
87
|
+
enriched_result[:user_permissions] = user_data['permissions']
|
88
|
+
enriched_result[:user_organizations] = user_data['organizations']
|
89
|
+
enriched_result[:applications] = user_data['applications']
|
90
|
+
rescue StandardError => e
|
91
|
+
ErrorUtils.log_error(e, 'User data retrieval failed')
|
92
|
+
# Continue with basic validation if user data service fails
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
enriched_result
|
98
|
+
end
|
99
|
+
|
100
|
+
# ========== SIMPLIFIED PUBLIC API ==========
|
101
|
+
|
102
|
+
# Quick validation for simple use cases
|
103
|
+
# Just validates the JWT token (includes blacklist check)
|
104
|
+
def validate_token(token, options = {})
|
105
|
+
result = validate(token, options.merge(enrich_user_data: false))
|
106
|
+
{
|
107
|
+
valid: result[:valid],
|
108
|
+
payload: result[:payload],
|
109
|
+
sub: result[:sub],
|
110
|
+
username: result[:username],
|
111
|
+
token_use: result[:token_use],
|
112
|
+
error: result[:error]
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
# Validate with API key (automatic appId verification)
|
117
|
+
# Use this when you have an API key and want automatic security
|
118
|
+
def validate_with_api_key(token, api_key, options = {})
|
119
|
+
validate(token, options.merge(api_key: api_key))
|
120
|
+
end
|
121
|
+
|
122
|
+
# Validate with strict appId requirement
|
123
|
+
# Use this when you MUST ensure user has access to a specific app
|
124
|
+
def validate_with_app_access(token, api_key, options = {})
|
125
|
+
validate(token, options.merge(api_key: api_key, require_app_access: true))
|
126
|
+
end
|
127
|
+
|
128
|
+
# Get enriched validation (user data included)
|
129
|
+
# Use this when you need user permissions, organizations, apps
|
130
|
+
def validate_enriched(token, api_key = nil, options = {})
|
131
|
+
validate(token, options.merge(api_key: api_key, enrich_user_data: true))
|
132
|
+
end
|
133
|
+
|
134
|
+
# ========== LEGACY METHODS (DEPRECATED) ==========
|
135
|
+
|
136
|
+
# @deprecated Use validate() or validate_with_api_key() instead
|
137
|
+
def validate_token_with_api_key(token, api_key = nil, options = {})
|
138
|
+
puts 'WARNING: validate_token_with_api_key is deprecated. Use validate() or validate_with_api_key() instead.'
|
139
|
+
result = validate(token, options.merge(api_key: api_key, enrich_user_data: false))
|
140
|
+
{
|
141
|
+
valid: result[:valid],
|
142
|
+
payload: result[:payload],
|
143
|
+
sub: result[:sub],
|
144
|
+
username: result[:username],
|
145
|
+
token_use: result[:token_use],
|
146
|
+
api_key: result[:api_key],
|
147
|
+
error: result[:error]
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
# @deprecated Use validate_with_app_access() instead
|
152
|
+
def validate_token_with_app_id(token, api_key, options = {})
|
153
|
+
puts 'WARNING: validate_token_with_app_id is deprecated. Use validate_with_app_access() instead.'
|
154
|
+
validate_with_app_access(token, api_key, options.merge(enrich_user_data: false))
|
155
|
+
end
|
156
|
+
|
157
|
+
# @deprecated Use validate() instead
|
158
|
+
def validate_token_enhanced(token, api_key = nil, options = {})
|
159
|
+
puts 'WARNING: validate_token_enhanced is deprecated. Use validate() instead.'
|
160
|
+
result = validate(token, options.merge(api_key: api_key, enrich_user_data: false))
|
161
|
+
{
|
162
|
+
valid: result[:valid],
|
163
|
+
payload: result[:payload],
|
164
|
+
sub: result[:sub],
|
165
|
+
username: result[:username],
|
166
|
+
token_use: result[:token_use],
|
167
|
+
api_key: result[:api_key],
|
168
|
+
error: result[:error]
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
# @deprecated Use validate_enriched() instead
|
173
|
+
def validate_token_enriched(token, api_key = nil, options = {})
|
174
|
+
puts 'WARNING: validate_token_enriched is deprecated. Use validate_enriched() instead.'
|
175
|
+
validate_enriched(token, api_key, options)
|
176
|
+
end
|
177
|
+
|
178
|
+
def old_validate_token_enriched(token, api_key = nil, options = {})
|
179
|
+
# First, perform standard token validation
|
180
|
+
basic_result = validate_token_with_api_key(token, api_key, options)
|
181
|
+
|
182
|
+
# If basic validation fails, return early
|
183
|
+
return basic_result unless basic_result[:valid] && basic_result[:payload]
|
184
|
+
|
185
|
+
# If user data retrieval is not enabled, return basic result
|
186
|
+
return basic_result unless @config.enable_user_data_retrieval && @user_data_service
|
187
|
+
|
188
|
+
# Extract user ID from the token
|
189
|
+
user_id = basic_result[:payload]['sub']
|
190
|
+
unless user_id
|
191
|
+
puts 'Token does not contain sub claim, cannot retrieve user data'
|
192
|
+
return basic_result
|
193
|
+
end
|
194
|
+
|
195
|
+
begin
|
196
|
+
# Get comprehensive user data from Redis
|
197
|
+
user_data = @user_data_service.get_comprehensive_user_data(user_id)
|
198
|
+
|
199
|
+
# Add user data to the result
|
200
|
+
enriched_result = basic_result.dup
|
201
|
+
enriched_result[:user_permissions] = user_data['permissions']
|
202
|
+
enriched_result[:user_organizations] = user_data['organizations']
|
203
|
+
enriched_result[:applications] = user_data['applications']
|
204
|
+
|
205
|
+
enriched_result
|
206
|
+
rescue StandardError => e
|
207
|
+
ErrorUtils.log_error(e, 'User data retrieval failed')
|
208
|
+
# Return basic result even if user data retrieval fails
|
209
|
+
basic_result
|
29
210
|
end
|
30
211
|
end
|
31
212
|
|
32
213
|
def validate_access_token(token)
|
33
214
|
result = validate_token(token)
|
34
|
-
|
35
|
-
if result[:valid] && result[:payload][
|
36
|
-
|
37
|
-
end
|
38
|
-
|
215
|
+
|
216
|
+
return { valid: false, error: 'Token is not an access token' } if result[:valid] && result[:payload]['token_use'] != 'access'
|
217
|
+
|
39
218
|
result
|
40
219
|
end
|
41
220
|
|
42
221
|
def validate_id_token(token)
|
43
222
|
result = validate_token(token)
|
44
|
-
|
45
|
-
if result[:valid] && result[:payload][
|
46
|
-
|
47
|
-
end
|
48
|
-
|
223
|
+
|
224
|
+
return { valid: false, error: 'Token is not an ID token' } if result[:valid] && result[:payload]['token_use'] != 'id'
|
225
|
+
|
49
226
|
result
|
50
227
|
end
|
51
228
|
|
@@ -64,11 +241,34 @@ module JwtAuthCognito
|
|
64
241
|
# Utility methods inspired by Node.js package
|
65
242
|
def extract_token_from_header(authorization_header)
|
66
243
|
return nil unless authorization_header
|
67
|
-
|
244
|
+
|
68
245
|
match = authorization_header.match(/\ABearer (.+)\z/)
|
69
246
|
match ? match[1] : nil
|
70
247
|
end
|
71
248
|
|
249
|
+
def extract_api_key_from_header(api_key_header)
|
250
|
+
# Support common API key header formats
|
251
|
+
return nil unless api_key_header
|
252
|
+
|
253
|
+
api_key_header.strip
|
254
|
+
end
|
255
|
+
|
256
|
+
def extract_api_key_from_headers(headers)
|
257
|
+
# Check various common API key header names (case insensitive)
|
258
|
+
api_key_headers = %w[x-api-key X-API-Key X-API-KEY X-Api-Key]
|
259
|
+
|
260
|
+
api_key_headers.each do |header_name|
|
261
|
+
# Convert headers to a case-insensitive hash for lookup
|
262
|
+
header_key = headers.keys.find { |key| key.downcase == header_name.downcase }
|
263
|
+
next unless header_key
|
264
|
+
|
265
|
+
value = headers[header_key]
|
266
|
+
return extract_api_key_from_header(value) if value
|
267
|
+
end
|
268
|
+
|
269
|
+
nil
|
270
|
+
end
|
271
|
+
|
72
272
|
def decode_token(token)
|
73
273
|
JWT.decode(token, nil, false).first
|
74
274
|
rescue JWT::DecodeError => e
|
@@ -80,15 +280,15 @@ module JwtAuthCognito
|
|
80
280
|
return payload if payload.is_a?(Hash) && payload[:error]
|
81
281
|
|
82
282
|
{
|
83
|
-
sub: payload[
|
84
|
-
username: payload[
|
85
|
-
email: payload[
|
86
|
-
token_use: payload[
|
87
|
-
client_id: payload[
|
88
|
-
issued_at: payload[
|
89
|
-
expires_at: payload[
|
90
|
-
not_before: payload[
|
91
|
-
jti: payload[
|
283
|
+
sub: payload['sub'],
|
284
|
+
username: payload['cognito:username'] || payload['username'],
|
285
|
+
email: payload['email'],
|
286
|
+
token_use: payload['token_use'],
|
287
|
+
client_id: payload['aud'],
|
288
|
+
issued_at: payload['iat'] ? Time.at(payload['iat']) : nil,
|
289
|
+
expires_at: payload['exp'] ? Time.at(payload['exp']) : nil,
|
290
|
+
not_before: payload['nbf'] ? Time.at(payload['nbf']) : nil,
|
291
|
+
jti: payload['jti'],
|
92
292
|
has_client_secret: @config.has_client_secret?
|
93
293
|
}
|
94
294
|
end
|
@@ -107,7 +307,7 @@ module JwtAuthCognito
|
|
107
307
|
payload = decode_token(token)
|
108
308
|
return true if payload.is_a?(Hash) && payload[:error]
|
109
309
|
|
110
|
-
exp = payload[
|
310
|
+
exp = payload['exp']
|
111
311
|
return false unless exp
|
112
312
|
|
113
313
|
Time.now.to_i >= exp
|
@@ -117,18 +317,18 @@ module JwtAuthCognito
|
|
117
317
|
payload = decode_token(token)
|
118
318
|
return nil if payload.is_a?(Hash) && payload[:error]
|
119
319
|
|
120
|
-
exp = payload[
|
320
|
+
exp = payload['exp']
|
121
321
|
return nil unless exp
|
122
322
|
|
123
323
|
seconds = exp - Time.now.to_i
|
124
|
-
seconds
|
324
|
+
seconds.positive? ? seconds : 0
|
125
325
|
end
|
126
326
|
|
127
327
|
# Create a convenience factory method
|
128
328
|
def self.create_cognito_validator(config = nil)
|
129
329
|
if config
|
130
330
|
old_config = JwtAuthCognito.configuration
|
131
|
-
JwtAuthCognito.configure { |
|
331
|
+
JwtAuthCognito.configure { |_c| config }
|
132
332
|
validator = new
|
133
333
|
JwtAuthCognito.instance_variable_set(:@configuration, old_config)
|
134
334
|
validator
|
@@ -142,84 +342,111 @@ module JwtAuthCognito
|
|
142
342
|
def validate_token_secure(token, options = {})
|
143
343
|
# Use JWKS validation for production
|
144
344
|
result = @jwks_service.validate_token_with_jwks(token)
|
145
|
-
|
345
|
+
|
146
346
|
if result[:valid]
|
147
347
|
# Additional custom validations
|
148
348
|
validate_custom_claims(result[:payload], options)
|
149
349
|
end
|
150
|
-
|
350
|
+
|
151
351
|
result
|
152
352
|
end
|
153
353
|
|
154
354
|
def validate_token_basic(token, options = {})
|
155
355
|
# Basic validation without signature verification (development only)
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
end
|
356
|
+
|
357
|
+
payload, = JWT.decode(token, nil, false)
|
358
|
+
|
359
|
+
# Basic claim validation
|
360
|
+
validate_basic_claims(payload)
|
361
|
+
validate_custom_claims(payload, options)
|
362
|
+
|
363
|
+
{
|
364
|
+
valid: true,
|
365
|
+
payload: payload,
|
366
|
+
sub: payload['sub'],
|
367
|
+
username: payload['cognito:username'] || payload['username'],
|
368
|
+
token_use: payload['token_use']
|
369
|
+
}
|
370
|
+
rescue JWT::DecodeError => e
|
371
|
+
{ valid: false, error: "JWT decode error: #{e.message}" }
|
372
|
+
rescue ValidationError => e
|
373
|
+
{ valid: false, error: e.message }
|
374
|
+
rescue StandardError => e
|
375
|
+
{ valid: false, error: "Validation error: #{e.message}" }
|
177
376
|
end
|
178
377
|
|
179
378
|
def validate_basic_claims(payload)
|
180
379
|
now = Time.now.to_i
|
181
|
-
|
380
|
+
|
182
381
|
# Check expiration
|
183
|
-
raise ValidationError,
|
184
|
-
|
382
|
+
raise ValidationError, 'Token has expired' if payload['exp'] && payload['exp'] < now
|
383
|
+
|
185
384
|
# Check issuer
|
186
385
|
expected_issuer = @config.cognito_issuer
|
187
|
-
if payload[
|
188
|
-
|
189
|
-
end
|
190
|
-
|
386
|
+
raise ValidationError, "Invalid issuer. Expected: #{expected_issuer}, got: #{payload['iss']}" if payload['iss'] != expected_issuer
|
387
|
+
|
191
388
|
# Check token use
|
192
|
-
|
193
|
-
|
194
|
-
|
389
|
+
return if %w[access id].include?(payload['token_use'])
|
390
|
+
|
391
|
+
raise ValidationError, 'Invalid token_use claim'
|
195
392
|
end
|
196
393
|
|
197
394
|
def validate_custom_claims(payload, options)
|
198
395
|
# Validate specific user ID if provided
|
199
|
-
if options[:user_id] && payload[
|
200
|
-
|
201
|
-
end
|
202
|
-
|
396
|
+
raise ValidationError, 'Token subject does not match expected user ID' if options[:user_id] && payload['sub'] != options[:user_id]
|
397
|
+
|
203
398
|
# Validate specific client ID if provided
|
204
|
-
if options[:client_id] && payload[
|
205
|
-
|
206
|
-
end
|
207
|
-
|
399
|
+
raise ValidationError, 'Token audience does not match expected client ID' if options[:client_id] && payload['aud'] != options[:client_id]
|
400
|
+
|
208
401
|
# Validate token type if specified
|
209
|
-
if options[:token_use] && payload[
|
210
|
-
|
211
|
-
end
|
212
|
-
|
402
|
+
raise ValidationError, 'Token use does not match expected type' if options[:token_use] && payload['token_use'] != options[:token_use]
|
403
|
+
|
213
404
|
# Custom scope validation
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
405
|
+
return unless options[:required_scopes]
|
406
|
+
|
407
|
+
token_scopes = payload['scope']&.split || []
|
408
|
+
required_scopes = Array(options[:required_scopes])
|
409
|
+
|
410
|
+
missing_scopes = required_scopes - token_scopes
|
411
|
+
return unless missing_scopes.any?
|
412
|
+
|
413
|
+
raise ValidationError, "Token missing required scopes: #{missing_scopes.join(', ')}"
|
414
|
+
end
|
415
|
+
|
416
|
+
def verify_app_access(api_key_data, payload, require_app_access)
|
417
|
+
app_id = api_key_data['appId'] || api_key_data['metadata']&.[]('appId')
|
418
|
+
|
419
|
+
return { valid: false, error: 'API key is not associated with an application' } if !app_id && require_app_access
|
420
|
+
|
421
|
+
return { valid: true } unless app_id
|
422
|
+
|
423
|
+
user_id = payload['sub']
|
424
|
+
return { valid: false, error: 'Token missing user ID (sub claim)' } unless user_id
|
425
|
+
|
426
|
+
verify_user_app_access(user_id, app_id, require_app_access)
|
427
|
+
end
|
428
|
+
|
429
|
+
def verify_user_app_access(user_id, app_id, require_app_access)
|
430
|
+
if require_app_access && (!@config.enable_user_data_retrieval || !@user_data_service)
|
431
|
+
return { valid: false,
|
432
|
+
error: 'User data service not available for application access verification' }
|
433
|
+
end
|
434
|
+
|
435
|
+
return { valid: true } unless @config.enable_user_data_retrieval && @user_data_service
|
436
|
+
|
437
|
+
begin
|
438
|
+
user_applications = @user_data_service.get_user_applications(user_id)
|
439
|
+
has_access = user_applications.any? { |app| app['appId'] == app_id }
|
440
|
+
|
441
|
+
return { valid: false, error: "User does not have access to application #{app_id}" } unless has_access
|
442
|
+
|
443
|
+
{ valid: true }
|
444
|
+
rescue StandardError => e
|
445
|
+
return { valid: false, error: 'Could not verify application access' } if require_app_access
|
446
|
+
|
447
|
+
ErrorUtils.log_error(e, 'User application access verification failed')
|
448
|
+
{ valid: true } # Continue with basic validation if user data service fails
|
222
449
|
end
|
223
450
|
end
|
224
451
|
end
|
225
|
-
end
|
452
|
+
end
|
@@ -3,11 +3,11 @@
|
|
3
3
|
module JwtAuthCognito
|
4
4
|
class Railtie < Rails::Railtie
|
5
5
|
rake_tasks do
|
6
|
-
load
|
6
|
+
load 'tasks/jwt_auth_cognito.rake'
|
7
7
|
end
|
8
8
|
|
9
9
|
generators do
|
10
|
-
require
|
10
|
+
require 'generators/jwt_auth_cognito/install_generator'
|
11
11
|
end
|
12
12
|
end
|
13
|
-
end
|
13
|
+
end
|