Complete Guide: Migrating Legacy Wizbrand Users to Keycloak & Customizing Email Templates

Posted by

Limited Time Offer!

For Less Than the Cost of a Starbucks Coffee, Access All DevOpsSchool Videos on YouTube Unlimitedly.
Master DevOps, SRE, DevSecOps Skills!

Enroll Now

When you integrated Keycloak SSO into Wizbrand, new users began being created in both Wizbrand and Keycloak.
However, existing users (created before Keycloak integration) only exist in Wizbrandโ€™s database.
To unify authentication, we need to migrate old users into Keycloak while keeping their Wizbrand data intact.

This tutorial explains:

  1. How to migrate existing users into Keycloak with automation
  2. How to handle email verification / password reset flows
  3. How to add a โ€œno-emailโ€ mode (so users reset passwords during next login)
  4. How to fix redirect & email-sending errors
  5. How to fully customize Keycloakโ€™s email UI to a modern, branded template

Architecture Summary

ComponentDescription
Wizbrand BackendLaravel-based service managing your app users
KeycloakAuth provider for SSO, OAuth2, OpenID Connect
CommunicationLaravel Artisan command uses Keycloak Admin API
FlowUsers migrated โ†’ Actions set โ†’ Email sent โ†’ Login triggers password reset

Files Involved

FilePurpose
app/Services/RoleMapper.phpMaps Wizbrand user roles/groups to Keycloak roles
app/Console/Commands/MigrateUsersToKeycloak.phpMain migration logic
app/Console/Kernel.phpRegisters the command for Artisan
app/Services/KeycloakAdminService.phpHandles Keycloak API calls (already implemented)

Updated Migration Command

Hereโ€™s the final version of app/Console/Commands/MigrateUsersToKeycloak.php
It includes:

  • --no-email โ†’ skip sending emails
  • --lifespan โ†’ custom expiry time
  • Graceful error handling
  • No method renaming or removal

(You already have this updated version; keep it as your base.)

Key usage examples:

# Normal migration + verification email
php artisan kc:migrate --limit=50 --email-verify

# Send emails with a 30-day valid link
php artisan kc:migrate --limit=50 --email-verify --lifespan=2592000

# Skip emails; users reset password on next login
php artisan kc:migrate --limit=50 --email-verify --no-email

Understanding Each Option

OptionDescription
--limitNumber of users to process in one run
--offsetStart offset for pagination
--dry-runSimulate migration without writing to Keycloak
--email-verifyAdds VERIFY_EMAIL to required actions
--lifespanLifespan of email action link (default: 1 day)
--redirectOptional callback URL after password reset
--onlyComma-separated DB IDs for targeted migration
--whereAdd SQL conditions like email like '%@wizbrand.com'
--include-disabledInclude inactive/disabled users
--no-emailSkip sending emails and force reset on next login

Common Errors & Fixes

Invalid Redirect URI

Error:

Invalid redirect uri

Fix:

  1. In Keycloak โ†’ Clients โ†’ wizbrand-web
  2. Add your redirect: http://wz-account-admin-ms/auth/callback
  3. Save and re-run your command.

Invalid Sender Address โ€˜nullโ€™

Error:

Failed to send execute actions email: Invalid sender address 'null'

Fix:
Configure SMTP in Realm Settings โ†’ Email

FieldExample
Fromno-reply@wizbrand.com
Hostsmtp.gmail.com
Port587
EncryptionStartTLS
Usernameyour-email
PasswordApp Password
Test Connectionโœ… must succeed

Tip โ€” Infinite Token is NOT Possible

Keycloak action links (password reset, verification) are JWT-based and must expire.
However, you can:

  • Extend their lifespan (e.g., 30โ€“90 days) using: --lifespan=2592000
  • Set a global default:
    • Realm Settings โ†’ Tokens โ†’ Default Admin-Initiated Action Lifespan โ†’ 30d

Forcing Reset at Next Login (No Email)

When --no-email is used:

  • No email link is sent.
  • Keycloak sets UPDATE_PASSWORD and VERIFY_EMAIL as required actions.
  • User will be forced to reset password during their next login.

