Project

General

Profile

Actions

Feature #43352

open

Provide an option to authenticate in Redmine through an OAuth provider.

Added by Marius BĂLTEANU 12 months ago. Updated 8 days ago.

Status:
New
Priority:
Normal
Category:
Accounts / authentication
Target version:
Resolution:

Description

This feature will allow users to securely log in using their accounts from popular services like Google, Microsoft, Okta, or Keylock, providing an alternative to the traditional username/password login or LDAP login.

From what I checked, there is very well maintained plugin that brings this capability, but I think that it should a core feature.


Files


Related issues

Related to Redmine - Feature #37363: Add native support for OIDCNewActions
Actions #1

Updated by Marius BĂLTEANU 12 months ago

Actions #2

Updated by Marius BĂLTEANU 12 months ago

I've added this to 7.0.0 for now to discuss it, but I strongly believe we should implement this in some way.

Actions #3

Updated by Anonymous 12 months ago

  • File clipboard-202510151400-sn8gk.png added
Actions #4

Updated by Go MAEDA 12 months ago

  • File deleted (clipboard-202510151400-sn8gk.png)
Actions #5

Updated by Jan Catrysse 11 months ago

https://github.com/jcatrysse/bless-this-redmine-sso/tree/feature_version_2.0.0

This is what I have been using (I added a version 2.0.0 feature branch).

Actions #6

Updated by Quentin Aymard 11 months ago

Yes please. The lack of support for modern auth / Single Sign On (SSO) is really a problem for Redmine to move forward.

The OAuth side of the force is a bit disorderly, with several plugins more or less trying to do the same thing, most of the time confusing OAuth and its subset OpenID Connect. Kontron/redmine_oauth is the only one I was able to use properly.

The SAML side of the force was, until recently, somewhat clearer : a bunch of abandoned plugins, and the last one standing being the one from AlphaNodes : https://github.com/AlphaNodes/redmine_saml. But this last one went in public archive mode on Github this fall, so I think this is not an option anymore.

Actions #7

Updated by Jan Opravil 4 months ago

Hello Marius Ionescu BĂLTEANU and team,

I'd like to propose a design for native OpenID Connect support and seek your direction before opening any patches. I've spent time analysing the four community OIDC plugins (`enricohuang/redmine_oidc`, `devopskube/redmine_openid_connect`, `nanego/redmine_omniauth_oidc`, `kontron/redmine_oauth`), read this issue and #37363 in detail, and produced a full design document covering data model, authentication flow, session lifecycle, logout (RP-initiated + Back-Channel), claim mapping, admin UI, security checklist, and testing strategy.

Full proposal: in attachement

The proposed shape is a native OIDC 1.0 implementation in Redmine core (no plugin layer), targeting 7.0.0. Architecture highlights:

Dedicated `OidcProvider` ActiveRecord model (not `AuthSource` STI) supporting multiple active providers simultaneously, with presets for Keycloak, Microsoft Entra ID, Okta, Auth0, Google Cloud Identity / Workspace, and a fully-configurable Custom (generic OIDC) profile.
Stable user identity via an `oidc_user_links(issuer, sub)` join table; first-time email matching gated by `email_verified=true`.
Mandatory PKCE S256 and JWKS-based ID token signature verification — the critical security gap in three of the four existing community plugins.
Three universal claim-mapping strategies (`group` / `project_role` / `none`) driven by a configurable dot-notation claim path that works across all major IdPs without special-casing. Admin flag is sync-controlled only when the admin explicitly opts in via an `admin_role_values` whitelist. Manually-assigned groups and memberships are never overwritten.
Full SSO logout propagation: RP-initiated logout via `end_session_endpoint`, Back-Channel Logout endpoint, opt-in periodic introspection for sub-token-TTL revocation latency.
Reactive token lifecycle: lazy refresh-on-expiry with a configurable buffer (default 300s), serialised under a pessimistic row lock to handle refresh-token rotation safely. No background scheduler in MVP.
2FA delegated to the IdP when the `amr` or `acr` claim signals MFA; auto-provisioned users without TOTP are routed through Redmine's existing setup wizard when global policy requires 2FA but the IdP did not assert MFA.
One new gem dependency: `jwt` (~> 2.x) for signature verification. Alternatives are either heavier (`omniauth_openid_connect` pulls OmniAuth middleware) or unsafe (manual base64 decoding, which is what three of the four existing plugins currently do).
EN + CS locales in MVP; comprehensive test pyramid (unit / functional / integration with WebMock-stubbed IdP); security checklist as a patch-submission gate.

Before I commit time to implementation, I'd appreciate your direction on the following:

