rack_jwt_aegis 1.1.1 → 1.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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +36 -7
- data/lib/rack_jwt_aegis/configuration.rb +12 -0
- data/lib/rack_jwt_aegis/middleware.rb +5 -1
- data/lib/rack_jwt_aegis/version.rb +1 -1
- data/lib/rack_jwt_aegis.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b5246ed44e15045cae4b9ec776d95b29e3f30f40008b41081c44acc61105e3de
|
|
4
|
+
data.tar.gz: 0d72626e7d23203a12ff37dbbf1516664f2043a52423404a9fdd43cd9ddc85ee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b2ac0d480d1e060e36e114fccfb373c6c6602913f49f227c94d24feb112590f877146e903c3dfdc726c2dc2c130ae9f1c183a968febba522e1607e2483cfba09
|
|
7
|
+
data.tar.gz: 2c349695ae61b01a65fd87f8de710d85f356e29b0328a639ea5aef5548c40140aaa4395a5245fb0374caabdaa9dd11abf14c88a161275f4f4bd3b0f233bda621
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## [1.2.0] - 2026-08-24
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `skip_options_requests` to bypass JWT authentication for CORS preflight
|
|
10
|
+
requests while leaving ordinary requests protected.
|
|
11
|
+
- Documented the intended middleware ordering: `Rack::Cors` must run before
|
|
12
|
+
`RackJwtAegis::Middleware`.
|
|
13
|
+
|
|
5
14
|
## [1.1.1] - 2026-06-13
|
|
6
15
|
|
|
7
16
|
### 🚀 Added
|
data/README.md
CHANGED
|
@@ -15,7 +15,8 @@ JWT authentication and authorization middleware for hierarchical multi-tenant Ra
|
|
|
15
15
|
- Subdomain-based tenant isolation for top-level tenants
|
|
16
16
|
- URL pathname slug access control for sub-level tenants
|
|
17
17
|
- **RBAC (Role-Based Access Control)** with flexible role extraction from JWT payloads
|
|
18
|
-
- Configurable
|
|
18
|
+
- Configurable route exclusions for public endpoints
|
|
19
|
+
- Optional automatic bypass for browser CORS preflight requests
|
|
19
20
|
- **Flexible payload mapping** for custom JWT claim names
|
|
20
21
|
- Custom payload validation
|
|
21
22
|
- Debug mode for development
|
|
@@ -79,15 +80,36 @@ Rack JWT Aegis includes a command-line tool for generating secure JWT secrets:
|
|
|
79
80
|
### Rails Application
|
|
80
81
|
|
|
81
82
|
```ruby
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
# config/initializers/cors.rb
|
|
84
|
+
Rails.application.config.middleware.insert_before 0, Rack::Cors do
|
|
85
|
+
allow do
|
|
86
|
+
origins 'https://app.example.com'
|
|
87
|
+
resource '*', headers: :any,
|
|
88
|
+
methods: %i[get post put patch delete options head]
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# config/initializers/rack_jwt_aegis.rb
|
|
93
|
+
Rails.application.config.middleware.insert_after Rack::Cors, RackJwtAegis::Middleware, {
|
|
84
94
|
jwt_secret: ENV['JWT_SECRET'],
|
|
85
95
|
validate_tenant_id: true,
|
|
86
96
|
tenant_id_header_name: 'X-Tenant-Id',
|
|
87
|
-
|
|
97
|
+
# Browser OPTIONS preflight requests do not carry bearer credentials.
|
|
98
|
+
skip_options_requests: true,
|
|
99
|
+
skip_routes: [
|
|
100
|
+
{ path: '/api/v1/login', verbs: [:post] },
|
|
101
|
+
{ path: '/health' }
|
|
102
|
+
]
|
|
88
103
|
}
|
|
89
104
|
```
|
|
90
105
|
|
|
106
|
+
`Rack::Cors` should run before `RackJwtAegis::Middleware` in the Rack stack.
|
|
107
|
+
It can then validate the request origin, requested method, and requested
|
|
108
|
+
headers and handle valid preflight requests before JWT authentication runs.
|
|
109
|
+
`skip_options_requests: true` is an additional middleware-level safeguard: it
|
|
110
|
+
skips JWT authentication for `OPTIONS` requests only. It does not make any
|
|
111
|
+
non-`OPTIONS` request public, and it does not replace CORS validation.
|
|
112
|
+
|
|
91
113
|
### Sinatra Application
|
|
92
114
|
|
|
93
115
|
```ruby
|
|
@@ -97,7 +119,10 @@ Rack JWT Aegis includes a command-line tool for generating secure JWT secrets:
|
|
|
97
119
|
jwt_secret: ENV['JWT_SECRET'],
|
|
98
120
|
validate_tenant_id: true,
|
|
99
121
|
tenant_id_header_name: 'X-Tenant-Id',
|
|
100
|
-
|
|
122
|
+
skip_routes: [
|
|
123
|
+
{ path: '/login', verbs: [:post] },
|
|
124
|
+
{ path: '/health' }
|
|
125
|
+
]
|
|
101
126
|
}
|
|
102
127
|
```
|
|
103
128
|
|
|
@@ -142,8 +167,12 @@ RackJwtAegis::Middleware.new(app, {
|
|
|
142
167
|
role_ids: :role_ids,
|
|
143
168
|
},
|
|
144
169
|
|
|
145
|
-
#
|
|
146
|
-
|
|
170
|
+
# Route Configuration
|
|
171
|
+
skip_options_requests: false, # Set true when Rack::Cors handles browser preflight requests
|
|
172
|
+
skip_routes: [
|
|
173
|
+
{ path: '/health' },
|
|
174
|
+
{ path: '/api/v1/login', verbs: [:post] }
|
|
175
|
+
],
|
|
147
176
|
pathname_slug_pattern: /^\/api\/v1\/([^\/]+)\//, # Default pattern
|
|
148
177
|
|
|
149
178
|
# RBAC Configuration
|
|
@@ -55,6 +55,10 @@ module RackJwtAegis
|
|
|
55
55
|
# @return [Boolean] true if strict authenticated request headers are required
|
|
56
56
|
attr_accessor :require_authentication_headers
|
|
57
57
|
|
|
58
|
+
# Whether HTTP OPTIONS preflight requests should bypass JWT authentication
|
|
59
|
+
# @return [Boolean] true if OPTIONS requests are treated as CORS preflight
|
|
60
|
+
attr_accessor :skip_options_requests
|
|
61
|
+
|
|
58
62
|
# Whether JWTs must include expiration-related claims
|
|
59
63
|
# @return [Boolean] true if exp and iat claims are required
|
|
60
64
|
attr_accessor :require_expiration_claims
|
|
@@ -178,6 +182,7 @@ module RackJwtAegis
|
|
|
178
182
|
# @option options [String] :jwt_algorithm ('HS256') JWT algorithm to use
|
|
179
183
|
# @option options [Boolean] :validate_subdomain (false) enable subdomain validation
|
|
180
184
|
# @option options [Boolean] :validate_pathname_slug (false) enable pathname slug validation
|
|
185
|
+
# @option options [Boolean] :skip_options_requests (false) bypass JWT authentication for OPTIONS requests
|
|
181
186
|
# @option options [Boolean] :rbac_enabled (false) enable RBAC authorization
|
|
182
187
|
# @option options [String] :tenant_id_header_name ('X-Tenant-Id') tenant ID header name
|
|
183
188
|
# @option options [Regexp] :pathname_slug_pattern default pattern for pathname slugs
|
|
@@ -242,6 +247,12 @@ module RackJwtAegis
|
|
|
242
247
|
config_boolean?(require_authentication_headers)
|
|
243
248
|
end
|
|
244
249
|
|
|
250
|
+
# Check if OPTIONS requests bypass JWT authentication
|
|
251
|
+
# @return [Boolean] true if CORS preflight requests are skipped
|
|
252
|
+
def skip_options_requests?
|
|
253
|
+
config_boolean?(skip_options_requests)
|
|
254
|
+
end
|
|
255
|
+
|
|
245
256
|
# Check if exp and iat claims are required
|
|
246
257
|
# @return [Boolean] true if expiration claims are required
|
|
247
258
|
def require_expiration_claims?
|
|
@@ -312,6 +323,7 @@ module RackJwtAegis
|
|
|
312
323
|
@validate_pathname_slug = false
|
|
313
324
|
@validate_tenant_id = false
|
|
314
325
|
@require_authentication_headers = false
|
|
326
|
+
@skip_options_requests = false
|
|
315
327
|
@require_expiration_claims = false
|
|
316
328
|
@tenant_id_header_name = 'X-Tenant-Id'
|
|
317
329
|
@tenant_slug_header_name = 'X-Tenant-Slug'
|
|
@@ -65,7 +65,7 @@ module RackJwtAegis
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
# Step 1: Check if route should be skipped
|
|
68
|
-
if @config.skip_request?(request.path, request.request_method)
|
|
68
|
+
if preflight_request?(request) || @config.skip_request?(request.path, request.request_method)
|
|
69
69
|
debug_log("Skipping authentication for route: #{request.request_method} #{request.path}")
|
|
70
70
|
return call_app(env)
|
|
71
71
|
end
|
|
@@ -155,6 +155,10 @@ module RackJwtAegis
|
|
|
155
155
|
@config.require_authentication_headers?
|
|
156
156
|
end
|
|
157
157
|
|
|
158
|
+
def preflight_request?(request)
|
|
159
|
+
@config.skip_options_requests? && request.request_method == 'OPTIONS'
|
|
160
|
+
end
|
|
161
|
+
|
|
158
162
|
def build_circuit_breaker
|
|
159
163
|
return nil unless @config.circuit_breaker_enabled?
|
|
160
164
|
|
data/lib/rack_jwt_aegis.rb
CHANGED
|
@@ -25,6 +25,7 @@ require_relative 'rack_jwt_aegis/response_builder'
|
|
|
25
25
|
# - Multiple cache adapter support (Memory, Redis, Memcached, SolidCache)
|
|
26
26
|
# - Request context management
|
|
27
27
|
# - Configurable skip routes and custom validators
|
|
28
|
+
# - Optional automatic bypass for CORS preflight requests
|
|
28
29
|
#
|
|
29
30
|
# @example Basic usage
|
|
30
31
|
# use RackJwtAegis::Middleware, jwt_secret: ENV['JWT_SECRET']
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rack_jwt_aegis
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ken C. Demanawa
|
|
@@ -120,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
120
120
|
- !ruby/object:Gem::Version
|
|
121
121
|
version: '0'
|
|
122
122
|
requirements: []
|
|
123
|
-
rubygems_version:
|
|
123
|
+
rubygems_version: 4.0.16
|
|
124
124
|
specification_version: 4
|
|
125
125
|
summary: JWT authentication and authorization middleware for multi-tenant Rack applications
|
|
126
126
|
test_files: []
|