You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit bf425a4
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: README.md
+44-6Lines changed: 44 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -50,16 +50,25 @@ OIDC is the only authentication mechanism — `:database_authenticatable`, `encr
50
50
51
51
If `devise_for :admin_users` lives inside a Rails engine (not the main app routes), set `Devise.router_name = :<engine_name>` in `config/initializers/devise.rb` and pass the same option to `devise_for`. The gem reads `Devise.available_router_name` and mounts its session routes inside that engine's route set, so `<Engine>.routes.url_helpers.new_<scope>_session_path` resolves correctly.
52
52
53
-
For **isolated** engines (`isolate_namespace ...`) mounted at a prefix (e.g. `mount AdminPanel::Engine => '/admin'`), the engine prepends its mount path to every internal route. The gem's default`login_path = '/admin/login'` would then become `/admin/admin/login`. Configure engine-relative paths in `config/initializers/activeadmin_oidc.rb`:
53
+
For **isolated** engines (`isolate_namespace ...`) mounted at a prefix (e.g. `mount AdminPanel::Engine => '/admin'`), the engine prepends its mount path to every internal route, so the derived`login_path` of `/admin/login` would become `/admin/admin/login`. Configure engine-relative paths in `config/initializers/activeadmin_oidc.rb`:
54
54
55
55
```ruby
56
56
ActiveAdmin::Oidc.configure do |c|
57
-
c.login_path ='/login'
58
-
c.logout_path ='/logout'
57
+
c.login_path ='/login'
58
+
c.logout_path ='/logout'
59
+
c.omniauth_route_prefix ='/auth'
59
60
end
60
61
```
61
62
62
-
Non-isolated engines don't need this override.
63
+
`omniauth_route_prefix` is the same idea applied to the routes Devise draws for
64
+
OmniAuth. It is separate from `omniauth_path_prefix` because the two are not the
65
+
same string here: the OmniAuth middleware sits in the *application's* Rack stack
66
+
and sees `/admin/auth/oidc` with the mount prefix still attached, while the route
67
+
Devise declares for the callback is inside the engine and gets `/admin` prepended
68
+
to it. Set only `omniauth_path_prefix` and the callback route lands on
69
+
`/admin/admin/auth/oidc/callback`, so the redirect the middleware issues 404s.
70
+
71
+
Non-isolated engines mounted at `/` don't need any of these overrides.
@@ -73,7 +82,7 @@ The gem's Rails engine handles several things so host apps don't have to:
73
82
***Callback controller** — the engine patches `ActiveAdmin::Devise.controllers` to route OmniAuth callbacks to the gem's controller. No manual `controllers: { omniauth_callbacks: ... }` needed in `routes.rb`.
74
83
***Login view override** — the engine prepends an SSO-only login page (no email/password fields) to the sessions controller's view path. If your host app ships its own `app/views/active_admin/devise/sessions/new.html.erb`, the gem detects it and backs off — your view wins.
75
84
***Session routes** — the engine mounts `GET /admin/login` (renders the SSO landing page) and `DELETE /admin/logout` under `devise_scope`, with the scope name derived from `config.admin_user_class`. Devise normally generates session routes as a side effect of `:database_authenticatable`; without that module the route helpers would not exist and ActiveAdmin's login redirect would 404.
76
-
***Path prefix** — the engine sets `Devise.omniauth_path_prefix` and `OmniAuth.config.path_prefix` to `/admin/auth` so the middleware intercepts requests under ActiveAdmin's mount point. Compatible with Rails 7.2+ and Rails 8's lazy route loading.
85
+
***Path prefix** — the engine registers the strategy with `path_prefix: '/admin/auth'` so the middleware intercepts requests under ActiveAdmin's mount point, and sets `Devise.omniauth_path_prefix` to the prefix Devise declares its routes with. Compatible with Rails 7.2+ and Rails 8's lazy route loading.
77
86
***Parameter filtering** — `code`, `id_token`, `access_token`, `refresh_token`, `state`, and `nonce` are added to `Rails.application.config.filter_parameters`.
78
87
79
88
## Configuration
@@ -137,12 +146,41 @@ end
137
146
|`identity_attribute`|`:email`| AdminUser column used for lookup/adoption |
138
147
|`identity_claim`|`:email`| Claim key read from the id_token/userinfo |
139
148
|`admin_user_class`|`"AdminUser"`| String or Class for the host's admin user model |
149
+
|`login_path`|`/<namespace>/login`| SSO landing page path; derived from ActiveAdmin's namespace |
150
+
|`logout_path`|`/<namespace>/logout`| Sign-out path; derived from ActiveAdmin's namespace |
151
+
|`omniauth_path_prefix`|`/<namespace>/auth`| Browser-visible path the OmniAuth middleware listens on; derived from ActiveAdmin's namespace |
152
+
|`omniauth_route_prefix`|`omniauth_path_prefix`| Prefix Devise declares its OmniAuth routes with; differs only for engine-mounted hosts |
140
153
|`login_button_label`|`"Sign in with SSO"`| Label on the login-page button |
141
154
|`access_denied_message`| generic | Flash shown on any denial |
142
155
|`on_login`| — (required) | Authorization hook; see below |
143
156
144
157
`stub_dev_env_login!` is a method, not an option — see "Stub login" below.
145
158
159
+
## ActiveAdmin's namespace
160
+
161
+
Everything the gem mounts hangs off ActiveAdmin's namespace, and all of it is
162
+
derived from `ActiveAdmin.application.default_namespace` rather than assumed to
163
+
be `admin`. A host that renames it:
164
+
165
+
```ruby
166
+
# config/initializers/active_admin.rb
167
+
config.default_namespace =:backoffice
168
+
```
169
+
170
+
gets `/backoffice/login`, `/backoffice/logout`, the OmniAuth middleware at
171
+
`/backoffice/auth`, and a post-sign-in redirect to `/backoffice` — no gem
false`) mounts everything at the top level: `/login`, `/auth`, `/`.
174
+
175
+
Each is still overridable. Isolated engines *have* to override them, since the
176
+
engine's mount prefix is prepended to every path declared inside it — see
177
+
[Engine-mounted Devise](#engine-mounted-devise).
178
+
179
+
`omniauth_route_prefix` is what the gem assigns to `Devise.omniauth_path_prefix`,
180
+
and it is skipped entirely if your app already assigned that in
181
+
`config/initializers/devise.rb`. `omniauth_path_prefix` is passed to the OmniAuth
182
+
strategy directly, so it stays correct regardless.
183
+
146
184
## The `on_login` hook
147
185
148
186
`on_login` is the **only** place authorization lives. The gem handles authentication (the user proved who they are via the IdP); deciding whether that user is allowed into the admin panel — and what they can see once they are in — is the host application's problem. The gem does not ship a role model.
@@ -247,7 +285,7 @@ AdminUser.last.oidc_raw_info
247
285
248
286
* A login button is added to the ActiveAdmin sessions page via a prepended view override — no templates to edit.
249
287
* Clicking it POSTs to `/admin/auth/oidc` with a Rails CSRF token. The gem loads `omniauth-rails_csrf_protection` so OmniAuth 2.x delegates its authenticity check to Rails' forgery protection and `button_to` just works.
250
-
* After a successful callback the user is signed in and redirected to `/admin`(not the host app's `/`, which may not exist).
288
+
* After a successful callback the user is signed in and redirected to ActiveAdmin's namespace root (not the host app's `/`, which may not exist). The path comes from ActiveAdmin's own route helper, so a renamed `config.default_namespace` or an engine-mounted ActiveAdmin lands correctly; `/admin` is only the fallback when that helper cannot be resolved.
251
289
***Disabled/locked users are rejected.** Devise's `active_for_authentication?` is checked after provisioning but before sign-in. If your model overrides this method (e.g. to check an `enabled` flag or Devise's `:lockable` module), the guard fires on OIDC sign-in too — the user sees an appropriate flash and is redirected to the login page.
252
290
* In development, `stub_dev_env_login!` repoints that same button at a local sign-in that never contacts the IdP — see "Stub login" below.
253
291
* Logout goes through Devise's stock session destroy. No RP-initiated single-logout ping to the IdP — override the destroy action in your host app if you need that.
0 commit comments