1. Scope: OIDC-only vs OIDC + plain OAuth2 in MVP? The title of this issue says "OAuth Authentication", and Felix Singer's comment in #37363 (note 2) asks for plain OAuth2 providers (GitHub, GitLab, Google OAuth). I propose OIDC-only for MVP because plain OAuth2 lacks a signed identity assertion (no ID token, no JWKS), but this is genuinely your call — extending to plain OAuth2 doubles the surface area and we akens the security baseline.
2. AuthSource vs. dedicated model? OIDC's browser-redirect flow doesn't fit the `AuthSource#authenticate(login, password)` contract, and multi-provider with per-provider quirks complicates STI. I propose a dedicated `OidcProvider` model. Confirm or redirect.
3. Patch series shape? Acceptable as one large patch, or do you want it split into a series (schema + models → discovery/JWKS primitives → login flow → role mapping → admin UI → BCL → tests)?
4. Gem dependency: is `jwt` (~> 2.x) acceptable? It's the minimum to do JWKS signature verification properly.
5. Server-side session store as a BCL prerequisite? Redmine defaults to cookie-only sessions; Back-Channel Logout needs server-side sessions to be able to destroy sessions on demand. Document this as a prerequisite admins must enable for BCL to be effective, or different approach?
6. Prior art — note 5 above (Jan Catrysse) links to a v2.0.0 feature branch of an alternative SSO implementation. I didn't have the URL when drafting the proposal — could you point me at it if it should inform the design?

The full proposal documents 21 design decisions with their rationale, and lists exactly what's deliberately out of scope for MVP (background refresh, plugin migration importers, SAML, plain OAuth2, SCIM, Front-Channel Logout, real-IdP integration tests in CI, step-up auth, mobile/native client support). Happy to break any section into a separate discussion if useful, and to iterate the design before any code lands.

Thanks for your time.

Jan Opravil

Actions #8

Updated by Marius BĂLTEANU 3 months ago

  • Target version changed from 7.0.0 to 7.1.0
Actions #9

Updated by Jan Opravil 8 days ago

Native OIDC implementation — patch attached

Following up on my design proposal above (comment #7): the implementation is complete and attached as redmine-oidc-native-support.patch (single consolidated diff, applies cleanly with patch -p1 or git apply against current trunk, r25125).

Scope (120 files, ~22.9k lines added):

- OidcProvider — dedicated model (not AuthSource STI), multiple providers can be enabled simultaneously. Built-in presets for Keycloak, Microsoft Entra ID, Okta, Auth0 and Google Cloud Identity/Workspace, plus a generic "custom" option for any spec-compliant IdP.
- OidcSession / OidcUserLink — per-device session tracking (refresh/access/ID tokens encrypted at rest via the existing Redmine::Ciphering), separate from the identity link so one identity can hold several concurrent device sessions.
- Auth code flow with mandatory PKCE (S256) and JWKS-based ID token signature verification (lib/redmine/oidc/id_token_validator.rb, jwks.rb, discovery.rb) — no fallback to unsigned or alg=none tokens.
- Login-CSRF defence via a signed, user-agent-bound handshake cookie (handshake_binding.rb) plus server-side handshake store, per RFC 9700 §4.7.
- RFC 9207 mix-up mitigation, iss checking, nonce, and standard claim validation (issuer/audience/exp/iat).
- Back-Channel and Front-Channel Logout support (RFC/OIDC spec), both revoking the stored refresh token at the provider, not just dropping the local session.
- Session lifecycle: periodic revalidation (prompt=none), optional token introspection (RFC 7662), token revocation (RFC 7009) on logout/unlink/deactivation/account deletion.
- Three role-mapping strategies: none, group (claim → Redmine group) and project_role (claim → project membership + role), plus a separate admin_role_values mapping — all reconciled against actual current access on every login, not just an internal bookkeeping table, and fully reversible when a provider or link is removed.
- Delegated 2FA: optional "trust the IdP's MFA claim (amr/acr) within a configurable max_age" policy, falling back to Redmine's own 2FA.
- CLI tooling: rake redmine:oidc:{providers,create,delete,revoke_grants,prune_sessions,refresh_metadata}, plus one-shot importers from two existing community plugins' data shapes (enricohuang/redmine_oidc, jcatrysse/bless-this-redmine-sso).
- Admin UI (OidcProvidersController + views) and end-user UI (login buttons, linked-accounts panel, unlink flow).
- Full English + Czech i18n.

Dependency: one new gem, jwt (~> 3.2), for signature verification.

Tests: 989 test runs (functional/unit/integration), all green, covering the full auth/logout/refresh/revocation lifecycle, role-mapping reconciliation, concurrency (row-locking against races between refresh and logout/BCL), and a dedicated security-regression suite (audit_r17_findings_test.rb) pinning specific findings from an independent security review of the branch (claim-extraction privilege escalation, weak-key JWKS acceptance, session-fixation-adjacent issues, etc.).

Patch attached below.

Actions

Also available in: Atom PDF