<!--
  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
  ~ and other contributors as indicated by the @author tags.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<chapter id="themes">
    <title>Themes</title>

    <para>
        Keycloak provides theme support for web pages and emails. This allows customizing the look
        and feel of end-user facing pages so they can be integrated with your applications.
    </para>

    <section>
        <title>Theme types</title>
        <para>
            A theme can support several types to customize different aspects of Keycloak. The types currently available
            are:
            <itemizedlist>
                <listitem>Account - Account management</listitem>
                <listitem>Admin - Admin console</listitem>
                <listitem>Email - Emails</listitem>
                <listitem>Login - Login forms</listitem>
                <listitem>Welcome - Welcome pages</listitem>
            </itemizedlist>
        </para>
    </section>

    <section>
        <title>Configure theme</title>
        <para>
            All theme types, except welcome, is configured through <literal>Keycloak Admin Console</literal>. To change
            the theme used for a realm open the <literal>Keycloak Admin Console</literal>, select your realm
            from the drop-down box in the top left corner. Under <literal>Settings</literal> click on <literal>Theme</literal>.
        </para>
        <para>
            To set the theme for the <literal>master</literal> Keycloak admin console set the admin console theme for
            the <literal>master</literal> realm. To set the theme for per realm admin access control set the admin console
            theme for the corresponding realm.
        </para>
        <para>
            To change the welcome theme you need to edit <literal>standalone/configuration/keycloak-server.json</literal>
            and add <literal>welcomeTheme</literal> to the theme element, for example:
<programlisting>
"theme": {
    ...
    "welcomeTheme": "custom-theme"
}
</programlisting>
        </para>
    </section>

    <section>
        <title>Default themes</title>
        <para>
            Keycloak comes bundled with default themes in <literal>standalone/configuration/themes</literal>. You should
            not edit the bundled themes directly. Instead create a new theme that extends a bundled theme.
        </para>
    </section>

    <section>
        <title>Creating a theme</title>
        <para>
            A theme consists of:
            <itemizedlist>
                <listitem><ulink url="http://freemarker.org">FreeMarker</ulink> templates</listitem>
                <listitem>Stylesheets</listitem>
                <listitem>Scripts</listitem>
                <listitem>Images</listitem>
                <listitem>Message bundles</listitem>
                <listitem>Theme properties</listitem>
            </itemizedlist>
        </para>
        <para>
            A theme can extend another theme. When extending a theme you can override individual files (templates, stylesheets, etc.).
            The recommended way to create a theme is to extend the base theme. The base theme provides templates
            and a default message bundle. If you decide to override templates bear in mind that you may need to update
            your templates when upgrading to a new release to include any changes made to the original template.
        </para>
        <para>
            Before creating a theme it's a good idea to disable caching as this makes it possible to edit theme resources
            without restarting the server. To do this open <literal>../standalone/configuration/keycloak-server.json</literal>
            for <literal>theme</literal> set <literal>staticMaxAge</literal> to <literal>-1</literal> and
            <literal>cacheTemplates</literal> and <literal>cacheThemes</literal> to <literal>false</literal>. For example:
