Skip to content

Commit b51a33f

Browse files
committed
Auto-require omniauth-rails_csrf_protection in the gem entry point
Without this, a host app that uses `gem "activeadmin-oidc"` never triggers the `omniauth-rails_csrf_protection` railtie: Bundler.require only auto-requires top-level Gemfile entries, not transitive gemspec dependencies. The result is that OmniAuth 2.x's Rack-level CSRF check runs against `button_to` posts and rejects them with OmniAuth::AuthenticityError. Requiring the railtie from the gem's own entry point registers OmniAuth::RailsCsrfProtection::Railtie with Rails before the initializer phase runs, so Rails' forgery protection transparently takes over for OmniAuth POSTs. Also pulls rails/railtie first so the require is safe outside of a fully-booted Rails environment (e.g. plain spec_helper contexts). Hit live during end-to-end testing with the Zitadel demo app.
1 parent 063cce8 commit b51a33f

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

lib/activeadmin-oidc.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
require "activeadmin/oidc/version"
44

5+
# `omniauth-rails_csrf_protection` registers a Railtie that replaces
6+
# OmniAuth 2.x's Rack-level authenticity check with Rails' own forgery
7+
# protection. It's a runtime dependency of this gem, but `Bundler.require`
8+
# in host apps only auto-requires top-level Gemfile entries — not
9+
# transitive deps pulled in via our gemspec. We `require` it here so
10+
# that the railtie gets loaded whenever a host does
11+
# `gem "activeadmin-oidc"`, and CSRF-protected OmniAuth POSTs work
12+
# out of the box with `button_to`-style login buttons.
13+
#
14+
# `omniauth/rails_csrf_protection/railtie` references `Rails::Railtie`
15+
# at file load, so pull in the minimal Railtie base class first — this
16+
# keeps the require safe even in spec_helper contexts where the full
17+
# Rails stack hasn't been initialized yet.
18+
require "rails/railtie"
19+
require "omniauth/rails_csrf_protection"
20+
521
module ActiveAdmin
622
module Oidc
723
class Error < StandardError; end

spec/unit/packaging_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
5+
# These are packaging-correctness tests: they verify that the gem's
6+
# main entry point wires in all the runtime glue a host app needs after
7+
# a plain `gem "activeadmin-oidc"` + `Bundler.require`.
8+
#
9+
# Why text-level? `Bundler.require` only auto-requires gems listed in
10+
# the Gemfile, not the transitive dependencies pulled in via our
11+
# gemspec. So a host that does `gem "activeadmin-oidc"` will NOT
12+
# auto-load `omniauth-rails_csrf_protection` — our gem has to require
13+
# it explicitly. The gem's own Gemfile uses `gemspec` which DOES load
14+
# all runtime deps, so a behavior test inside this suite would always
15+
# pass and silently miss regressions. Parsing the entry-point file
16+
# catches that.
17+
RSpec.describe "packaging" do
18+
let(:entry_point_path) do
19+
File.expand_path("../../lib/activeadmin-oidc.rb", __dir__)
20+
end
21+
22+
let(:entry_point_source) { File.read(entry_point_path) }
23+
24+
it "requires omniauth/rails_csrf_protection so its railtie registers before the app boots" do
25+
expect(entry_point_source).to match(/^require\s+["']omniauth\/rails_csrf_protection["']/)
26+
end
27+
28+
it "loads OmniAuth::RailsCsrfProtection::TokenVerifier at require time" do
29+
# Second guard: even if the grep above drifted, the constant must
30+
# exist by the time the gem is loaded.
31+
require "activeadmin-oidc"
32+
expect(defined?(OmniAuth::RailsCsrfProtection::TokenVerifier))
33+
.to eq("constant")
34+
end
35+
end

0 commit comments

Comments
 (0)