Class: StandardId::Engine
- Inherits:
-
Rails::Engine
- Object
- Rails::Engine
- StandardId::Engine
- Defined in:
- lib/standard_id/engine.rb
Class Method Summary collapse
-
.verify_host_cookie_encryption!(app) ⇒ Object
Defensive check: StandardId's Web::SessionManager stores session tokens in
cookies.encrypted[:session_token]in addition tosession[:...]. -
.warn_if_allowed_audiences_empty_in_production! ⇒ Object
Logs a production-only warning when no global audience allow-list is configured.
Class Method Details
.verify_host_cookie_encryption!(app) ⇒ Object
Defensive check: StandardId's Web::SessionManager stores session tokens
in cookies.encrypted[:session_token] in addition to session[:...].
If the host app is somehow missing a secret_key_base, encrypted cookies
fall back to plaintext and session tokens leak to the client. Rails 8
apps always have a secret_key_base, but this check catches misconfigured
test harnesses, custom boot sequences, and host apps that blank it out.
We warn (not raise) to avoid breaking apps that intentionally short-
circuit boot (e.g., assets:precompile rake tasks with no secrets
available). A hard failure would be hostile to those workflows.
IMPORTANT: we must NOT call app.secret_key_base directly. Rails 8.1's
getter runs the "generate + persist" path on first read, which in turn
invokes the setter — and the setter raises when the resolved value is
blank (which is exactly the case this check is meant to warn about).
So calling the getter here would turn a soft warning into a hard boot
failure under parallel workers (e.g. parallel_rspec's parallel:create)
that don't share a generated key between processes. Instead we read
the same underlying sources Rails resolves from (ENV, then credentials)
without triggering the write path.
72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/standard_id/engine.rb', line 72 def self.(app) secret = host_secret_key_base(app) if secret.blank? Rails.logger.warn( "[StandardId] Host application has no secret_key_base configured. " \ "Encrypted cookies will not be available and session tokens stored in " \ "cookies.encrypted will be persisted in plaintext. Configure " \ "Rails.application.credentials.secret_key_base (or ENV['SECRET_KEY_BASE']) " \ "before running in production." ) end end |
.warn_if_allowed_audiences_empty_in_production! ⇒ Object
Logs a production-only warning when no global audience allow-list is
configured. With allowed_audiences empty, the API token manager
skips decode-time aud enforcement, leaving cross-audience JWT replay
mitigation dependent on per-controller AudienceVerification
inclusion. Extracted to a module method so specs can exercise it
directly without booting a second Rails app.
113 114 115 116 117 118 119 120 121 122 |
# File 'lib/standard_id/engine.rb', line 113 def self.warn_if_allowed_audiences_empty_in_production! return unless Rails.env.production? return if StandardId.config.oauth.allowed_audiences.present? Rails.logger.warn( "StandardId: config.oauth.allowed_audiences is empty in production — " \ "JWT audience is not enforced globally. Set this to your expected " \ "audiences (e.g., ['web', 'api']) to close cross-audience replay vectors." ) end |