This repository contains two parts that work together:
- A Keycloak server extension (Java) that exposes
POST /realms/{realm}/avatar/{userId}and stores avatar images through pluggable backends. - A Keycloakify Single-Page account theme (
avatar-account-ui/) that overrides the Personal Info page with avatar upload + crop (react-easy-crop).
The custom Personal Info route adds an avatar panel that allows users to:
- Select an image file (
png,jpeg,webp, max 5MB). - Crop it to a square/round avatar.
- Upload it to the extension endpoint using the logged-in user's bearer token.
The server endpoint now enforces:
- authenticated bearer token,
token.subject == {userId}authorization,- MIME allow-list (
image/jpeg,image/png,image/webp), - max payload size (5MB).
When the extension initializes, it ensures the default profile client scope contains a picture OIDC mapper (oidc-usermodel-attribute-mapper) so the claim is available in tokens.
On successful avatar upload, the extension also updates the user attribute picture to point at:
/realms/{realm}/avatar/{userId}
Token claim values are evaluated when tokens are issued, so users need to refresh/re-login to see a newly uploaded avatar reflected in picture.
From the repository root:
mvn clean packageOutput:
target/avatar-extension-0.0.1-SNAPSHOT.jartarget/providers/*.jar(runtime dependencies needed by the extension, including AWS SDK when using S3)
From theme/:
npm install
npm run build-keycloak-themeOutput:
theme/dist_keycloak/keycloak-theme-for-kc-all-other-versions.jar(for Keycloak 26+)theme/dist_keycloak/keycloak-theme-for-kc-22-to-25.jar(for Keycloak 22-25)
From theme/:
npm run publish-maven-themeWhat this does:
- Builds the Keycloakify theme.
- Syncs generated Keycloakify Maven resources into
theme/maven/keycloak-theme-for-kc-all-other-versions/. - Publishes via
mvn -Prelease -DskipTests deployusing the checked-inpom.xml.
The sync step also keeps a verbatim copy of Keycloakify's generated POM in:
theme/maven/keycloak-theme-for-kc-all-other-versions/pom.keycloakify.xml
Copy the extension JAR, its runtime dependency JARs, and the theme JAR into Keycloak providers, then rebuild the Keycloak distribution:
# Optional but recommended when iterating: remove previously copied runtime deps
rm -f /opt/keycloak/providers/jackson-*.jar /opt/keycloak/providers/slf4j-api-*.jar
cp target/avatar-extension-0.0.1-SNAPSHOT.jar /opt/keycloak/providers/
cp target/providers/*.jar /opt/keycloak/providers/
cp theme/dist_keycloak/keycloak-theme-for-kc-all-other-versions.jar /opt/keycloak/providers/
/opt/keycloak/bin/kc.sh buildThen start Keycloak and set the realm Account Theme to avatar-account-ui.
If you select storage-type=minio in avatar storage settings:
- set
minio-host,minio-port, andbucket, - set
minio-access-keyandminio-secret-keywhen authentication is required, - set
minio-secure=falsefor local HTTP MinIO instances, - keep
minio-secure=truewhen connecting over HTTPS.
- Start Keycloak.
- Log into the admin console (
/). - Go to the avatar settings section and set the storage backend to the one you want to test.
- Set the account theme to
avatar-account-ui. - Log in to account console (
/realms/{realm}/account). - Open Personal Info.
- Upload a valid image, crop, click Upload avatar.
- Confirm success alert and storage backend write.
- Confirm oversized or invalid MIME uploads are rejected.
- Confirm users cannot upload avatars for another user id.