<programlisting>[<![CDATA[
"theme": {
    "default": "keycloak",
    "staticMaxAge": -1,
    "cacheTemplates": false,
    "cacheThemes": false,
    "folder": {
      "dir": "${jboss.server.config.dir}/themes"
    }
},
]]></programlisting>
            Remember to re-enable caching in production as it will significantly impact performance.
        </para>
        <para>
            To create a new theme create a directory for the theme in <literal>.../standalone/configuration/themes</literal>.
            The name of the directory should be the name of the theme. For example to create a theme called <literal>example-theme</literal>
            create the directory <literal>.../standalone/configuration/themes/example-theme</literal>. Inside the theme
            directory you then need to create a directory for each of the types your theme is going to provide. For example
            to add the login type to the <literal>example-theme</literal> theme create the directory
            <literal>.../standalone/configuration/themes/example-theme/login</literal>.
        </para>
        <para>
            For each type create a file <literal>theme.properties</literal> which allows setting some configuration for
            the theme, for example what theme it overrides and if it should import any themes. For the above example we
            want to override the base theme and import common resources from the Keycloak theme. To do this create the
            file <literal>.../standalone/configuration/themes/example-theme/login/theme.properties</literal> with the
            following contents:
<programlisting>[<![CDATA[
parent=base
import=common/keycloak
]]></programlisting>
        </para>
        <para>
            You have now created a theme with support for the login type. To check that it works open the admin console.
            Select your realm and click on <literal>Themes</literal>. For <literal>Login Theme</literal> select
            <literal>example-theme</literal> and click <literal>Save</literal>. Then open the login page for the realm.
            You can do this either by login through your application or by opening <literal>http://localhost:8080/realms/&lt;realm name&gt;/account</literal>.
        </para>
        <para>
            To see the effect of changing the parent theme, set <literal>parent=keycloak</literal> in <literal>theme.properties</literal>
            and refresh the login page. To follow the rest of the documentation set it back to <literal>parent=base</literal>
            before continuing.
        </para>
        <section>
            <title>Stylesheets</title>
            <para>
                A theme can have one or more stylesheets, to add a stylesheet create a file inside <literal>resources/css</literal>
                (for example <literal>resources/css/styles.css</literal>) inside your theme folder. Then registering it
                in <literal>theme.properties</literal> by adding:
            </para>
            <programlisting>styles=css/styles.css</programlisting>
            <para>
                The <literal>styles</literal> property supports a space separated list so you can add as many
                as you want. For example:
            </para>
            <programlisting>styles=css/styles.css css/more-styles.css</programlisting>
            For the example-theme above add <literal>example-theme/login/resources/css/styles.css</literal> with the
            following content:
<programlisting>[<![CDATA[
#kc-form {
    background-color: #000;
    color: #fff;
    padding: 20px;
}]]></programlisting>
            Then edit <literal>example-theme/login/theme.properties</literal> and add <programlisting>styles=css/styles.css</programlisting>.
            Refresh the login page to see your changes. It's not pretty, but you can see how easily you can modify the
            styles for your theme.
        </section>
        <section>
            <title>Scripts</title>
            <para>
                A theme can have one or more scripts, to add a script create a file inside <literal>resources/js</literal> (for example <literal>resources/js/script.js</literal>)
                inside your theme folder. Then registering it in <literal>theme.properties</literal> by adding:
            </para>
            <programlisting>scripts=js/script.js</programlisting>
            <para>
                The <literal>scripts</literal> property supports a space separated list so you can add as many
                as you want. For example:
            </para>
            <programlisting>scripts=js/script.js js/more-script.js</programlisting>
        </section>
        <section>
            <title>Images</title>
            <para>
                To make images available to the theme add them to <literal>resources/img</literal>. They can then be used
                through stylesheets. For example:
            </para>
            <programlisting>body {
    background-image: url('../img/image.jpg');
}</programlisting>
            <para>
                Or in templates, for example:
            </para>
            <programlisting>&lt;img src="${url.resourcesPath}/img/image.jpg"&gt;</programlisting>
        </section>
        <section>
            <title>Messages</title>
            <para>
                Text in the templates are loaded from message bundles. A theme that extends another theme will inherit
                all messages from the parents message bundle, but can override individual messages. For example to replace
                <literal>Username</literal> on the login form with <literal>Your Username</literal> create the file
                <literal>messages/messages.properties</literal> inside your theme folder and add the following content:
            </para>
            <programlisting>username=Your Username</programlisting>
            <para>
                For the admin console, there is a second resource bundle named <literal>admin-messages.properties</literal>.
                This resource bundle is converted to JSON and shipped to the console to be processed by
                angular-translate.  It is found in the same directory as messages.properties and can be overridden
                in the same way as described above.
            </para>
        </section>
        <section>
            <title>Modifying HTML</title>
            <para>
                Keycloak uses <ulink url="http://freemarker.org">Freemarker Templates</ulink> in order to generate HTML.
                These templates are defined in <literal>.ftl</literal> files and can be overriden from the base theme.
                Check out the Freemarker website on how to form a template file. To override the login template for the
                <literal>example-theme</literal> copy <literal>../standalone/configuration/themes/base/login/login.ftl</literal>
                to <literal>../standalone/configuration/themes/example-theme/login</literal> and open it in an editor. After
                the first line (&lt;#import ...&gt;) add <literal>&lt;h1&gt;HELLO WORLD!&lt;/h1&gt;</literal> then refresh
                the page.
            </para>
        </section>
    </section>

    <section>
        <title>Deploying themes</title>
        <para>
            Themes can be deployed to Keycloak by copying the theme directory to <literal>../standalone/configuration/themes</literal>
            or it can be deployed as a module. For a single server or during development just copying the theme is fine, but
            in a cluster or domain it's recommended to deploy as a module.
        </para>
        <para>
            To deploy a theme as a module you need to create an jar (it's basically just a zip with jar extension) with
            the theme resources and a file <literal>META/keycloak-themes.json</literal> that describes the themes contained
            in the archive. For example <literal>example-theme.jar</literal> with the contents:
            <itemizedlist>
                <listitem>META-INF/keycloak-themes.json</listitem>
                <listitem>theme/example-theme/login/theme.properties</listitem>
                <listitem>theme/example-theme/login/login.ftl</listitem>
                <listitem>theme/example-theme/login/resources/css/styles.css</listitem>
            </itemizedlist>
            The contents of META-INF/keycloak-themes.json in this case would be:
<programlisting>[<![CDATA[
{
    "themes": [{
        "name" : "example-theme",
        "types": [ "login" ]
    }]
}
]]></programlisting>
            As you can see a single jar can contain multiple themes and each theme can support one or more types.
        </para>
        <para>
            The deploy the jar as a module to Keycloak you can either manually create the module or use <literal>jboss-cli</literal>.
            It's simplest to use <literal>jboss-cli</literal> as it creates the required directories and module descriptor
            for you. To deploy the above jar <literal>jboss-cli</literal> run:
<programlisting>[<![CDATA[
    KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.example.exampletheme --resources=example-theme.jar"
]]></programlisting>
            If you're on windows run <programlisting>KEYCLOAK_HOME/bin/jboss-cli.bat</programlisting>.
        </para>
        <para>
            This command creates <literal>modules/org/example/exampletheme/main</literal> containing <literal>example-theme.jar</literal>
            and <literal>module.xml</literal>.
        </para>
        <para>
            Once you've created the module you need to register it with Keycloak do this by editing
            <literal>../standalone/configuration/keycloak-server.json</literal> and adding the module to <literal>theme/module/modules</literal>. For example:
<programlisting>[<![CDATA[
"theme": {
    ...
    "module": {
        "modules": [ "org.example.exampletheme" ]
    }
}
]]></programlisting>
        </para>
        <para>
            If a theme is deployed to <literal>../standalone/configuration/themes</literal> and as a module the first
            is used.
        </para>
    </section>

    <section>
        <title>SPIs</title>
        <para>
            For full control of login forms and account management Keycloak provides a number of SPIs.
        </para>
        <section>
            <title>Account SPI</title>
            <para>
                The Account SPI allows implementing the account management pages using whatever web framework or templating
                engine you want. To create an Account provider implement <literal>org.keycloak.account.AccountProviderFactory</literal>
                and <literal>org.keycloak.account.AccountProvider</literal>.
            </para>
            <para>
                Once you have deployed your account provider to Keycloak you need to configure <literal>keycloak-server.json</literal> to specify which provider should be used:
<programlisting>
"account": {
    "provider": "custom-provider"
}
</programlisting>
            </para>
        </section>
        <section>
            <title>Login SPI</title>
            <para>
                The Login SPI allows implementing the login forms using whatever web framework or templating
                engine you want. To create a Login forms provider implement <literal>org.keycloak.login.LoginFormsProviderFactory</literal>
                and <literal>org.keycloak.login.LoginFormsProvider</literal> in <literal>forms/login-api</literal>.
            </para>
            <para>
                Once you have deployed your account provider to Keycloak you need to configure <literal>keycloak-server.json</literal> to specify which provider should be used:
<programlisting>
"login": {
    "provider": "custom-provider"
}
</programlisting>
            </para>
        </section>
    </section>

</chapter>
