This repository contains the source code for a collection of Keycloak MFA plugins. The plugins are:
- SMS authenticator: Provides SMS as authentication step. SMS are sent via HTTP API, which can be configured. (production ready)
- Email authenticator: Provides Email OTP as authentication step. Uses the SMTP server configured in the realm. (production ready)
- Enforce MFA: Force users to configure a second factor after logging in. (beta)
- Native App MFA integration: connect a mobile app to Keycloak which receives a notification about a pending login process and allows the user to allow/block the login request. (work in progress)
- Trusted Device authenticator: remember a device after a successful 2FA login and skip the second factor on it for a configurable period.
The different plugins are documented in the submodules README. If you need support for deployment or adjustments, please contact support@verdigado.com.
The code of this project is Apache 2.0 licensed. Parts of the original code are MIT licensed.
- Clone this repository
- Install Apache Maven and a JDK 17
- Change into the cloned directory and run
Each module produces its provider jar as
mvn clean install
<module>/target/netzbegruenung.<module>-v<version>.jar, e.g.sms-authenticator/target/netzbegruenung.sms-authenticator-v26.7.2-1.jar.
Needs Docker with BuildKit (Docker 23 or newer). Builds in a maven:3.9-eclipse-temurin-17 container and writes
the provider jars to dist/:
docker build --platform linux/amd64 --output type=local,dest=dist .The Maven stage runs on the host's native architecture and the jars are platform independent; --platform only
sets the platform of the (empty) result image. Add --build-arg SKIP_TESTS=false to run the test suites, which
takes several minutes because they start an embedded Keycloak. The Maven repository lives in a BuildKit cache
mount, so repeated builds only download what changed.
This is also the way around a local JDK whose truststore lacks the ISRG roots behind repo.maven.apache.org
(PKIX path building failed): the container image ships a current truststore.
.github/workflows/snapshot.yml publishes rolling pre-releases with the provider jars: pr-<number> for every
pull request opened from a branch of this repository (replaced on each push, linked from a comment on the pull
request, deleted when it closes) and main-snapshot for every push to main. Tagged releases are separate, see
below.
Deployment is done by github actions: .github/workflows/release.yml
To trigger the release workflow be sure to have proper access rights and follow the steps below.
https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/configuring-tag-protection-rules#about-tag-protection-rules
Versions follow <keycloak.version>-<counter>, e.g. 26.7.0-0, rather than independent semantic versioning. The counter starts at 0 for the first release built against a given Keycloak version and increments for any additional release against that same Keycloak version (e.g. a hotfix); it resets to 0 whenever keycloak.version is bumped in pom.xml.
Run the block below to bump the version, commit, and tag (in IntelliJ you can run it directly from this file):
set -e
KEYCLOAK_VERSION=$(mvn help:evaluate -Dexpression=keycloak.version -q -DforceStdout \
| awk '{gsub(/\x1b\[[0-9;]*[mK]/,""); print}' \
| tr -d '\r')
LAST_COUNTER=$(git tag -l "v${KEYCLOAK_VERSION}-*" \
| sed "s/^v${KEYCLOAK_VERSION}-//" \
| sort -n | tail -1)
NEW_VERSION="${KEYCLOAK_VERSION}-$(( ${LAST_COUNTER:--1} + 1 ))"
mvn versions:set -DnewVersion="$NEW_VERSION"
mvn versions:commit
git add -u
git commit -m "chore: release $NEW_VERSION"
git tag -a "v$NEW_VERSION" -m "Release $NEW_VERSION"
echo "Tagged v$NEW_VERSION - review it, then push with: git push --follow-tags"Review the resulting commit and tag, then trigger the release by pushing both together:
git push --follow-tags(--follow-tags pushes the commit and the new annotated tag in one step; a plain git push would not push the tag on its own, and it's the tag push that triggers the workflow.)
After building completes the new release is available on github containing the jar files for each module. Release notes are auto-generated from merged PRs since the last tag (gh release create --generate-notes in the workflow), so any PR description explaining a notable change — like this versioning switch — is automatically surfaced to the community.