A demo application for the Spring User Framework. It runs the framework's user-management surface (registration with email verification, login, passkeys, MFA, OAuth2 and OIDC, password reset, profile editing, account deletion) behind a working Thymeleaf and Bootstrap UI, and adds a small event-management domain on top to show how application code builds on the framework's identity and authorization. The HTML, JavaScript, and configuration here are meant to be copied into your own application as a starting point.
Documentation for this demo is in docs/; the framework's own documentation lives in its repository.
| Demo version | Spring Boot | Spring User Framework | Java | Branch or tag |
|---|---|---|---|---|
| main | 4.1.x | 5.3.x | 21 | main |
| 1.0.0-springboot3 | 3.5.x | 3.5.x | 17 | v1.0.0-springboot3 |
main is on Spring Boot 4.1.0 and framework 5.3.0 (build.gradle). For the Spring Boot 3.5.6
and framework 3.5.1 combination on Java 17, git checkout v1.0.0-springboot3 after cloning.
| Capability | Where it lives | Details |
|---|---|---|
| Application-specific user profile sharing the framework user's key | user/profile/ |
EXTENDING.md |
| Cleaning up application data when an account is deleted | UserProfileDeletionListener |
EXTENDING.md |
| An application domain (events) using privilege-based access control | event/, roles in application.yml |
EXTENDING.md |
Allowing or denying registrations through the RegistrationGuard SPI |
DomainRegistrationGuard, registration-guard profile |
AUTHENTICATION.md |
| Passkey sign-in, enrollment, management, and passwordless registration | static/js/user/ (register.js, webauthn-*.js) |
AUTHENTICATION.md |
| Two-factor login, password plus passkey | application-mfa.yml, user/mfa/ |
AUTHENTICATION.md |
| OAuth2 login with Google and Facebook | application-local.yml-example |
AUTHENTICATION.md |
| OIDC login against a bundled Keycloak, as a runnable stack | docker-compose-keycloak.yml, keycloak/ |
AUTHENTICATION.md |
| Remember-me cookies | login.html, application.yml |
AUTHENTICATION.md |
| Admin page and API that lock and unlock accounts | AdminController, AdminAPIController |
AUTHENTICATION.md |
| Reference templates, JavaScript, and message bundle to copy | templates/, static/js/ |
EXTENDING.md |
| Replacing a framework service with your own | CustomUserEmailService |
EXTENDING.md |
| A test-only API, profile-gated and loopback-only, for E2E runs | TestDataController |
EXTENDING.md |
| Browser tests covering the flows above | playwright/ |
TESTING.md |
src/main/java/com/digitalsanctuary/spring/demo/
├── controller/ AdminController, AdminAPIController, PageController
├── event/ the example domain: entity, repository, service, page and API controllers
├── registration/ DomainRegistrationGuard, the RegistrationGuard SPI sample
├── service/ CustomUserEmailService, a framework service replaced with @Primary
├── test/ api/ the test-only API, config/ its security config; playwright-test only
├── user/profile/ the profile entity, repository, service, session holder, and listeners
├── util/ LocaleConfiguration
└── web/ DemoTemplateModelAdvice
src/main/resources/
├── static/js/ user/ (one module per page), admin/, utils/, shared.js
├── templates/ layout.html plus fragments/, user/, event/, admin/, mail/
├── messages/ messages.properties, the UI and validation message bundle
├── application.yml base configuration, overridden by application-<profile>.yml where needed
└── data-local.sql sample events, loaded under the local profile
src/test/java/com/digitalsanctuary/spring/
├── demo/ tests for this application's own code
└── user/ tests against the framework's user-management surface
playwright/ E2E specs, fixtures, and playwright.config.ts
keycloak/ realm export and TLS material for the Keycloak stack
Not every profile has its own file: local is a gitignored copy of application-local.yml-example,
test lives in src/test/resources/application-test.properties, and registration-guard has no
file at all. docs/CONFIGURATION.md lists what each one overrides.
Nothing to install but Docker:
git clone https://github.com/devondragon/SpringUserFrameworkDemoApp.git
cd SpringUserFrameworkDemoApp
docker compose up --buildThe app image is built from source inside Docker, so the first build takes several minutes. When it is up,
open http://localhost:8080 and register at http://localhost:8080/user/register.html. This stack sets
USER_REGISTRATION_SENDVERIFICATIONEMAIL=false, so accounts are enabled at registration and you can log in
immediately. Its mailserver container is a relay with no route to real inboxes, so nothing it accepts will
reach an actual mailbox. The stack runs under the dev profile and loads no sample events.
Stop it with Ctrl-C, then docker compose down -v to remove the containers and their data.
Needs JDK 21 (mise.toml pins it) and a running Docker daemon: bootRun starts the MariaDB
container defined in compose.dev.yaml and stops it with the app.
git clone https://github.com/devondragon/SpringUserFrameworkDemoApp.git
cd SpringUserFrameworkDemoApp
cp src/main/resources/application-local.yml-example src/main/resources/application-local.yml
./gradlew bootRun --args='--spring.profiles.active=local'application-local.yml is gitignored, so credentials you put in it stay out of git. Copying it also turns off
the verification email and loads the sample events in
data-local.sql. Then open http://localhost:8080, register at
http://localhost:8080/user/register.html, and browse the API at http://localhost:8080/swagger-ui.html.
To use a database you manage yourself instead of the container, set spring.docker.compose.enabled: false and
your own spring.datasource.* values; see CONFIGURATION.md.
docker compose -f docker-compose-keycloak.yml up -d --build --wait runs the app against a bundled Keycloak
and its imported demo realm. Ports, credentials, and the login walkthrough are in
keycloak/README.md and AUTHENTICATION.md.
| Profile | What it is for |
|---|---|
local |
Everyday local development; needs application-local.yml copied from the example |
dev |
Debug-heavy dev server; what the compose.yaml Docker stack runs |
prd |
Production settings: env-driven datasource and URLs, strict cookies, template caching |
test |
The JUnit suite on H2, applied automatically by ./gradlew test |
playwright-test |
Add-on: enables the loopback-only test API and turns off the verification and password-reset emails for E2E runs |
docker-keycloak |
OIDC against the bundled Keycloak; set for you inside docker-compose-keycloak.yml |
mfa |
Add-on: requires PASSWORD plus WEBAUTHN, for example local,mfa |
registration-guard |
Add-on: activates the domain-restricted registration guard, for example local,registration-guard |
Pick a base profile with --spring.profiles.active=, and list add-ons after it, comma-separated. With no
--args at all, bootRun still runs local (build.gradle:114-124). Full per-profile
override lists are in CONFIGURATION.md.
This demo:
- docs/CONFIGURATION.md: profiles, the properties this demo sets, environment variables, mail, and security settings.
- docs/DEVELOPMENT.md: prerequisites, running the app, the Compose files, Gradle tasks, logs, LiveReload, and IDE setup.
- docs/TESTING.md: the JUnit suite, disabled tests, the Playwright suite and its test API, and CI.
- docs/EXTENDING.md: each framework extension point, the demo code that uses it, and what to write in your own app.
- docs/AUTHENTICATION.md: every authentication path here, how to run it, and its configuration.
- keycloak/README.md: the Keycloak stack, its realm export, and its credentials.
- CHANGELOG.md: what changed, by date.
The framework:
- README.md: what the library does and how to add it to an application.
- CONFIG.md: the full property reference.
- MIGRATION.md: upgrading between framework versions.
- docs/PROFILE.md: the user-profile extension contract.
- docs/REGISTRATION-GUARD.md:
the
RegistrationGuardSPI.
./gradlew test # JUnit suite, test profile, H2
./gradlew playwrightTest # E2E; starts the app itselfRun both from the repository root. playwrightTest depends on playwrightBrowsers and
playwrightInstall, so it installs the npm dependencies and the browsers on its first run.
Details, including the MFA-only Playwright project and the test-only API, are in docs/TESTING.md.
Issues and pull requests are welcome at
SpringUserFrameworkDemoApp. Follow the
patterns already in the code, add tests for new behavior, and make sure ./gradlew test passes before
opening a pull request. Changes to the library itself belong in the framework repository, which has its own
CONTRIBUTING.md.
Apache License 2.0; see LICENSE.
The application is based on the principles in the Baeldung Spring Security Course.
Disclaimer: This is a demo project provided as-is with no guarantees of performance, security, or production readiness.