To verify:

  1. Go to Users โ†’ [user] โ†’ Required Actions
  2. Youโ€™ll see: UPDATE_PASSWORD VERIFY_EMAIL
  3. After user completes reset, list becomes empty.

Customizing the Email Design (Wizbrand Branded)

The default email looks basic.
You can fully rebrand it to match Wizbrandโ€™s identity.

Folder Structure

/opt/keycloak/themes/wizbrand/
โ”œโ”€ theme.properties
โ”œโ”€ messages/messages_en.properties
โ””โ”€ email/
   โ”œโ”€ html/execute-actions.ftl
   โ””โ”€ text/execute-actions.ftl

theme.properties

parent=keycloak
types=email
locales=en

HTML Template (Beautiful Modern UI)

email/html/execute-actions.ftl

(abridged summary โ€” full version above in chat)

Features:

  • Wizbrand logo & dark header
  • Clean card layout
  • โ€œContinue & secure my accountโ€ button
  • Action list (e.g., Update Password, Verify Email)
  • Expiry notice & fallback link
  • Responsive design (works in Gmail, Outlook, Apple Mail)

Plain Text Fallback

email/text/execute-actions.ftl โ€” simple message body for clients that block HTML.


Select Theme in Keycloak

  1. Go to Realm Settings โ†’ Themes
  2. Set Email Theme = wizbrand
  3. Save
  4. Restart Keycloak if needed --spi-theme-cache-themes=false --spi-theme-cache-templates=false

Preview of the Styled Email (Conceptually)

(You can imagine this layout)

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘ Wizbrand Logo                        โ•‘
โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
โ•‘  Action required to secure your account
โ•‘  Click below to reset your credentials
โ•‘  [ Continue & Secure My Account ]     โ•‘
โ•‘  This link expires in 30 days.        โ•‘
โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
โ•‘  Need help? Contact support@wizbrand.com
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Folder Path & Permissions (Linux/Docker)

If Keycloak runs in Docker:

docker cp ./wizbrand keycloak:/opt/keycloak/themes/wizbrand
docker exec -it keycloak chmod -R 755 /opt/keycloak/themes/wizbrand
docker restart keycloak

If self-hosted on Linux:

sudo mkdir -p /opt/keycloak/themes/wizbrand
sudo chown -R keycloak:keycloak /opt/keycloak/themes/wizbrand
sudo systemctl restart keycloak

Optional Enhancements

FeatureDescription
Resend pending actionsUse a cron job to resend execute-actions-email to users who havenโ€™t completed verification
Auto-detect SMTP errorsCatch Invalid sender in logs and automatically switch to --no-email
Multi-client redirectAdd --client-id override to target different Keycloak clients
Error metricsLog success/error counts for daily monitoring

Verification Checklist

CheckResult
php artisan kc:migrate runs without ERRโœ…
Keycloak email config testedโœ…
Wizbrand redirect whitelistedโœ…
Email theme = wizbrandโœ…
Email styling verifiedโœ…
Required actions visible in KCโœ…
User resets password successfullyโœ…

Key Benefits Achieved

Seamless migration of legacy users
Stronger password reset and verification enforcement
Optional email-less password reset
100% branded, professional email communication
Automated, repeatable process for future imports


Example: Full Command Lifecycle

Initial Import

php artisan kc:migrate --limit=100 --email-verify --lifespan=2592000

If SMTP fails

php artisan kc:migrate --limit=100 --email-verify --no-email

Weekly resend pending resets

php artisan kc:resend-actions --verify --lifespan=604800

Final Outcome

After completing this setup:

  • All Wizbrand users (old + new) are in Keycloak.
  • New users use standard registration.
  • Old users either:
    • Receive a Wizbrand-branded email to reset credentials, or
    • Are forced to reset at next login (no email mode).
  • Emails now look professional and consistent with Wizbrandโ€™s identity.

Leave a Reply

Your email address will not be published. Required fields are marked *

0
Would love your thoughts, please comment.x
()
x