{"id":443,"date":"2025-03-07T13:00:00","date_gmt":"2025-03-07T13:00:00","guid":{"rendered":"https:\/\/discovery.cevolution.co.uk\/ciam\/?p=443"},"modified":"2026-01-17T14:40:37","modified_gmt":"2026-01-17T14:40:37","slug":"open-source-ciam-using-keycloak","status":"publish","type":"post","link":"https:\/\/discovery.cevolution.co.uk\/ciam\/2025\/03\/07\/open-source-ciam-using-keycloak\/","title":{"rendered":"Think Open-Source for Your CIAM Integration, with Keycloak DIY"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Reading Time: <\/span> <span class=\"rt-time\"> 14<\/span> <span class=\"rt-label rt-postfix\">minutes<\/span><\/span>\n<p>Depending on your perspective, deployment is where a vendor-hosted <span class=\"popup-trigger popmake-2946\" data-popup-id=\"2946\" data-do-default=\"0\">SaaS<\/span> CIAM solution can pay dividends, as the third-party vendor will manage the hosting for you. However, as discussed in a previous article I wrote, building a SaaS application \u2014 particularly a <span class=\"popup-trigger popmake-418\" data-popup-id=\"418\" data-do-default=\"0\">B2B<\/span> one \u2014 will likely mean you already have the necessary infrastructure (which you already have to manage), and so can leverage this to deploy an open-source CIAM solution.<\/p>\n\n\n\n<div class=\"wp-block-group is-content-justification-center is-nowrap is-layout-flex wp-container-core-group-is-layout-23441af8 wp-block-group-is-layout-flex\">\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-discover-ciam wp-block-embed-discover-ciam\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"4JF5yosfOT\"><a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/2025\/02\/22\/diy-or-buy\/\">Build, Buy or DIY your CIAM Solution?<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&#8220;Build, Buy or DIY your CIAM Solution?&#8221; &#8212; Discover CIAM\" src=\"https:\/\/discovery.cevolution.co.uk\/ciam\/2025\/02\/22\/diy-or-buy\/embed\/#?secret=AAi4YE35fx#?secret=4JF5yosfOT\" data-secret=\"4JF5yosfOT\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n<\/div>\n\n\n\n<p>Keycloak is one such open-source solution that, out of the box, provides the things commonly required of a <a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/2025\/04\/09\/architecting-a-modern-ciam-solution\/\" target=\"_blank\" rel=\"noreferrer noopener\">CIAM integration<\/a>. Arguably, it&#8217;s one of the most well-known and configurable of the open-source solutions, and being open-source means it can easily be tailored to requirements&#8230;leveraging one&#8217;s own software development skills where needed:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Single Sign-On (<a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/authenticate\/login\/sso\/\" target=\"_blank\" rel=\"noreferrer noopener\">SSO<\/a>)<\/li>\n\n\n\n<li>Multi-factor authentication (<a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/authenticate\/mfa\/\" target=\"_blank\" rel=\"noreferrer noopener\">MFA<\/a>)<\/li>\n\n\n\n<li><a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/authorize\/access-control\/\u2197\" target=\"_blank\" rel=\"noreferrer noopener\">Access control<\/a> (specifically <span class=\"popup-trigger popmake-1623 \" data-popup-id=\"1623\" data-do-default=\"0\">RBAC<\/span>)<\/li>\n\n\n\n<li><span class=\"popup-trigger popmake-523 \" data-popup-id=\"523\" data-do-default=\"0\">Social<\/span> login support (e.g., Google, Facebook)<\/li>\n\n\n\n<li>Account Linking (read more about that <a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/2025\/06\/04\/why-account-linking-should-be-pivotal-in-your-ciam-sso-integration\/\" target=\"_blank\" rel=\"noopener\" title=\"Why Account Linking Should Be Pivotal in your CIAM SSO\">here<\/a>)<\/li>\n\n\n\n<li><a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/2025\/03\/25\/the-benefits-of-self-service-user-profile-management\/\" target=\"_blank\" rel=\"noopener\" title=\"The Benefits of Self-Service User Profile Management\">Self-Service Account Management<\/a>,<\/li>\n\n\n\n<li><a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/authorize\/consent\/\" target=\"_blank\" rel=\"noreferrer noopener\">Delegated Authorization<\/a><\/li>\n\n\n\n<li>Enterprise <a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/authenticate\/login\/federation\/\" data-type=\"page\" data-id=\"1136\">Federation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/manage\/brand\/\" data-type=\"page\" data-id=\"12\" target=\"_blank\" rel=\"noreferrer noopener\">Brand Management<\/a><\/li>\n\n\n\n<li>etc.<\/li>\n<\/ul>\n\n\n\n<p>Whilst Keycloak isn&#8217;t particularly difficult to install, it&#8217;s fair to say that some work is required to get it into a production-ready state (read more in the official <em><a href=\"https:\/\/www.keycloak.org\/server\/configuration-production\" target=\"_blank\" rel=\"noreferrer noopener\">Configuring Keycloak for Production<\/a><\/em> guide). It&#8217;s not a huge amount, especially if you already have similar considerations for deploying your consumer-oriented B2C\/B2B SaaS application, but it&#8217;s work nonetheless. <\/p>\n\n\n\n<p>My name\u2019s <span class=\"popup-trigger popmake-378\" data-popup-id=\"378\" data-do-default=\"0\">Peter Fernandez<\/span>, and in this article, I\u2019m going to talk about my own DIY experience using open-source <a href=\"https:\/\/www.keycloak.org\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Keycloak<\/strong><\/a> as a tool-oriented CIAM option that comes at a fraction of the cost of a vendor-hosted <span class=\"popup-trigger popmake-2946\" data-popup-id=\"2946\" data-do-default=\"0\">SaaS<\/span> CIAM solution.<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-ddc47d161e6cf6f97edfffb89fd2878a is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Throughout the rest of this article, I&#8217;ll be dipping in and out of the various guides at <a href=\"https:\/\/www.keycloak.org\/guides\">https:\/\/www.keycloak.org\/guides<\/a>, so whilst I don&#8217;t necessarily advocate reading them all, I&#8217;d recommend at least familiarising yourself with that resource before continuing \ud83d\ude0e<\/em><\/p>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"containerized-deployment\">Containerized Deployment<\/h2>\n\n\n<p>For evaluation\/prototyping, arguably the easiest way to deploy Keycloak, if you don&#8217;t already have it installed, is via the <em><a href=\"https:\/\/www.keycloak.org\/downloads\" target=\"_blank\" rel=\"noopener\" title=\"\">Container Image<\/a><\/em>. Of course, you&#8217;ll need a container management platform installed and configured, too, and my preferred choice is typically to use <a href=\"https:\/\/www.docker.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Docker<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-ab775f012083d4d7a860cf481d2e370c is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Docker is a Platform-as-a-Service&nbsp;(PaaS) product that uses&nbsp;OS-level virtualisation&nbsp;to deploy software using containers. I often use the Docker Desktop free tier, which can be downloaded <a href=\"https:\/\/www.docker.com\/products\/docker-desktop\/\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/em><\/p>\n<\/div>\n\n\n\n<p>The article <a href=\"https:\/\/www.keycloak.org\/getting-started\/getting-started-docker\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a> provides more details as part of the latest official Keycloak documentation, but for convenience, once the container is downloaded to Docker, the following command should get it up and running in a local development environment:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=password quay.io\/keycloak\/keycloak:26.1.0 start-dev<\/code><\/pre>\n\n\n\n<p>A Docker container can be used for production deployment, too; however, you can also download a non-containerised package should you choose. Keycloak is a Java-based service, with the latest version being powered using Quarkus, so either option should perform well enough.<\/p>\n\n\n\n<p>As a general &#8220;rule of thumb&#8221;, I like to take the simplest approach to deployment in the first instance, so using a containerised setup is a good option for getting something up and running before tackling anything more complicated \ud83d\ude01<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-d1da02f74f54f3b9b301273c58e2dc8f is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Primarily an Enterprise-Grade IAM Managed Solution provider for Keycloak, the folks over at <a href=\"https:\/\/phasetwo.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">Phase 2<\/a> also offer a <strong>free<\/strong> Starter plan if you&#8217;d prefer skipping the deployment of your own instance to start with. Alternatively, the folks over at <a href=\"https:\/\/pro.keycloakkit.com\/\" title=\"\">Keycloakit<\/a> offer a ready-made install for a low <strong>one-time cost<\/strong> with no subscription fee.<\/em><\/p>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"bare-metal-deployment\">Bare Metal Deployment<\/h2>\n\n\n<p>If you decide to take the non-containerised route \u2014 the route typically referred to as the <em>bare metal<\/em> or <em>OpenJDK<\/em> option \u2014 then the Keycloak documentation <a href=\"https:\/\/www.keycloak.org\/getting-started\/getting-started-zip\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a> provides a lot of details to help you get going. Again, if you don&#8217;t already have Keycloak installed, the latest package can be downloaded <a href=\"https:\/\/www.keycloak.org\/downloads\" target=\"_blank\" rel=\"noopener\" title=\"\">here<\/a>.<\/p>\n\n\n\n<p>Depending on your point of view, the bare metal option arguably gives you the most flexibility, but it all depends on your preference and also the existing environment in which you plan to deploy. <\/p>\n\n\n\n<p>I&#8217;m opting for the bare metal approach because I (a) want to familiarise myself with the various aspects of setting up a Keycloak environment, and (b) will ultimately want to experiment and customise, using things like <a href=\"https:\/\/httpd.apache.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">Apache<\/a> for proxying, etc. (see more <a href=\"#proxy\">below<\/a>).<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-08d1f9847da09781804b8722ccba14c9 is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Keycloak runs on either Windows, Mac or Linux, and I&#8217;m deploying to AWS Lightsail, using what is effectively a LAMP stack templated by <a href=\"https:\/\/docs.bitnami.com\/aws\/get-started-lightsail\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Bitnami<\/a>. At a reasonable $12 per month hosting charge (for 2GB Memory, 2 vCPUs, 60GB of SSD and where the first 90 days of usage are typically free for new customers), this represents amazing value \u2014 at least for getting started! <\/em> <em> <\/em><\/p>\n<\/div>\n\n\n\n<p>Once installed, by default, Keycloak can be simply executed from a command shell, typically taking a number of different configuration options as parameters. Primarily, this is the easiest way to test out a bare metal installation, and all the snippets I&#8217;ve included in this article are based on taking that approach. <\/p>\n\n\n\n<p>You can also use <code>start-dev<\/code> rather than <code>start<\/code>, and doing so enables some developer options by default&#8230;like disabling optimisations. You often find that you need to set environment variables as well as specify Keycloak parameters, so a quick way to do this from the command line is just to execute from within a separate shell context, e.g. something like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo bash -c 'KC_DB=\"mysql\" KC_DB_URL=\"jdbc:mysql:\/\/<em>&lt;address<\/em>>:3306\/keycloak?characterEncoding=UTF-8\" KC_DB_USERNAME=\"keycloak\" KC_DB_PASSWORD=\"<em>&lt;password><\/em>\" \/opt\/keycloak\/bin\/kc.sh start --hostname=<em>&lt;hostname><\/em> --https-certificate-file=\/opt\/bitnami\/apache\/conf\/bitnami\/certs\/server.crt --https-certificate-key-file=\/opt\/bitnami\/apache\/conf\/bitnami\/certs\/server.key'<\/code><\/pre>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-ae0e1f5c5321958dc952bc83f2f9b9e8 is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>I&#8217;ve installed into <code>\/opt\/keycloak<\/code>, so feel free to replace with whichever location you&#8217;ve installed your Keycloak deployment.<\/em><\/p>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"turnkey\">Turnkey Solution<\/h3>\n\n\n<p>At some point, however, you&#8217;ll want to create a turnkey solution so that you can ensure Keycloak is always operational, particularly on reboot of the host environment, etc. Whilst it might seem like I&#8217;m &#8220;skipping ahead&#8221; a bit, I&#8217;m going to cover this now&#8230;which also saves time for those who just want to cut to the chase \ud83d\ude09<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-8f3830053decd2a39eafb4e022e451db is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Turnkey essentially means ready to use, often implying a complete, pre-packaged solution that requires minimal additional effort to operate. <\/em><\/p>\n<\/div>\n\n\n\n<p>As mentioned, I&#8217;m installing Keycloak as part of a LAMP deployment, using Apache Web Server, and hosted on AWS Lightsail, configured by a stack template supplied by Bitnami. <\/p>\n\n\n\n<p>I&#8217;ve added some additional bits for my specific use case scenario \u2014 like WordPress Multisite (see the Bitnami docs <a href=\"https:\/\/docs.bitnami.com\/aws\/apps\/wordpress-multisite\/\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a> for more details), that&#8217;s not required to host Keycloak \u2014 however, the setup is basically a Debian Linux distro, and so I&#8217;ll focus on how I set up a turnkey solution for that; your hosting may differ, but if it&#8217;s a Linux-based one, then most of what I share should still work.<\/p>\n\n\n<h4 class=\"wp-block-heading has-fira-code-font-family\" id=\"systemd\">systemd<\/h4>\n\n\n<p>As described in detail in the Digital Ocean article <a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/how-to-use-systemctl-to-manage-systemd-services-and-units\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a> (a fantastic primer on the topic) one of the most widely adopted mechanisms for Linux system management is <em><a href=\"https:\/\/systemd.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">systemd<\/a><\/em>, with the&nbsp;<code>systemctl<\/code>&nbsp;command being the central tool for controlling it. <\/p>\n\n\n\n<p><em>Systemd<\/em> is essentially a software suite (providing tools related to services, mounting points, and more) that manages Linux by acting as a system and service manager, and is the default init system option for many major Linux distributions.<\/p>\n\n\n\n<p>Using <em>systemd<\/em> and the <code>systemctl<\/code> command, it&#8217;s a relatively straightforward process to set up Keycloak-managed system initialisation, and when using <em>systemd<\/em> (which is typically run as a <code>root<\/code> service), the first thing to do is create the unit file. In this case, a <code>keycloak.service<\/code> unit file. Using the <code>nano<\/code> editor, this would be something like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/systemd\/system\/keycloak.service<\/code><\/pre>\n\n\n\n<p>In the editor (and where editing can also be achieved using the <code>systemctl edit keycloak<\/code> command), the next thing to do is add\/modify the relevant directives (documented <a href=\"https:\/\/www.freedesktop.org\/software\/systemd\/man\/latest\/systemd.service.html\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>) that control the service definition. In my case, where I&#8217;m deploying to a system configured by the stack template supplied by Bitnami, and also using MySQL (more <a href=\"#mysql\" title=\"\">below<\/a>), this looks similar to the following:<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-900011fa95c9359710dfd2300466da5b is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Changes made to an existing <code>.service<\/code> file may require a reload, which can typically be achieved using the <code>sudo systemctl daemon-reload<\/code> command. <\/em><\/p>\n<\/div>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;Unit]\nDescription=Keycloak\nAfter=syslog.target network.target\n\n# Hint: If Keycloak must be started before other services,\n# specify it like this:\nBefore=bitnami.service\n\n&#91;Service]\nLimitNOFILE=102642\nEnvironment=\"KC_DB=mysql\"\nEnvironment=\"KC_DB_URL=jdbc:mysql:\/\/<em>&lt;address:<\/em>3306|<em>port&gt;<\/em>\/<em>&lt;schema&gt;<\/em>?characterEncoding=UTF-8\"\nEnvironment=\"KC_DB_USERNAME=<em>&lt;DB user name&gt;<\/em>\"\nEnvironment=\"KC_DB_PASSWORD=<em>&lt;DB password&gt;<\/em>\"\nExecStart=\/opt\/keycloak\/bin\/kc.sh start --hostname=auth.cevolution.co.uk --http-max-queued-requests=<em>&lt;max request threshold&gt;<\/em> --https-certificate-file=\/opt\/bitnami\/apache\/conf\/bitnami\/certs\/server.crt --https-certificate-key-file=\/opt\/bitnami\/apache\/conf\/bitnami\/certs\/server.key --proxy-headers xforwarded\n\n&#91;Install]\nWantedBy=multi-user.target\n<\/code><\/pre>\n\n\n\n<p>I&#8217;m using a MySQL instance hosted externally \u2014 an important consideration for the work I&#8217;m currently doing \u2014 however, an AWS Lightsail instance templated by Bitnami typically comes with a MariaDB deployment that&#8217;s perfectly adequate. In fact, a localised DB deployment can be beneficial to a load-balanced, fault-tolerant, geographically distributed production system; however, all of that is a story for another time.<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"systemctl-commands\"><code>systemctl<\/code> Commands<\/h4>\n\n\n<p>I can now use the various <code>systemctl<\/code> commands to interact with the service, like getting status information and\/or restarting the service independently using the <code>start<\/code> and <code>stop<\/code> commands. <\/p>\n\n\n\n<p>The <code>system enable<\/code> command is particularly relevant, and you&#8217;ll want to run this at least once to enable the Keycloak service automatic start on boot; systemd automatically takes care of the start order based on the definitions in the service unit file (above).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl status keycloak\nsudo systemctl start keycloak\nsudo systemctl stop keycloak\nsudo systemctl enable keycloak<\/code><\/pre>\n\n\n<h2 class=\"wp-block-heading\" id=\"data-storage\">Data Storage<\/h2>\n\n\n<p>Whichever deployment route you choose, out-of-the-box Keycloak lets you get up and running with a data storage facility that utilises the local filesystem \u2014 great for minimal evaluation\/prototyping, but not particularly manageable or scalable. <\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-04ec4a3ce8ec2c2f2f53dbf331f36c50 is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Anything you set up under a basic out-of-box configuration will typically be lost when you change data storage, so it&#8217;s probably best not to do a huge amount without first configuring to use a database (even during prototype\/evaluation).<\/em><\/p>\n<\/div>\n\n\n\n<p>Ultimately, in a production environment, you&#8217;ll want to leverage a database, which also allows for Keycloak service distribution \u2014 i.e. the setup of multiple Keycloak servers for load\/geographical balance. You can read more in the official <em><a href=\"https:\/\/www.keycloak.org\/server\/configuration-production\" target=\"_blank\" rel=\"noreferrer noopener\">Configuring Keycloak for Production<\/a><\/em> guide. <\/p>\n\n\n\n<p>I&#8217;ve opted for the database route from the start because I want to be able to stand up both a development and a production instance of the Keycloak server, and I&#8217;ll also want to be able to use tools that help me investigate the data being generated\/consumed.<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-bf583b9e89ab4513fae6e053b42e6fd1 is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>As mentioned, I&#8217;m using a MySQL service and MySQL Workbench to help analyse performance, data tables usage, and configuration; a Bitnami templated stack on AWS Lightsail comes with MariaDB, which is equivalent to using MySQL. <\/em><\/p>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"mysql\">MySQL<\/h3>\n\n\n<p>Whether you&#8217;re configuring for MySQL or one of the other supported databases, you&#8217;ll want to get familiar with the official Keycloak documentation <a href=\"https:\/\/www.keycloak.org\/server\/db\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>. Keycloak is a Java application, and Java Database Connectors tend to follow a particular specification when it comes to configuring connection parameters; for MySQL, I&#8217;ve found the documentation <a href=\"https:\/\/dev.mysql.com\/doc\/connector-j\/en\/connector-j-reference.html\" target=\"_blank\" rel=\"noopener\" title=\"\">here<\/a> to be really useful \ud83d\ude0e<\/p>\n\n\n\n<p>Like me, you&#8217;re probably going to end up using an already deployed DBMS instance \u2014 in my case, MySQL \u2014 and defining a new Schema for Keycloak. If you are, then start by paying particular attention to <a href=\"https:\/\/www.keycloak.org\/server\/db#_preparing_for_mysql_server\">this<\/a> section of the documentation to check the suitability of your instance. For me, when creating a MySQL schema, I typically opt for a <code>utf8mb4<\/code> charset with <code>utf8mb4_general<\/code> collation, which provides blanket support for Unicode characters. Your requirements may be different.<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-77f9ddf608bdfe86b0758dd076659b8c is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Securing access to any database schema is important, but even more so for a database schema being used by a security subsystem. The use of TLS, as well as access restriction based on IP address, is always recommended.<\/em><\/p>\n<\/div>\n\n\n<h4 class=\"wp-block-heading\" id=\"schema-creation\">Schema Creation<\/h4>\n\n\n<p>According to the official <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.4\/en\/charset-unicode-sets.html\" target=\"_blank\" rel=\"noreferrer noopener\">MySQL docs<\/a>, <code>utf8mb4<\/code> provides Unicode support using 1-4 characters, and will soon be the default for the <code>utf8<\/code> alias (which currently uses the soon-to-be-deprecated <code>utf8mb3<\/code>). Whilst the <a href=\"https:\/\/www.keycloak.org\/server\/db#_configuring_unicode_support_for_a_mysql_database\" target=\"_blank\" rel=\"noreferrer noopener\">Keycloak docs<\/a> suggest <code>utf8mb4<\/code> is not currently supported, as in the full 4 characters are not currently used, I&#8217;ve preferred to opt for using the additional storage to prepare for when it is \ud83d\ude0e<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-362b44ed1838aa14dd2827e34137a1c9 is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>If anyone knows any reason why my choice of using <code>utf8mb4<\/code> might not be a good one \u2014 other than potentially consuming more storage space \u2014 please feel free to let me know \ud83e\udd17<\/em><\/p>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"tempadminaccount\">Temporary Admin Account<\/h3>\n\n\n<p>Whichever data storage route you choose, you&#8217;ll typically need to start by creating the temporary administrative user. This is the user who&#8217;ll be initially responsible for managing the whole Keycloak installation, and you will be encouraged to change it once you have established initial access (see <a href=\"#adminaccount\">below<\/a> for more details).<\/p>\n\n\n\n<p>If you&#8217;re installing in an interactive environment which also has Browser capability, then navigating to the admin console (described <a href=\"#adminconsole\">below<\/a>) via <code>localhost<\/code> will allow the creation of the temporary admin user. However, if, like me, you&#8217;re installing into an environment that has no (or limited) interactive Browser capability, then I&#8217;d recommend using the dedicated <code>bootstrap-admin<\/code> command as discussed in the official Keycloak documentation <a href=\"https:\/\/www.keycloak.org\/server\/bootstrap-admin-recovery#_bootstrapping_an_admin_user_or_service_account_using_the_dedicated_command\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>, and which goes something like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/opt\/keycloak\/bin\/kc.sh start --bootstrap-admin-username admin --bootstrap-admin-password password<\/code><\/pre>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-a763ad4faf6f8671a6d6f11c03f6f71b is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Keycloak also supports the use of a service account as the temporary administrator, but I haven&#8217;t tried that, so I won&#8217;t comment on it more here. The official Keycloak docs, though, provide <a href=\"https:\/\/www.keycloak.org\/server\/bootstrap-admin-recovery#_create_a_service_account\" target=\"_blank\" rel=\"noreferrer noopener\">further details<\/a>.<\/em><\/p>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"security\">Security<\/h2>\n\n\n<p>Security should be a paramount consideration for any deployed SaaS solution, and for security-related components, the importance is even greater: if you&#8217;re going to take an open-source DIY (Deploy It Yourself) approach to CIAM, the last thing you want is to have a system vulnerable to attack! <\/p>\n\n\n\n<p>AWS Lightsail deployments templated by <a href=\"https:\/\/docs.bitnami.com\/aws\/get-started-lightsail\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Bitnami<\/a> are already hardened from an OS\/Network perspective, and, in my case, the WordPress template has some additional attention. I&#8217;ll be talking more about hardening from a security perspective in future articles, but for now, here are some of the basic things that will make your Keycloak installation secure.<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"adminaccount\">Permanent Admin Account<\/h3>\n\n\n<p>The temporary admin account generated by Keycloak is just that \u2014 i.e. temporary \u2014 and should be changed as part of the configuration process. Actually, &#8220;change&#8221; is not the correct term, as Keycloak doesn&#8217;t really allow you to &#8220;change&#8221; an admin user per se.<\/p>\n\n\n\n<p>Once connected to the admin console (see <a href=\"#adminconsole\">below<\/a> for details), the first thing Keycloak will remind you to do is to <em>replace<\/em> the temporary admin account you previously created (see <a href=\"#tempadminaccount\">above<\/a>). <\/p>\n\n\n\n<p>From a security perspective, using a name other than <code>admin<\/code> or <code>administrator<\/code> is always preferable, and, of course, a suitably obscure password makes life difficult for a would-be hacker!<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-1b265c81caf6b3fe17b17715a9fb4940 is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>As you&#8217;ll see in the section <a href=\"#proxy\" title=\"\">below<\/a>, using a proxy to cloak admin console access makes things even more secure.<\/em><\/p>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"tls\">TLS<\/h3>\n\n\n<p>No SaaS security-related system should be run without some level of transport encryption: HTTP traffic is typically routed via the internet, which means potential interception by any third party. Fortunately, when using the HTTP protocol, it&#8217;s relatively easy to do this by using TLS (a.k.a. HTTPS), enabled by an appropriate certificate.<\/p>\n\n\n\n<p>Keycloak can be easily configured to use TLS as described in the official documentation <a href=\"https:\/\/www.keycloak.org\/server\/enabletls\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>, which includes details of leveraging a system keystore as an option, too. However, below you&#8217;ll find an easy-to-use example \u2014 replacing the <code>--hostname<\/code> value with one compatible with the certificate you&#8217;re using. Remember, this is based on simple command line usage, whereas my solution to a fully configured turnkey approach, <a href=\"#turnkey\">above<\/a>, has everything combined.<\/p>\n\n\n\n<pre class=\"wp-block-code has-roboto-slab-font-family\"><code>\/opt\/keycloak\/bin\/kc.sh start --hostname=auth.cevolution.co.uk --https-certificate-file=\/opt\/bitnami\/apache\/conf\/bitnami\/certs\/server.crt --https-certificate-key-file=\/opt\/bitnami\/apache\/conf\/bitnami\/certs\/server.key<\/code><\/pre>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-07df9bec1f68f12752fc75ae4d31fd55 is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>If you&#8217;re planning to use a reverse proxy \u2014 see the <a href=\"#proxy\" title=\"\">next section<\/a> for more details \u2014 you can potentially skip TLS if you&#8217;re going to terminate SSL at the proxy; encryption is computationally intensive, so there&#8217;s no need to do it needlessly. However, there are many things to consider from a security perspective if you do opt for that approach, which are beyond the scope of this article.  <\/em><\/p>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"proxy\">Reverse Proxy<\/h3>\n\n\n<p>Setting up a reverse proxy for Keycloak is a really good option for hardening security and paving the way for scalability if it comes to the point you need it. For instance, using a proxy will allow you to restrict Keycloak administration (discussed <a href=\"#adminconsole\">later<\/a>) to a limited set of clients, whilst opening up the other routes to the internet. This is described in more detail in the official Keycloak documentation <a href=\"https:\/\/www.keycloak.org\/server\/reverseproxy\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>, so the first thing to probably do is take a look at that.<\/p>\n\n\n\n<p>As mentioned previously, I&#8217;m using Apache Web Server as part of an installation on AWS Lightsail, powered by a stack template supplied by Bitnami, and this is specific to my use case scenario. <\/p>\n\n\n\n<p>It&#8217;s certainly not a requirement to proxy Keycloak, and you may not even be using Apache. However, setting up a proxy will provide benefits long term \u2014 paving the way for scalability, for example, as I say \u2014 and if you do decide to use Apache, the documentation <a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/how-to-use-apache-as-a-reverse-proxy-with-mod_proxy-on-ubuntu-16-04\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a> (supplied by Digital Ocean) provides a really good primer on setting up and enabling it as a general reverse proxy for HTTP et al.<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-8669805d75ea73a47a062b587a23f14a is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Bitnami provide a number of <a href=\"https:\/\/docs.bitnami.com\/aws\/apps\/\" target=\"_blank\" rel=\"noreferrer noopener\">different stacks for AWS<\/a> \u2014 and other hosting platforms for that matter \u2014 and my setup already came with <code>mod_proxy<\/code> and its associated components (e.g. <code>mod_proxy_http<\/code>), all of which you will need for proxing via Apache, enabled by default. <\/em><\/p>\n<\/div>\n\n\n\n<p>Once you&#8217;ve enabled proxy capability on whatever web server you&#8217;re using, you&#8217;ll need to configure it. As I say, I&#8217;m using Apache, so the configuration I&#8217;m going to describe is for that, and I&#8217;ll be doing so within the context of the setup provided by Bitnami (though it should be easy to work out what you need to do for your situation; Apache \u2014 or an equivalent web server \u2014 is the only thing you really need).<\/p>\n\n\n\n<p>Start by configuring a <em>vhost<\/em> for Keycloak, using something like the following example; this will provide Apache with the proxy definitions it requires, and in my configuration, I called it something like <code>keycloak-https-vhost.conf<\/code> (TLS being the best practice recommendation, as described <a href=\"http:\/\/tls\">above<\/a>).<\/p>\n\n\n\n<pre class=\"wp-block-code has-roboto-slab-font-family\"><code>&lt;VirtualHost _default_:443&gt;\n  ServerName <em>&lt;hostname&gt;<\/em>\n\n  SSLEngine on\n  SSLCertificateFile \"\/opt\/bitnami\/apache\/conf\/bitnami\/certs\/server.crt\"\n  SSLCertificateKeyFile \"\/opt\/bitnami\/apache\/conf\/bitnami\/certs\/server.key\"\n  SSLProxyEngine On\n  SSLProxyCheckPeerExpire Off\n  SSLProxyCheckPeerName Off\n  SSLProxyCheckPeerCN Off\n\n  ProxyPass \/resources https:\/\/localhost:8443\/resources\/\n  ProxyPassReverse \/resources https:\/\/localhost:8443\/resources\/\n\n  ProxyPass \/realms https:\/\/localhost:8443\/realms\/\n  ProxyPassReverse \/realms https:\/\/localhost:8443\/realms\/\n\n  ErrorLog logs\/error_keycloak.log\n  CustomLog logs\/access_keycloak.log common\n&lt;\/VirtualHost&gt;<\/code><\/pre>\n\n\n\n<p>I specified additional <code>ErrorLog<\/code> and <code>CustomLog<\/code> definitions so that I could keep Keycloak proxy logging separate from everything else (Apache, in my case, also being used to support WordPress). <\/p>\n\n\n\n<p>The various <code>SSLProxyCheck<\/code> settings were also required to bypass peer context checking, given that I&#8217;m using a <code>localhost<\/code> target reference: for me, both Keycloak and Apache are on the same machine, and I&#8217;m not doing SSL termination at the proxy.<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"rate-limiting\">Rate Limiting<\/h3>\n\n\n<p>As described in the official Keycloak documentation, <a href=\"https:\/\/www.keycloak.org\/server\/configuration-production#_limit_the_number_of_queued_requests\" title=\"\">limiting the number of queued requests<\/a> in a production environment is a recommended best practice, and you should use the <code>http-max-queued-requests<\/code> option to configure this accordingly to protect your Keycloak installation from overload \u2014 i.e. by rejecting requests once a certain threshold is reached. <\/p>\n\n\n\n<p>What that threshold might be will depend on your use case and also your configuration; I&#8217;ve opted for a setting of 100 (at least whilst in development). As the Keycloak docs suggest, you should reflect this throughout your Keycloak infrastructure, including tuning whatever load balancing (via proxy) you have in your environment.<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-9474aa5d43bfb388e4b99622cd749e81 is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Outside of Keycloak specific defintions, proxy configuration and\/or your infrastructure provider will likely provide additional rate-limiting mechanisms which you should familiarise yourself with and leverage where appropriate. <\/em><\/p>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"adminconsole\">Administration<\/h2>\n\n\n<p>For the newly initiated, administration is largely performed via the Keycloak <em>Admin Console<\/em>; from a <a data-type=\"page\" data-id=\"18\" href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/manage\/\" target=\"_blank\" rel=\"noreferrer noopener\">Management<\/a> perspective, Keycloak provides an <a href=\"https:\/\/www.keycloak.org\/docs-api\/latest\/rest-api\/index.html\" target=\"_blank\" rel=\"noreferrer noopener\">Admin API<\/a>, which also allows operational configuration to be integrated within a CI\/CD pipeline or other automation as part of the SDLC, etc., but that&#8217;s a story for another time. <\/p>\n\n\n\n<p>At some stage, I&#8217;ll no doubt share my own take on the various aspects of the Keycloak Admin Console from a Customer Identity perspective (and you&#8217;ll be able to read those articles on the <a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/blog\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Discover CIAM Blog<\/a> at some point in the future). <\/p>\n\n\n\n<p>For now, however, the following by <em><a href=\"https:\/\/www.youtube.com\/@code-215\" target=\"_blank\" rel=\"noopener\" title=\"\">@code-215<\/a><\/em> comes across as being a fairly good introduction, despite it being a few years old now; though I&#8217;ll not go much further in this article, there are a few aspects of the Admin Console that are worth paying particular attention to.:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Keycloak Admin Console Tutorial\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/j0oIguIa0r0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n<h3 class=\"wp-block-heading\" id=\"realm\">Realm<\/h3>\n\n\n<p>A realm is a discrete space where you manage objects like clients, users, roles, etc. Creating a new realm is relatively straightforward and is probably the first thing you&#8217;ll want to do from the <em>Admin Console<\/em>. If you are already familiar with a CIAM solution like Auth0, then a Realm is analogous to a Tenant (at least in the Auth0 case).<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"realm-isolation\">Realm Isolation<\/h4>\n\n\n<p>Many folks go overboard when it comes to creating realms, and probably the best advice I can share here is to use them sparingly. Realms are isolating constructs, so sharing the likes of client definitions, users, or roles across them is restricted. Ergo, prefer to use a new Realm only when hard isolation is required, e.g:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Environmental separation<\/strong>: i.e. for development, staging, and production to test changes in isolation.<\/li>\n\n\n\n<li><strong>Functional separation<\/strong>: i.e. in large (corporate) enterprises that may be developing discrete internal B2C style applications for different departments or business units.<\/li>\n<\/ul>\n\n\n\n<p>Having said that, I would always recommend that you create at least one realm in addition to the <code>master<\/code> realm that comes supplied out of the box. You&#8217;re going to want to do this because you&#8217;ll want to keep your <span class=\"popup-trigger popmake-1354 \" data-popup-id=\"1354\" data-do-default=\"0\">B2C<\/span>\/<span class=\"popup-trigger popmake-418 \" data-popup-id=\"418\" data-do-default=\"0\">B2B<\/span> SaaS user definitions separate from those users who can administer Keycloak (even if they might also be users\/administrators of your <span class=\"popup-trigger popmake-2946 \" data-popup-id=\"2946\" data-do-default=\"0\">SaaS<\/span> application). <\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-accent-4-background-color has-text-color has-background has-link-color wp-elements-0ba2ec91f79436533a6c36ce68b270cf is-layout-flow wp-block-group-is-layout-flow\" style=\"border-radius:20px\">\n<p class=\"has-text-align-center\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><em>Prior to v26, the Keycloak Realm metaphor was often used to model multitenancy in <span class=\"popup-trigger popmake-418\" data-popup-id=\"418\" data-do-default=\"0\">B2B<\/span> SaaS applications. Since Keycloak v26, however, this is now modelled natively using the Organizations feature (discussed <a href=\"#organizations\">below<\/a>)<\/em><\/p>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"client\">Client<\/h3>\n\n\n<p>As per <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc6749#section-1.1\" target=\"_blank\" rel=\"noopener\" title=\"\">RFC 6749<\/a>  \u2014 the <span class=\"popup-trigger popmake-467\" data-popup-id=\"467\" data-do-default=\"0\">OAuth 2.0<\/span> specification \u2014 a client represents an application that uses Keycloak. To be more precise, I take the perspective of a client representing an aspect of an application that utilises OAuth 2.0 (and\/or <span class=\"popup-trigger popmake-407\" data-popup-id=\"407\" data-do-default=\"0\">OIDC<\/span>), and in the admin console, under the newly created realm, you can create the various clients you need to reflect your SaaS application requirements. I&#8217;ll talk more about client definitions in future articles as I show how to integrate with Keycloak \ud83d\ude0a<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"users\">Users<\/h3>\n\n\n<p>Likewise, for users, the admin console shows the users defined to the realm and allows you to add and\/or modify user definitions as required. <\/p>\n\n\n\n<p>For anything other than the <code>master<\/code> realm, users are typically created via the CIAM interactions of your B2C\/B2B SaaS applications; from a management perspective, and in a development context in particular, the admin console provides authorised personnel with an out-of-box interface to manipulate the various aspects of any user definition \u2014 especially when it comes to manipulating the specifics associated with a user account.<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"organizations\">Organizations<\/h3>\n\n\n<p>I&#8217;m going to cover Keycloak <em>Organizations<\/em> in detail in a future article; it&#8217;s a crucial feature if you&#8217;re developing a <span class=\"popup-trigger popmake-418\" data-popup-id=\"418\" data-do-default=\"0\">B2B<\/span> SaaS application, and so worthy of a discussion in its own right. In the meantime, the folks over at <a href=\"https:\/\/inero-software.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Inero Software<\/a> \u2014 a consultancy specialising in <span class=\"popup-trigger popmake-3257\" data-popup-id=\"3257\" data-do-default=\"0\">IAM<\/span> integrations, amongst other things \u2014 have created a short article of their own that&#8217;s worth checking out:<\/p>\n\n\n\n<div class=\"wp-block-group is-content-justification-center is-nowrap is-layout-flex wp-container-core-group-is-layout-23441af8 wp-block-group-is-layout-flex\">\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-inero-software-rozwi-zania-it-i-konsulting wp-block-embed-inero-software-rozwi-zania-it-i-konsulting\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"rYq06s6kM2\"><a href=\"https:\/\/inero-software.com\/organizations-in-keycloak-management-and-customization-of-authentication\/\">Organizations in Keycloak: Management and Customization of Authentication<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&#8220;Organizations in Keycloak: Management and Customization of Authentication&#8221; &#8212; Inero Software - Rozwi\u0105zania IT i Konsulting\" src=\"https:\/\/inero-software.com\/organizations-in-keycloak-management-and-customization-of-authentication\/embed\/#?secret=y9D6olZXjT#?secret=rYq06s6kM2\" data-secret=\"rYq06s6kM2\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"access-restriction\">Access Restriction<\/h3>\n\n\n<p>One last thing to cover for now is how using a reverse proxy setup can help provide additional protection to your Keycloak environment. Unlike with most 3rd-party SaaS CIAM solutions, with Keycloak DIY, a proxy can be used to completely cloak access to the admin console \u2014 and also the Keycloak management API \u2014 from anything other than a specific set of IP addresses (i.e. typically those behind your firewall). This really does limit the potential for malicious attack. <\/p>\n\n\n\n<p>In my case, for example, I have Keycloak running on port <code>8443<\/code> and have restricted public internet access to all routes <em>except<\/em> <code>\/realms<\/code> and <code>\/resources<\/code> (as described in the section <a href=\"#proxy\" title=\"\">above<\/a>). I&#8217;ve then opened up port <code>8443<\/code> at the infrastructure level \u2014 in my case, AWS Lightsail \u2014 to only a handful of IP addresses, in a process commonly referred to as <em>IP Allowlisting<\/em>.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"integration\">Integration<\/h2>\n\n\n<p>I recently shared an article on my experience with Vibe Coding, which, for those not familiar, is an AI-dependent programming technique where you can describe a problem in a few sentences as a prompt to a large language model (LLM) tuned for coding. It was a fun CIAM integration experiment, and since then, I&#8217;ve been doing more Vibe Coding as part of the work I&#8217;m doing on the <span class=\"popup-trigger popmake-2946\" data-popup-id=\"2946\" data-do-default=\"0\">SaaS<\/span> applications I&#8217;m developing. <\/p>\n\n\n\n<p>My experiment used Keycloak to integrate CIAM Authentication into a simple Next.js application, so for now, I will sign off by providing a link to that article; be sure to watch out for more articles in a similar vein very soon \ud83d\ude0e<\/p>\n\n\n\n<div class=\"wp-block-group is-content-justification-center is-nowrap is-layout-flex wp-container-core-group-is-layout-23441af8 wp-block-group-is-layout-flex\">\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-discover-ciam wp-block-embed-discover-ciam\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"i4cxPRzYJR\"><a href=\"https:\/\/discovery.cevolution.co.uk\/ciam\/2025\/05\/16\/vibe-coded-authn\/\">Vibe Coding Authentication via Authorization Code Flow<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&#8220;Vibe Coding Authentication via Authorization Code Flow&#8221; &#8212; Discover CIAM\" src=\"https:\/\/discovery.cevolution.co.uk\/ciam\/2025\/05\/16\/vibe-coded-authn\/embed\/#?secret=FbybeipXwP#?secret=i4cxPRzYJR\" data-secret=\"i4cxPRzYJR\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Integrating Keycloak into a SaaS application provides a robust, cost-effective CIAM solution for managing user Authentication and Authorization. In this article, I&#8217;ll show you how to easily set up a Keycloak instance to provide a best-practice CIAM implementation that will help ensure your application is safe from unauthorised access.<\/p>\n","protected":false},"author":1,"featured_media":3238,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"authenticate":"","authentication":"","authenticatedMethod":"","authenticatedMember":"","authorizedPermissions":[],"_jetpack_memberships_contains_paid_content":false,"footnotes":"[]","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2},"_links_to":"","_links_to_target":""},"categories":[7],"tags":[6,28,65],"class_list":["post-443","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-integration","tag-diy","tag-keycloak","tag-opensourceciam"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/discovery-bucket-ha60ib.s3.eu-west-2.amazonaws.com\/wp-content\/uploads\/sites\/22\/2025\/03\/21123957\/create-a-highly-detailed-sharp-focused-image-showcasing-the-concept-of.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/posts\/443","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/comments?post=443"}],"version-history":[{"count":181,"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/posts\/443\/revisions"}],"predecessor-version":[{"id":5208,"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/posts\/443\/revisions\/5208"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/media\/3238"}],"wp:attachment":[{"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/media?parent=443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/categories?post=443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/discovery.cevolution.co.uk\/ciam\/wp-json\/wp\/v2\/tags?post=443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}