Module: Everywhere::OmniAuth
- Defined in:
- lib/everywhere/omniauth.rb
Overview
OmniAuth 2 and the native sign-in flow, introduced to each other.
Since CVE-2015-9284, OmniAuth only starts a provider flow from a POST carrying a CSRF token (omniauth-rails_csrf_protection). Right for browsers — and impossible for the native flow, which enters the provider path through /everywhere/auth/start's redirect: a GET, in a browser session that has no CSRF token to give. Without help, tapping "Sign in with GitHub" in the app ends on OmniAuth's failure page.
# config/initializers/omniauth.rb, after your provider setup
require "everywhere/omniauth"
Everywhere::OmniAuth.protect!
Browsers keep exactly the validation they had — whatever request_validation_phase was set to keeps running. The one extra shape allowed through is the native flow's entry: a top-level, not-cross-site GET carrying a marker cookie that /everywhere/auth/start sealed seconds ago. Nobody else can mint that marker (AES-GCM under the app's secret), start refuses cross-site initiators outright, and the freshness window means a marker lingering in Safari's jar after a real sign-in stops vouching for anything almost immediately.
Defined Under Namespace
Classes: RequestValidator
Constant Summary collapse
- ENTRY_WINDOW =
How long after start seals the marker its GET still reads as the native flow arriving. The real gap is one redirect — milliseconds — but the sheet can sit on our page briefly on a slow network; anything past this is a browser wandering in.
90
Class Method Summary collapse
-
.protect!(entry_window: ENTRY_WINDOW) ⇒ Object
Wire OmniAuth's global config: allow GET request phases (they're refused per-request by the validator unless they prove themselves), and wrap the configured validation phase so everything that isn't the native entry is judged exactly as before.
Class Method Details
.protect!(entry_window: ENTRY_WINDOW) ⇒ Object
Wire OmniAuth's global config: allow GET request phases (they're refused per-request by the validator unless they prove themselves), and wrap the configured validation phase so everything that isn't the native entry is judged exactly as before. Safe to call more than once — re-running replaces the wrapper, never stacks it.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/everywhere/omniauth.rb', line 40 def protect!(entry_window: ENTRY_WINDOW) unless defined?(::OmniAuth) && ::OmniAuth.respond_to?(:config) raise "Everywhere::OmniAuth.protect! needs OmniAuth loaded first — " \ "call it below your OmniAuth/Devise setup (config/initializers/omniauth.rb)" end config = ::OmniAuth.config config.allowed_request_methods = Array(config.allowed_request_methods) | [:get] config.silence_get_warning = true if config.respond_to?(:silence_get_warning=) fallback = config.request_validation_phase fallback = fallback.fallback if fallback.is_a?(RequestValidator) config.request_validation_phase = RequestValidator.new(fallback: fallback, entry_window: entry_window) end |