A custom Keycloak UserProfile Validator that restricts email addresses to a configurable list of allowed domains. This validator applies to ALL email update contexts in Keycloak, including registration, UPDATE_EMAIL required action, profile updates, account console, and admin API operations.
This project has been inspired by the keycloak-mail-whitelisting project, which works great for the registration flow, but not for the UPDATE_EMAIL flow. This project is a UserProfile validator that applies to all email update contexts so it can be used in all contexts.
- ✅ Validates email domains across all Keycloak contexts
- ✅ Support for multiple allowed domains
- ✅ Glob pattern matching with
*(any characters) and?(single character) wildcards - ✅ Case-insensitive domain matching
- ✅ Internationalized error messages (English, Spanish, French, Basque)
- ✅ Easy configuration through Keycloak's User Profile UI
- ✅ Permissive mode when no domains are configured
- Keycloak 26.x or later (Jakarta EE)
- Java 17+
- Docker and Docker Compose (for building)
This project uses Docker for all build operations to ensure a consistent development environment.
# Build the Docker image
docker compose build
# Build the project and create the JAR
docker compose run --rm maven clean packageThe JAR will be available at target/keycloak-email-domain-validator-1.0.0-SNAPSHOT.jar
# Run all unit tests
docker compose run --rm maven test
# Run tests with verbose output
docker compose run --rm maven test -X# Clean the build
docker compose run --rm maven clean
# Verify the build
docker compose run --rm maven verify
# Install to local Maven repository
docker compose run --rm maven install- Copy the JAR to the Keycloak providers directory:
cp target/keycloak-email-domain-validator-1.0.0-SNAPSHOT.jar $KEYCLOAK_HOME/providers/- Rebuild Keycloak to load the new provider:
$KEYCLOAK_HOME/bin/kc.sh build- Start Keycloak:
$KEYCLOAK_HOME/bin/kc.sh startCreate a Dockerfile extending the official Keycloak image:
FROM quay.io/keycloak/keycloak:26.0.0
# Copy the validator JAR
COPY target/keycloak-email-domain-validator-1.0.0-SNAPSHOT.jar /opt/keycloak/providers/
# Build the optimized image
RUN /opt/keycloak/bin/kc.sh build
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]Build and run:
docker build -t keycloak-with-domain-validator .
docker run -p 8080:8080 keycloak-with-domain-validator start-dev- Log in to the Keycloak Admin Console
- Select your realm
- Go to Realm Settings → User Profile
- Click on the email attribute
- Expand the Validations section
- Click Add Validator
- Select email-domain-whitelist from the dropdown
- Configure the allowed domains:
mydomain.com
myotherdomain.com
*.contractor.com
- Click Save
You can configure the validator via realm JSON import:
{
"realm": "your-realm",
"userProfile": {
"attributes": [
{
"name": "email",
"validations": {
"email": {},
"email-domain-whitelist": {
"allowed-domains": "mydomain.com\nmyotherdomain.com\n*.contractor.com"
}
}
}
]
}
}Configure multiple domains separated by newlines or ##. Each domain supports:
- Exact match:
mydomain.com - Subdomain wildcard:
*.mydomain.com(matchessub.mydomain.combut notmydomain.com) - Single character wildcard:
my?domain.com(matchesmydomain.com,my1domain.com, etc.) - Combined patterns:
*.sub?.mydomain.com
Notes:
- Leading
@is optional (@mydomain.com=mydomain.com) - Domain matching is case-insensitive
- Leave empty to allow all domains (permissive mode)
Customize the error message key (optional):
- Default:
error-email-domain-not-allowed - The key must be defined in your theme's message properties
- The message can include
{0}placeholder for the list of allowed domains
company.com
company.org
company.net
Allowed:
user@company.comadmin@company.org
Blocked:
user@gmail.comuser@company.co.uk
*.company.com
company.com
Allowed:
user@company.comuser@dev.company.comuser@staging.company.com
Blocked:
user@company.co.uk
*.dev?.company.com
prod.company.com
Allowed:
user@dev1.company.comuser@deva.company.comuser@prod.company.com
Blocked:
user@development.company.com(more than one character after "dev")user@dev.company.com(no character after "dev")
This validator applies to ALL contexts where email is validated:
| Context | Description |
|---|---|
| Registration | New user registration form |
| UPDATE_EMAIL | Required action for email update |
| Update Profile | User profile update flow |
| Account Console | Account management console |
| Admin API | REST API user management |
- Verify the JAR is in
$KEYCLOAK_HOME/providers/ - Ensure you ran
kc.sh buildafter adding the JAR - Check Keycloak logs for errors:
grep -i "email-domain-whitelist" $KEYCLOAK_HOME/logs/keycloak.log- Verify the validator is added to the email attribute in User Profile
- Check the allowed domains configuration (no typos)
- Test with a simple exact match domain first
- Enable debug logging:
kc.sh start --log-level=org.keycloak.userprofile:debug- Ensure
theme-resources/messagesfiles are in the JAR - Verify the message key matches in the validator configuration
- Check if a custom theme overrides the base messages
# Rebuild the Docker image
docker compose build --no-cache
# Clear Maven cache volume
docker compose down -v
docker volume rm keycloak-email-domain-whitelist-validator_maven-cache
# Rebuild
docker compose build
docker compose run --rm maven clean packageIf you're currently using the FormAction-based validator:
- Deploy this UserProfile validator alongside the existing one
- Configure it for the email attribute in User Profile
- Test all flows (registration, email update, etc.)
- Remove the FormAction from the registration flow
- Optionally remove the old JAR
The glob pattern syntax is fully compatible with the existing implementation.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
This project uses GitHub Actions for CI/CD:
-
CI Workflow: Runs on every push and pull request
- Builds Docker image
- Runs all tests
- Creates JAR artifact
- Generates test reports
-
Release Workflow: Runs on version tags (e.g.,
v1.0.0)- Runs full test suite
- Builds release JAR
- Creates GitHub release with artifacts
All workflows use Docker to ensure consistency with local development.
keycloak-email-domain-validator/
├── Dockerfile # Maven build environment
├── docker-compose.yml # Docker Compose configuration
├── pom.xml # Maven project configuration
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── net/micedre/keycloak/validator/
│ │ │ ├── EmailDomainValidator.java
│ │ │ └── EmailDomainValidatorFactory.java
│ │ └── resources/
│ │ ├── META-INF/services/
│ │ │ └── org.keycloak.validate.ValidatorFactory
│ │ └── theme-resources/messages/
│ │ ├── messages_en.properties
│ │ ├── messages_es.properties
│ │ ├── messages_fr.properties
│ │ └── messages_eu.properties
│ └── test/
│ └── java/
│ └── net/micedre/keycloak/validator/
│ └── EmailDomainValidatorTest.java
└── README.md
# Run tests
docker compose run --rm maven test
# Run specific test class
docker compose run --rm maven test -Dtest=EmailDomainValidatorTest
# Run with coverage
docker compose run --rm maven verifyApache License 2.0

