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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 355b1a9e875355d5a3c5c7ca9c83dd24af066e1c69e89c9030fab8bb2c5a3f71
4
- data.tar.gz: e151caf3879396e067aaf2c7f5ba0228fece3de07c5bdf41ac3df3e37d271ab9
3
+ metadata.gz: b5246ed44e15045cae4b9ec776d95b29e3f30f40008b41081c44acc61105e3de
4
+ data.tar.gz: 0d72626e7d23203a12ff37dbbf1516664f2043a52423404a9fdd43cd9ddc85ee
5
5
  SHA512:
6
- metadata.gz: e9709c05464dade807e95a135d6c5fe7d4e301127c4ea23209086298bc3078882cd1c5454262b1bc1759d1b48b27ac7cd630690e735a210f354bbb20fea808e8
7
- data.tar.gz: 505983dd1f954880f7ad1a9a6e33beaf3ff83734c5034f90f5515d1ac0d48bac7c6b4e75842aeb7860695bf10efd7aba24c012cafd97b7e1089270d853c0bb23
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 path exclusions for public endpoints
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
- # config/application.rb
83
- config.middleware.insert_before 0, RackJwtAegis::Middleware, {
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
- skip_paths: ['/api/v1/login', '/health']
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
- skip_paths: ['/login', '/health']
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
- # Path Configuration
146
- skip_paths: ['/health', '/api/v1/login'],
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RackJwtAegis
4
- VERSION = '1.1.1'
4
+ VERSION = '1.2.0'
5
5
  end
@@ -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.1.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: 3.6.9
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: []