OpenMFA is a Jenkins plugin that adds TOTP-based MFA for interactive logins. It introduces setup, verification, and management flows for user accounts inside Jenkins.
- OpenMFA Plugin
- TOTP MFA using authenticator apps (RFC 6238 compatible)
- QR-based enrollment flow for end users
- Global admin configuration for issuer and enforcement
- MFA user management page for administrators
- Session-based MFA verification after primary login
- Remember MFA across sessions for users who check "Keep me signed in" (signed cookie, configurable duration, disabled by setting it to 0)
- Basic brute-force protection on code verification attempts
- Supports Jenkins dark theme for all UI elements
- Configurable exemptions for service accounts and specific roles
- Jenkins
2.568.3or newer
- Install the plugin from the Jenkins Plugin Manager or build it from source.
- Go to
Manage Jenkins->Security->OpenMFA Configuration. - Configure:
Issuer NameRequire MFA for all usersRemember MFA for "Keep me signed in" (hours)(default: 24, 0 disables)Exempt Users(optional)Exempt Roles(optional)
- Save settings.
- Ask users to enroll via the OpenMFA setup page before broad enforcement.
Showcases
(OpenMFA Global Configuration: Manage Jenkins > Security > OpenMFA Configuration)
- User signs in with username/password.
- If MFA is required and the user is not enrolled, user is redirected to MFA setup.
- User scans QR code in authenticator app and verifies setup.
- On future logins, user enters a 6-digit TOTP code.
Showcases
(MFA setup page: User Property > Security > Setup MFA)
(MFA login challenge: after Jenkins login)
(MFA enabled: User Property > Security > Manage MFA )
(MFA enabled: User Property > Security)
- Go to
Manage Jenkins>MFA User Management. - Use this page to inspect enrollment state and perform admin-side MFA operations.
Showcases
(MFA user management: Manage Jenkins > MFA User Management)
By default, MFA verification lives only in the HTTP session, so every new session (new browser session, session timeout, controller restart) triggers a new MFA challenge -- even for users who checked Jenkins' "Keep me signed in" at login.
With this feature, users who logged in with "Keep me signed in" receive a long-lived openmfa-remember cookie after passing MFA and are not challenged again until it expires. Users who log in without "Keep me signed in" keep the per-session behavior.
How it works:
- The cookie is a stateless, HMAC-SHA256-signed token bound to the username, an absolute expiry, and a hash of the user's current TOTP secret. Nothing is stored server-side per device.
- Duration is configured by
Remember MFA for "Keep me signed in" (hours)(default: 24). Setting it to0disables the feature entirely. - Re-enrolling or disabling MFA changes the TOTP secret and therefore invalidates all previously issued cookies for that user.
- Logging out clears the cookie.
- The signing key is generated automatically on first use and persisted in the global configuration. Rotating the key (or setting a new one via JCasC) immediately invalidates all issued remember-MFA cookies -- this is the emergency "forget all remembered devices" switch.
No configuration is required on a standard installation with a persistent JENKINS_HOME. For ephemeral setups, see Ephemeral JENKINS_HOME.
This plugin exposes global configuration and can be managed through Jenkins Configuration as Code.
Recommended workflow:
- Configure OpenMFA once from the Jenkins UI.
- Export current JCasC from your Jenkins instance.
- Copy the OpenMFA section into your managed JCasC repository.
- Apply via your standard
CASC_JENKINS_CONFIGworkflow.
Example:
security:
openMFA:
issuer: 'Jenkins'
requireMFA: true
rememberMfaHours: 24
# Optional. Omit to let the plugin generate and persist a key in
# JENKINS_HOME. Set it explicitly (via any JCasC secret source, e.g.
# Vault, env var, or mounted secret) when JENKINS_HOME is ephemeral,
# so remember-MFA cookies survive restarts.
rememberMfaKey: ${OPENMFA_REMEMBER_KEY}
exemptUsers:
- svc-deploy
- break-glass
exemptRoles:
- ci-agents
- service-accounts
You can exempt specific users or roles from MFA requirements:
- Exempt Users: Individual usernames that bypass MFA (case-insensitive)
- Exempt Roles: Group/role names that bypass MFA for all members
Exemptions are useful for:
- Service accounts used by CI/CD pipelines
- Emergency break-glass accounts
- Automated agents that cannot complete MFA
Note: Exempted users bypass MFA entirely. Do not exempt regular user accounts.
On setups where JENKINS_HOME does not survive restarts (e.g. jenkins-operator with its default ephemeral home), two pieces of state need attention:
- Remember-MFA signing key -- set
rememberMfaKeyvia JCasC from an external secret source (Vault, Kubernetes Secret, env var). The key is then re-applied on every boot and issued cookies stay valid across pod restarts. Without it, each fresh instance generates a new key and all remembered devices are challenged again. - User TOTP enrollments -- stored by Jenkins in
$JENKINS_HOME/users/and encrypted with$JENKINS_HOME/secrets/master.key. These are runtime user data and cannot come from configuration: persistusers/andsecrets/together (PVC mounts or backup/restore), always as a pair -- one without the other is unusable.
- Treat JCasC files and Jenkins configuration files as privileged, since they control authentication behavior.
- API token authentication is not challenged with interactive MFA. Basic auth with a real password is challenged; use API tokens for scripted access.
- OpenMFA uses per-session verification and redirects back to the original destination after successful MFA.
- The remember-MFA cookie is
HttpOnly,Secureon HTTPS, HMAC-SHA256 signed with constant-time comparison, and carries no secret material -- only the username, expiry, and signature.
The maven-hpi-plugin offers important commands for Jenkins plugin development:
-
Build and package your plugin (.hpi):
mvn install
This compiles the plugin and creates the
.hpifile (e.g.,target/openmfa-plugin.hpi), suitable for installation in Jenkins. -
Run Jenkins in development mode with your plugin:
mvn hpi:run
This starts a local Jenkins controller instance with your plugin pre-installed, typically at http://localhost:8080/jenkins/.
If you use Visual Studio Code, the repo includes a sample .vscode/launch.json for debugging Jenkins plugin development:
-
Debug Jenkins Plugin: Attaches to a Jenkins process started with
mvn hpi:runin debug mode (-Dmaven.surefire.debug), listening on port5005. -
Debug Jenkins Plugin (mvnDebug): Attaches to Jenkins launched with
mvnDebug, typically listening on port8000.
To use:
- Open this repository in VS Code.
- In VS Code, go to the "Run and Debug" panel and select a launch configuration.
You can set breakpoints in your Java code immediately.
You can configure your development environment by creating a .env file in the project root. This file is used to provide environment variables, such as JAVA_HOME, which are required for Maven or Jenkins commands.
- Sample
.envfile:JAVA_HOME=/path/to/your/java # JENKINS_HOME=/path/to/jenkins_home (optional)
How to use:
- Copy
.env.exampleto.env:cp .env.example .env
- Edit
.env, settingJAVA_HOMEto your local Java installation and any other variables as needed. - The
.envfile is automatically loaded when running development commands via the provided.vscode/run.sh(used invscode/tasks.json) script, ensuring your environment variables (likeJAVA_HOME) are available.
Tip: .env is ignored by git, so your local secrets and paths are not committed. Use .env.example as a starting point for other developers.
This project uses Spotless with Eclipse formatter rules from fmt.xml. It also ships a prek config in .pre-commit-config.yaml.
-
Install git hooks with
prek:prek install
-
Run all configured checks/formatters with
prek:prek run --all-files
-
Check formatting:
mvn spotless:check
-
Apply formatting:
mvn spotless:apply
Spotless checks are also executed during Maven compile, so formatting issues fail the build.
MIT. See LICENSE.md.
