Skip to content

Feature/global redash login logout - #75

Merged
imenattatra merged 8 commits into
metr-mainfrom
feature/global-redash-login-logout
Jul 15, 2026
Merged

Feature/global redash login logout#75
imenattatra merged 8 commits into
metr-mainfrom
feature/global-redash-login-logout

Conversation

@imenattatra

@imenattatra imenattatra commented Jul 14, 2026

Copy link
Copy Markdown

Closes https://github.com/metr-systems/backlog/issues/4784
Closes https://github.com/metr-systems/backlog/issues/4761
Closes https://github.com/metr-systems/backlog/issues/4760

AI Disclaimer: Yes claude opus , to plan and assist

Summary

Global Redash already existed. This PR adds authentication and admin management to it:

  • CLI commands to create and update global admins: create_global_admin and update_global_admin_password ( the readme for how to run these commands ).
  • Login and Logout that clears the session and returns to the login page.
  • The now-authenticated app renders inside Redash's normal navbar + layout.
  • Global admins are a separate set of users from main Redash's org users.

Code Strategy

  • Maintain Global redash separated from main redash while accessing same db.
  • Separate identity: new GlobalAdminUser model that is not org scoped.
  • Separate sessions: dedicated GLOBAL_SECRET_KEY (app won't start without it) and also a separate cookie name.
  • Reuse the UI base elements.
  • Frontend build: added the shared main.less/ant.less to the existing global_app webpack entry so the navbar renders styled, and set baseHref/staticPath on its HTML template for routing and favicons.

Security

Baseline protections are in place: separate sessions, a dedicated secret key, CSRF on the login POST, and login rate limiting (a dedicated Limiter pointed at the same Redis as main Redash, defaulting to 10/hour, configurable via GLOBAL_THROTTLE_LOGIN_PATTERN).

A follow-up PR will do more security hardening: bringing Redash Global up to main Redash's level and probably beyond. check issue

QA

How did you test it? Keep your future self in mind to help debug things later.

Separate admin user for global redash.
env.py imports redash_global.models so migrations pick up the table,
keeping the main app decoupled from redash_global.
Registered via app.cli.add_command in create_global_app, so
`FLASK_APP=redash_global.app:create_global_app flask create_global_admin`
works.
Gate the Redash Global admin SPA behind a login page so only
authenticated global admins can reach it.

- Add a /login page and POST handler that verifies GlobalAdminUser
  credentials and starts a flask_login session; wrap the SPA index
  in @login_required so unauthenticated visitors are redirected there.
- Configure a dedicated GLOBAL_SECRET_KEY for signing the session
  cookie, and fail fast at startup if it's unset — this keeps global
  sessions cryptographically independent from the main Redash app so a
  leaked key in one app can't forge sessions in the other.
- Use a separate session cookie name (global_admin_session) so the two
  apps' cookies don't collide when served from the same host.
- Enable CSRF protection on the global app and include a csrf_token in
  the login form to protect the credential POST.
- Register a Jinja ChoiceLoader that prefers Redash Global's own
  templates but falls back to Redash's, so login.html can extend the
  shared signed_out.html layout and reuse existing styling.
- Add tests covering the redirect-when-unauthenticated, valid-login,
  and invalid-login flows. The shared test process forces us to mute
  the user_logged_in signal, since the main app's handler expects an
  org_id that GlobalAdminUser doesn't have.
Let an authenticated global admin end their session and return to
the login page.

- Add a POST-only /logout handler wrapped in @login_required that
  calls logout_user() to clear the flask_login session and redirects
  back to /login.
- Keep it POST-only rather than GET so CSRF protection applies to it:
  a GET logout could be triggered by a prefetched link or embedded
  <img>, letting a third-party page silently sign the admin out.
- Add a test that logs in, POSTs /logout, and confirms / gates back
  to /login — proving the session was actually cleared, not just that
  the endpoint returns a redirect.
Wires the bare "Work in progress" global app into Redash's existing
application chrome and fixes logout end to end.

- Render ApplicationLayout + Router with a placeholder home route, reusing
  the main app's chrome instead of reinventing it.
- Register GlobalDesktopNavbar as "ApplicationDesktopNavbar"; the default
  navbar needs an org-scoped currentUser that Redash Global doesn't have.
- Add main.less + ant.less to the global_app webpack entry, without them the
  navbar's Ant Design Menu had no styles and the layout was unpositioned.
- Pass baseHref + staticPath to global.html so the Router can resolve routes
  and favicons load.
- Change /logout from POST to GET to match main Redash and the navbar's
  <a href>, which was returning Method Not Allowed.
Accessing a protected page while logged out redirected to the login
page but flashed "Please log in to access this page." as an error. For
an admin app the redirect alone is enough signal, and the message read
as an error the user had done something wrong rather than a routine
auth gate.
@imenattatra imenattatra self-assigned this Jul 14, 2026
@imenattatra
imenattatra requested review from a team and helenalebreton July 14, 2026 16:47
@imenattatra
imenattatra merged commit 3b4e7c5 into metr-main Jul 15, 2026
1 check passed
Comment thread redash_global/app.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants