keycloakify / keycloakify Goto Github PK
View Code? Open in Web Editor NEWπ Create Keycloak themes using React
Home Page: https://www.keycloakify.dev
License: MIT License
π Create Keycloak themes using React
Home Page: https://www.keycloakify.dev
License: MIT License
Is there any specific guide to make it work with custom webpack config.
When I tried it is just tries to find the bundle.js on the keycloak domain and gives 404 error.
Any suggestion, how can I fix it or using create-react-app
is absolutely essential ?
This is awesome project, thank you.
Can it support other technologies like VueJS?
I saw that the base Keycloak theme is generating JSON files based on the realm configuration
What else do we need?
I'm pretty new to react and this is more of a question than an issue and it may not even be an issue with this library.
Some background on what I'm trying to achieve:
I would like to use a single Keycloakify project to render different themes for multiple clients based on the clientId kc context value. In the past, I would simply extend a theme and append to the styles
property with the file path to client specific css to override the previous styles. Is there a way to do that with this library?
I first tried to import the css path as I do with favicon import client1Favicon from "app/assets/client1/favicon.ico";
and append that to styles
but I had no luck with that as the value was an object. But I'll continue looking into this, there may be some webpack option I can use to address this.
I also tried using code splitting feature to generate multiple css files but I now receive 404s as the Keycloak resource path is not prepended, example:
https://REDACTED/auth/resources/31exq/login/keycloakify/build/static/css/main.761845f0.chunk.css
https://REDACTED/static/css/4.75c36a70.chunk.css
Only the main.*
chunks are available. Would it be possible for this to be fixed in the build-keycloak-theme scripts?
Here's a snippet of my components:
Main component:
const Component = lazy(() => {
return Promise.resolve(import("./path/to/component2"));
});
export const Login = ({ kcContext, ...kcProps }: KcContextLoginComponent) => {
return (
<Suspense fallback={<DefaultLogin {...props} />}>
<Component {...props} />
</Suspense>
)
};
Component2
import "./component2.scss";
const Component2 = memo((props: KcContextLoginComponent) => {
return <Login {...props} />;
});
Component2.displayName = "Component2";
export default Component2;
Here's my resulting build folder directory build_keycloak/src/main/resources/theme/keycloakify/login/resources/build/static
:
.
βββ css
β βββ 3.976b061b.chunk.css
β βββ 3.976b061b.chunk.css.map
β βββ 4.1a7cc1a2.chunk.css
β βββ 4.1a7cc1a2.chunk.css.map
β βββ main.1bbd513a.chunk.css
β βββ main.1bbd513a.chunk.css.map
βββ js
β βββ 2.62a3ec59.chunk.js
β βββ 2.62a3ec59.chunk.js.LICENSE.txt
β βββ 2.62a3ec59.chunk.js.map
β βββ 3.f64e32e6.chunk.js
β βββ 3.f64e32e6.chunk.js.map
β βββ 4.30b8d41c.chunk.js
β βββ 4.30b8d41c.chunk.js.map
β βββ 5.66f9d5bf.chunk.js
β βββ 5.66f9d5bf.chunk.js.map
β βββ main.66a4253a.chunk.js
β βββ main.66a4253a.chunk.js.map
β βββ runtime-main.0d72eac6.js
β βββ runtime-main.0d72eac6.js.map
βββ media
βββ banner.8160ab86.png
βββ favicon.0c02463a.ico
βββ favicon.5d99451e.ico
βββ favicon.81150f84.ico
βββ favicon.9115d06a.ico
βββ favicon.9921761b.ico
βββ favicon.ec5b0a49.ico
βββ favicon.f5926395.ico
βββ favicon.f6bfd61d.ico
βββ logo-text-300x63.e429c0bd.png
I'm trying to adopt keycloakify with my own theme library by re-implementing KcApp
, importing all pages and incrementally substituting my own template and page components. However with the v2 upgrade (I had just gotten this working for v1 when v2 was released) LoginOtp
, Register
and Terms
are not exported. Is this an oversight, or is something not working for them?
Hello,
Could you please provide some documentation that how can we add our custom styles?
I have tried many ways using useStyles
of tss-react
and styling of material/ui but whenever I run app keycloak, page does not render and says that Refused to apply styles
.
I would be grateful if you can provide a guide to customize styles.
Thanks
Hello!
We have a highly customized Keycloak setup and have added a couple of additional '.ftl' pages to our login & signup flows.
As far as I know, the current version does not support such a thing as building arbitrary Freemarker pages. The only way I see to achieve this is to fork the library and add them manually to the build script.
Will it be possible to incorporate such functionality into the library? I could work on the PR if it's feasible (any advice is more than welcome ofc).
P.S. Thanks for the lib, it's a great piece of work, saved so much time for us π
FTL stack trace ("~" means nesting-related):
- Failed at: #local value = object[key] [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 77, column 21]
- Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 43, column 5]
- Reached through: @objectToJson_please_ignore_errors ob... [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 88, column 27]
- Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 43, column 5]
- Reached through: @objectToJson_please_ignore_errors ob... [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 88, column 27]
- Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 43, column 5]
- Reached through: @objectToJson_please_ignore_errors ob... [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 88, column 27]
- Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 43, column 5]
- Reached through: @objectToJson_please_ignore_errors ob... [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 88, column 27]
Compiling...
/home/user/projects/keycloak/keycloakify-demo-app/node_modules/react-scripts/scripts/start.js:19
throw err;
^
[Error: ENOENT: no such file or directory, stat '/home/user/.steampath'] {
errno: -2,
code: 'ENOENT',
syscall: 'stat',
path: '/home/user/.steampath'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
OS: Linux
Keycloakify version is 0.3.22.
I'm using this template without any edit, just only upgraded keycloakify.
./node_modules/keycloakify/lib/i18n/useKcMessage.js
Module not found: Can't resolve 'markdown' in '/home/user/projects/keycloak/keycloakify-demo-app/node_modules/keycloakify/lib/i18n/useKcMessage.js
yarn add markdown fixes the issue.
Hello,
I have build a Keycloak theme but when I try to launch the docker container I am facing the following issues (see below). Do you know how could I solve this problem? Thank you
09:31:08,790 ERROR [org.jboss.modcluster] (ServerService Thread Pool -- 60) MODCLUSTER000034: Failed to start advertise listener: java.net.SocketException: Protocol not available (Error setting socket option) at java.base/java.net.PlainDatagramSocketImpl.socketSetOption0(Native Method) at java.base/java.net.PlainDatagramSocketImpl.socketSetOption(PlainDatagramSocketImpl.java:91) at java.base/java.net.AbstractPlainDatagramSocketImpl.setOption(AbstractPlainDatagramSocketImpl.java:352) at java.base/java.net.MulticastSocket.setInterface(MulticastSocket.java:477) at [email protected]//org.jboss.modcluster.advertise.impl.AdvertiseListenerImpl.init(AdvertiseListenerImpl.java:151) at [email protected]//org.jboss.modcluster.advertise.impl.AdvertiseListenerImpl.start(AdvertiseListenerImpl.java:161) at [email protected]//org.jboss.modcluster.ModClusterService.init(ModClusterService.java:165) at [email protected]//org.wildfly.mod_cluster.undertow.UndertowEventHandlerAdapterService.start(UndertowEventHandlerAdapterService.java:83) at [email protected]//org.wildfly.clustering.service.AsyncServiceConfigurator$AsyncService.lambda$start$0(AsyncServiceConfigurator.java:117) at [email protected]//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) at [email protected]//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982) at [email protected]//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486) at [email protected]//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377) at java.base/java.lang.Thread.run(Thread.java:834) at [email protected]//org.jboss.threads.JBossThread.run(JBossThread.java:485)
Error: ENOENT: no such file or directory, scandir 'E:\keycloak_custom\my-app\build_keycloak\src\main\resources\theme\my-app\tmp_xxKdLpdIdLd\keycloak\login\resources'
at Object.readdirSync (node:fs:1390:3)
at crawlRec (E:\keycloak_custom\my-app\node_modules\keycloakify\bin\tools\crawl.js:41:39)
at crawl (E:\keycloak_custom\my-app\node_modules\keycloakify\bin\tools\crawl.js:61:9)
at transformCodebase (E:\keycloak_custom\my-app\node_modules\keycloakify\bin\tools\transformCodebase.js:48:50)
at generateKeycloakThemeResources (E:\keycloak_custom\my-app\node_modules\keycloakify\bin\build-keycloak-theme\generateKeycloakThemeResources.js:124:51)
at main (E:\keycloak_custom\my-app\node_modules\keycloakify\bin\build-keycloak-theme\build-keycloak-theme.js:57:73)
at Object.<anonymous> (E:\keycloak_custom\my-app\node_modules\keycloakify\bin\build-keycloak-theme\index.js:17:37)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32) {
errno: -4058,
syscall: 'scandir',
code: 'ENOENT',
path: 'E:\\keycloak_custom\\my-app\\build_keycloak\\src\\main\\resources\\theme\\my-app\\tmp_xxKdLpdIdLd\\keycloak\\login\\resources'
}
Hello! Love the project!
I'm new to Keycloak and Keycloakify, so apologies if this is a simple question.
I'm working on migrating an existing Keycloak theme to use Keycloakify. The existing theme is written using FTL.
The existing theme has variables in the FTL files like so;
<a name="Home" href="${primaryUrl}" title="${nameOfTitle}" data-ga-tracking-id="headerLogo">
My understanding is that these variables come from the theme.properties
file.
How can I access these variables on the React side?
Thanks
Thanks for your awesome library for Keycloak. Is this possible to get same or some common library for Vue.js as well?
Hello! I'm using your tool and it's currently in production and I have a major issue on iOS (15). As the title says, I'm getting this error here when I uses it on iOS: Invalid regular expression: invalid group specifier name
.
This only happens on iOS and only when I import something from keycloakify
. Any help would be appreciated.
Hi!
I need to build several themes for different realms. But with the same components.
(I use my KcApp and pages components). I really don't want to duplicate the react app because of this.
Could you add more customization options for the titles? For example:
package.json:
{
"other_props": "...",
"keycloakify": {
"themeName": "example",
"sourcePath": "build",
"buildPath": "build_keycloak2"
}
}
src/bin/build-keycloak-theme.ts:
const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json"));
const buildDirName: string = (parsedPackageJson as any)["keycloakify"]?.["buildPath"] ?? 'build_keycloak';
export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, buildDirName);
...
const reactDirName: string = (parsedPackageJson as any)["keycloakify"]?.["sourcePath"] ?? 'build';
const themeName = sanitizeThemeName((parsedPackageJson as any)["keycloakify"]?.["themeName"] ?? parsedPackageJson.name);
...
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, reactDirName),
Hi!
I managed to fix the template. You can look at the implementation here:
Errors with "The type of the containing value was: extended_hash+string"
<#attempt>
<#local value = object[key]!"error_data_is_undefined">
<#recover>
/* couldn't dereference ${key} of object */
<#continue>
</#attempt>
The freemarker documentation advises:
<#local value = object[key]!"">
But keycloakify app pages expect undefined.
And I followed a simple path. (So that these changes do not break other applications.)
JSON.parse(JSON.stringify(<@objectToJson_please_ignore_errors object=.data_model depth=0 arr=[] ftl="ftl_template_for_replacement" />), (key, value) => value === "error_data_is_undefined" ? undefined : value)
After that, 4 errors will remain in the console for the login.ftl page. Keys: loginUpdateTotpUrl, loginUsernameReminderUrl, loginUpdateProfileUrl, loginUpdatePasswordUrl from url object. And the template will work quickly.
"${key}": <@objectToJson_please_ignore_errors object=value depth=depth+1 arr=arr_keys ftl=ftl />
I'm doing the checks:
<#local arr_keys = []>
<#if depth==0 && key=="url" >
<#local arr_keys = ["loginAction", "resourcesPath", "resourcesCommonPath", "loginRestartFlowUrl", "loginUrl", "loginResetCredentialsUrl", "registrationUrl", "registrationAction", "oauth2DeviceVerificationAction", "oauthAction", "loginResetCredentialsUrl"]>
</#if>
One new error will appear in the login.tpl template related to the fieldNames enumeration.
This error can be fixed by adding additional checks:
<#assign attributes = (profile.attributes)![]>
<#attempt>
<#list attributes as attribute>
<#if (attribute.name)??>
<#assign fieldNames += [attribute.name]>
</#if>
</#list>
<#recover>
</#attempt>
Error in the login-reset-password.ftl template
Key: attemptedUsername from auth object. AttemptedUsername is used in login-reset-password.ftl template. If you try to get the value by the key of the attemptUsername in login-reset-password.ftp template (or in login.ftl template), it will not lead to an error. Therefore, ftlName parameter should appear in the conditions.
At the end of generateFtl.ts file:
objectKeys(ftlPlaceholders).forEach(
id => (ftlCode = ftlCode.replace(id, ftlPlaceholders[id]).replace("ftl_template_for_replacement", pageId)),
);
At the end of common.ftl file:
Object.deepAssign(
out,
//Removing all the undefined
JSON.parse(JSON.stringify(<@objectToJson_please_ignore_errors object=.data_model depth=0 arr=[] ftl="ftl_template_for_replacement" />), (key, value) => value === "error_data_is_undefined" ? undefined : value)
);
Before:
"${key}": <@objectToJson_please_ignore_errors object=value depth=depth+1 arr=arr_keys ftl=ftl />,
<#if depth==0 && key=="auth" && ftl=="login-reset-password.ftl" >
<#local arr_keys = ["showUsername", "showResetCredentials", "showTryAnotherWayLink", "attemptedUsername"]>
<#elseif depth==0 && key=="auth">
<#local arr_keys = ["showUsername", "showResetCredentials", "showTryAnotherWayLink"]>
</#if>
Error in the login-update-profile.ftl template
I'm not sure if this page worked before my changes. On my computer, when I tried to open this page for 10 minutes, errors appeared in the console. As a result, the page did not load. After my changes, it became clear that this page is broken. Because the download has become faster. There is an error in the browser window 500 (internal server error).
I got all the top-level keys from the .data_model
on login-update-profile page: msg, execution, updateProfileCtx, social, auth, requiredActionUrl, message, locale, authenticatorConfigured, login, url, advancedMsg, messagesPerField, client, realm, kcSanitize, scripts, user, properties.
First I excluded all the keys (before "${key}": <@objectToJson_please_ignore_errors...
).
<#if depth==0 && key=="url" ><#continue></#if>
<#if depth==0 && key=="auth" ><#continue></#if>
<#if depth==0 && key=="locale" ><#continue></#if>
<#if depth==0 && key=="realm" ><#continue></#if>
<#if depth==0 && key=="scripts" ><#continue></#if>
<#if depth==0 && key=="message" ><#continue></#if>
<#if depth==0 && key=="client" ><#continue></#if>
<#if depth==0 && key=="messagesPerField" ><#continue></#if>
<#if depth==0 && key=="user" ><#continue></#if>
<#if depth==0 && key=="requiredActionUrl" ><#continue></#if>
<#if depth==0 && key=="msg" ><#continue></#if>
<#if depth==0 && key=="execution" ><#continue></#if>
<#if depth==0 && key=="updateProfileCtx" ><#continue></#if>
<#if depth==0 && key=="social" ><#continue></#if>
<#if depth==0 && key=="authenticatorConfigured" ><#continue></#if>
<#if depth==0 && key=="login" ><#continue></#if>
<#if depth==0 && key=="advancedMsg" ><#continue></#if>
<#if depth==0 && key=="kcSanitize" ><#continue></#if>
<#if depth==0 && key=="properties" ><#continue></#if>
I found a problem in updateProfileCtx key. Since frontend does not use this object, I have excluded it altogether.
<#if depth==0 && key=="updateProfileCtx" ><#continue></#if>
This object has the following keys: lastName, getClass, setSingleAttribute, getUserProfileContext, getFirstAttribute, getAttributeStream, getUsername, setLastName, setAttribute, hashCode, class, email, isEditUsernameAllowed, getAttributes, setUsername, getLastName, firstName, editUsernameAllowed, setEmail, setFirstName, equals, getEmail, attributes, toString, getFirstName, userProfileContext, username.
The real problem is one or more of them.
Error in the saml-post-form.ftl template (optional)
At the moment there are two additional templates in my fork: saml-post-form.ftl, login-config-totp.ftl.
loginAction
key of url object creates an error. That's why I excluded him:
<#if depth==0 && key=="url" && ftl=="saml-post-form.ftl" >
<#local arr_keys = ["resourcesPath", "resourcesCommonPath", "loginRestartFlowUrl", "loginUrl", "loginResetCredentialsUrl", "registrationUrl", "registrationAction", "oauth2DeviceVerificationAction", "oauthAction", "loginResetCredentialsUrl"]>
<#elseif depth==0 && key=="url">
<#local arr_keys = ["loginAction", "resourcesPath", "resourcesCommonPath", "loginRestartFlowUrl", "loginUrl", "loginResetCredentialsUrl", "registrationUrl", "registrationAction", "oauth2DeviceVerificationAction", "oauthAction", "loginResetCredentialsUrl"]>
</#if>
At this stage, all errors in the templates have been fixed.
Hope you don't mind the question, I wasn't sure where else to ask it.
As part of the "build" process, you are attaching variables on to a global object called kcContext
(window.kcContext
).
This is fine and works great.
As part of my task I have to migrate not only the login related pages, but also account pages as well. For example, I have an account page that allows the user to change their email address. Here is the code that links the user to that page;
<@inputs.input id="username" name="username" type="text" value="${(account.email!'')}" class="input_withOption" disabled="true" labelText="Email address" hasOption="true">
<@buttons.link href="${email.emailPage}" class="inputOption inputOption__link" importance="tertiary" gaId="updateLoginDetails_changeEmailButton">Change</@buttons.link>
</@inputs.input>
We display the email address and provide a "Change" link. We pre-populate the email address field with the email they used for their account.
The account
object is provided I believe from Keycloak. Currently it is not exposed by Keycloakify, even though I assume it is available.
So I was looking at this code;
<script>
Object.deepAssign(
window.kcContext,
{ "pageId": "login-reset-password.ftl" }
);
Object.deepAssign(
window.kcContext,
{
"realm": {
"loginWithEmailAllowed": (function (){
<#attempt>
return ${realm.loginWithEmailAllowed?c};
<#recover>
</#attempt>
})()
}
}
);
</script>
Specifically this;
<#attempt>
return ${realm.loginWithEmailAllowed?c};
<#recover>
</#attempt>
This is compiled by keycloakfiy.
Is there any way I can easily extend the build process so that I can output my own variables?
Thank you for this life saving project!
How can we customize the otp one time code page?
Regards
Hello,
There are no implementations for some pages, such as login-update-password.ftl
I think it'd be better if we can inject our implementations dynamically, for example:
switch (kcContext.pageId) {
...
case 'login-update-password.ftl':
return <LoginUpdatePassword {...{ kcContext, ...kcProps }} />;
...
}
=> the library would build the login-update-password.ftl
file
I would like to add translation files to the theme.
Keycloak documentation on internationalization states that in order to support a custom language two steps are neccessary:
messages*
file inside the theme foldertheme.properties
by adding the locales= ...
entryI was investigating if translations are already supported. AFAIK the build theme script generateKeycloakThemeResources.js
only copies the resources
folder to the theme
folder. The messages
folder is not mentioned in the script.
To be clear what I was looking for: Keycloak expects the messages
folder next to the resources
folder.
META-INF/keycloak-themes.json
theme/mytheme/login/theme.properties
theme/mytheme/login/login.ftl
theme/mytheme/login/resources/css/styles.css
theme/mytheme/login/resources/img/image.png
theme/mytheme/login/messages/messages_en.properties
theme/mytheme/email/messages/messages_en.properties
Maybe I am missing something here, so any help regarding adding translation files would be much appreciated.
A workaround would be to add the messages
folder to the theme by updating a jar
package once it is compiled, but that is not a permanent solution.
I think this pull-request solves it: #18
Hi, first of all thank you for this amazing project. I agree with all your motivations :).
Which branch is the right one for me to start ?
"look_and_feel" branch ?
demo branch ?
I started with the "look_and_feel" following "advanced usage" following this guide.
Replaces those lines by const kcContext = realKcContext ?? kcContextMocks.kcLoginContext;, now if you run yarn start you will be able to debug the login page, replace kcLoginContext by kcRegisterContext and the register page will be loaded instead.
This point doesnt apply for the code of the "look_and_feel" branch though.
You see my confusion ? Otherwise let me know and I can try to explain it in other way :)
Thank you!
image in page is load fail
Dear @garronej
many thanks for the great project. We started using it for our project.
Can you please help us with the local fonts?
We can not load them from GoogleFonts or remote and they shall be there as local fonts.
I tried all your workarounds and it just didnt work. Can you please provide us guidance, which steps we have to do, to build the project and include in docker image with our local fonts? The KC docker image keeps ignoring them.
This would be so great. The links at workaround are not working anymore.
Many thanks!
Hello, i made a fully custom theme using others deps as 'styled-components' and 'react-intl', everything is working well except the register and login verify email where both of those pages throw me the same error:
FTL stack trace ("~" means nesting-related):
- Failed at: #local value = object[key] [in template "login-verify-email.ftl" in macro "objectToJson" at line 70, column 21]
this is the code at line 70:
<#attempt>
<#local value = object[key]>
<#recover>
/* couldn't dereference ${key} of object */
<#continue>
</#attempt>
Do you have any ideas of what is going on with this issue, the user cannot register and verify its email (he can only log in) ?
Thanks
Hi. Thank you for this nice library. I'm a Keycloak and react developer since a while and I was very excited to discover this library. So I'm about to convert my themes using this library. Now I have this error stopping me from going further.
I obtain this error when I try to run the dev server after adding my own config, based on this config.
./node_modules/keycloakify/src/lib/components/Template.tsx 3:12
Module parse failed: Unexpected token (3:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|
| import { useReducer, useEffect, memo } from "react";
> import type { ReactNode } from "react";
| import { useKcMessage } from "../i18n/useKcMessage";
| import { useKcLanguageTag } from "../i18n/useKcLanguageTag";
I've added these libraries because I need material inside my design:
...
"@fontsource/roboto": "^4.4.5",
"@material-ui/core": "^4.12.0",
...
This is my kcContext
:
import {getKcContext} from "keycloakify";
declare type RegisterType = {
pageId: "register.ftl";
phoneNumber: string;
}
declare type PhoneTanType = {
pageId: "request-sms-tan.ftl";
phoneNumber: string;
}
export const {kcContext} = getKcContext<RegisterType | PhoneTanType>({
"mockPageId": "request-sms-tan.ftl",
"mockData": [
{
"pageId": "request-sms-tan.ftl",
"phoneNumber": "+234567890987"
},
]
});
export type KcContext = NonNullable<typeof kcContext>;
Now when I use a pure js project, I don't have this error. After some researches, Webpack is the problem, not knowing how to load "import type" (obviously π).
Does someone have an Idea how to deal with such a situation?
Hi,
We are upgrading from keycloak 11 to 15 and noticed that the register page was customized anymore.
From my limited keycloak understanding, it seems there is a new register-user-profile.ftl
page. See https://github.com/keycloak/keycloak/blob/master/themes/src/main/resources/theme/base/login/register-user-profile.ftl
Could it be related ?
Of what I understand this isn't supported yet? Would it be enough to follow this or would other steps/methods be required?
First of all thanks a lot for creating this package, it might just be a lifesaver for people like us.
I am trying to make use of keycloakify with custom Material UI login screen.
From the source code, I can see that in the example template, you have created your own login page
I see in this login page you are making use of kcContext
, which help maintain the values state.
Is there any documentation on how to use kcContext
for any custom implementation. If not can you guide me in the right direction and I will more than happy make it possible.
Appreciate your help.
Is there a way to make this work also on windows?
Hi,
I am using keycloakify in a very basic way. Just copied Register.tsx from the library itself and pasted in my code and I am getting this error:
12:37:18,101 ERROR [freemarker.runtime] (default task-6) Error executing FreeMarker template part in the #attempt block: freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
[keycloak] ==> object[key] [in template "register.ftl" at line 70, column 37]
[keycloak]
Could you please help, why it is coming?
TIA
When building in a project that has spaces in the file path, keycloakify tries to build "seperate" projects.
This is uncommon on Linux but we're using WSL and referencing a host path with a space in it's path.
Thanks!
Hello guys
Can you please share the knowledge on why the generateFtl function exists and replicates the common.ftl across many templates?
When i run the yarn start
then i got the following error
Compiled with problems:X
ERROR in ./node_modules/keycloakify/lib/components/LoginOtp.js 43:13-28
Module not found: Error: Can't resolve 'path' in '/home/kousher/Projects/edge-commerce/keycloak-bookstore/node_modules/keycloakify/lib/components'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
ERROR in ./node_modules/keycloakify/lib/components/Template.js 75:13-28
Module not found: Error: Can't resolve 'path' in '/home/kousher/Projects/edge-commerce/keycloak-bookstore/node_modules/keycloakify/lib/components'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
ERROR in ./node_modules/keycloakify/lib/getKcContext/kcContextMocks/kcContextMocks.js 70:13-28
Module not found: Error: Can't resolve 'path' in '/home/kousher/Projects/edge-commerce/keycloak-bookstore/node_modules/keycloakify/lib/getKcContext/kcContextMocks'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
ERROR in ./node_modules/keycloakify/lib/getKcContext/kcContextMocks/urlResourcesPath.js 8:13-28
Module not found: Error: Can't resolve 'path' in '/home/kousher/Projects/edge-commerce/keycloak-bookstore/node_modules/keycloakify/lib/getKcContext/kcContextMocks'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
OS: Ubuntu 20.04.3 LTS 64 Bit
I tried to add required actions to the info.ftl mock but it throws an error when I try to get the mocked context as shown in the image below. Have I made a mistake or does the feature not work exactly as intended?
The field is supposed to be undefined and according to the code in deepassign it should just use the new provided property.
"mockData": [
{
"pageId": "info.ftl",
requiredActions : [
"CONFIGURE_TOTP",
"UPDATE_PASSWORD",
"UPDATE_PROFILE",
"VERIFY_EMAIL",
"terms_and_conditions"
]
}
]
keycloakify 2.0.10
Node 14.17.3
I created a new project via create-react-app
. index.tsx
looks like this:
import ReactDOM from "react-dom";
import "./index.css";
import reportWebVitals from "./reportWebVitals";
import { KcApp, defaultKcProps, getKcContext } from "keycloakify";
import { css } from "tss-react";
const { kcContext } = getKcContext();
const myClassName = css({ color: "red" });
ReactDOM.render(
<KcApp
kcContext={kcContext!}
{...{
...defaultKcProps,
kcHeaderWrapperClass: myClassName,
}}
/>
,
document.getElementById("root")
);
reportWebVitals();
When I'm trying to run yarn build && build-keycloak-theme
I'm getting this:
Downgraded versions of Node
or keycloakify
makes no difference.
I also tried the demo-app and still got the same error.
Any ideas?
Thanks π
I ran into an undefined error which was preventing my login page from rendering due to having this on my realm:
HTML Display name: <div class="kc-logo-text"><span>Keycloak</span></div>
Removing that value fixes the issue so there is a workaround. Based on the output, the "
appear to be causing the issue. I'm not sure why I used that setting in the past (may be default?) but I imagine this library would render it obsolete.
The full rendered snippet is here: https://pastebin.com/kdNU2vY8
I have install maven on our company's self hosted runner and verified from workflow the mvn -version
is showing that maven is installed.
still when I run the build-keycloak-theme
it gives me error
/bin/sh: mvn: command not found
node:child_process:903
throw err;
^
Error: Command failed: mvn package
/bin/sh: mvn: command not found
at checkExecSyncError (node:child_process:826:11)
at Object.execSync (node:child_process:900:15)
any idea how I can resolve this issue ?
Hello, during the conversion of my themes from Keycloak Freemarker to keycloakify, I came across this problem. Actually, there's no equivalent to advancedMsg
when using this library, or I didn't found any.
<#if client.name?has_content>
${msg("oauthGrantTitle",advancedMsg(client.name))}
<#else>
${msg("oauthGrantTitle",client.clientId)}
</#if>
This is what I've tried:
client.name ? msgStr('oauthGrantTitle', msgStr(client.name)) : msg("oauthGrantTitle", client.clientId
but without surprise, I'm getting an error:
Do you have an idea how I can do it right ?
Errors coming in the Keycloak logs.
Tried my best to figure it out, but don't have the FTL knowledge.
This object[key]
part in the FTL common.ftl is generating errors everywhere :(
Keycloak version 15.0.2
18:32:33,252 ERROR [freemarker.runtime] (default task-11) Error executing FreeMarker template part in the #attempt block: freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> object[key] [in template "login.ftl" at line 70, column 37]
----
FTL stack trace ("~" means nesting-related):
- Failed at: #local value = object[key] [in template "login.ftl" in macro "objectToJson" at line 70, column 21]
- Reached through: @compress [in template "login.ftl" in macro "objectToJson" at line 36, column 5]
- Reached through: @objectToJson object=value depth=(dep... [in template "login.ftl" in macro "objectToJson" at line 81, column 27]
- Reached through: @compress [in template "login.ftl" in macro "objectToJson" at line 36, column 5]
- Reached through: @objectToJson object=(.data_model) de... [in template "login.ftl" at line 230, column 35]
----
Hello,
I'm glad that you introduced messagesPerField.exists
and messagesPerField.get
in the new keycloakify v2.4.0 !
Though, I'm unable to use it.
Looking at the code, it seems that if I have no profile.attributes
in my configuration. I don't know if that's necessary as I would like to use it on classic fields such as userLabel
, username
, email
, firstName
, lastName
, password
and password-confirm
.
I'm not sure if this is a bug or whether it is intended.
I would be happy if you could update the lib for it to iterate on those values at least.
Cheers!
Hi. :)
Is there any way to redirect origin page after login?
My application stays on the login page after successful login.
I tried 2 different ways to login.
const handleLogin = async () => {
await api.login({url: url.loginAction, userName: userName, password: password, });
// go back to home page!
};
<form
method="post"
action={url.loginAction}
>
...
</form>
Hi,
Here are the things important to note:
The components are imported to Keycloackify successfully, but when it comes to the css variables that are required for it is own styling, then it gets ignored.
So we ended up with components without styling.
Two example of imports:
Component import:
import Button from '@components/button';
Styles and themes import:
import '@components/theme/src/theme.scss';
Example of the theme file that is been imported:
@import 'variables.scss'; // should be included only here not in a WES, SES, COS !!!
// utility function to convert a hex color like #ffffff to it's r,g,b elements.
@function cssrgb($hex) {
@return red($hex), green($hex), blue($hex);
}
/**
defines a css variable with the provided $name with $hex as value
and additionally converts the $hex to it's r,g,b elements and defines a $name-rgb variable
Example
@include defineCssColorVariable(--my-var, #ffffff)
Result:
--my-var: #ffffff;
the -rgb variable can then be used as input for the css `rgba` function
Example:
rgba(var(--my-var-rgb), 0.5)
would be interpreted as `rgba(255, 255, 255, 0.5)`
*/
@mixin defineCssColorVariable($name, $hex) {
#{$name}: #{$hex};
#{$name}-rgb: #{cssrgb($hex)};
}
:global {
:root {
--white: #ffffff;
// title text H1, H2, dark background
@include defineCssColorVariable(--grey-10, #33445c);
// info
--background-info: var(--blue-light);
// success
--background-success: var(--green-light);
// warning
--background-warning: var(--yellow-light);
// borders
--border-color: var(--grey-40);
// font-size
--font-xl: 19px;
// base font parameters
--font-size-base: var(--font-m);
// icons
--menu-icon-color: var(--grey-35);
// animations
--ease-in: cubic-bezier(0.4, 0, 0.2, 1);
}
}
Is there a way to make Keycloakify responsive to our imported components stylings?
Hey, I want to add "Sign Up with {social display name}" buttons in my register page, but apparently it's not possible to access the social
variable outside the login page.
After checking the code, I guess it's because it's missing this part in the generateFtl/register.ftl
file:
"social": { ... },
Is there already a workaround for this?
If not, one idea I have, is to build the generateFtl files programmatically, where we define the variables based on the config or the default value. For example (The code is just so the idea can be better understood) :
//foo/variables
export const url = `{
"loginResetCredentialsUrl": (function (){
<#attempt>
return "${url.loginResetCredentialsUrl?no_esc}";
<#recover>
</#attempt>
})(),
"registrationUrl": (function (){
<#attempt>
return "${url.registrationUrl?no_esc}";
<#recover>
</#attempt>
})()
}`
export const realm = `{
"loginWithEmailAllowed": (function(){
<#attempt>
return ${realm.loginWithEmailAllowed?c};
<#recover>
</#attempt>
})(),
"rememberMe": (function (){
<#attempt>
return ${realm.rememberMe?c};
<#recover>
</#attempt>
})(),
"password": (function (){
<#attempt>
return ${realm.password?c};
<#recover>
</#attempt>
})(),
"resetPasswordAllowed": (function (){
<#attempt>
return ${realm.resetPasswordAllowed?c};
<#recover>
</#attempt>
})(),
"registrationAllowed": (function (){
<#attempt>
return ${realm.registrationAllowed?c};
<#recover>
</#attempt>
})()
}`
// ...
import * as variables from 'foo/variables'
import * as config from 'foo/config'
const defaultVariables = {
login: ["url", "realm", ...],
...
}
const generateFile = (name: string) => {
const fileVariables = config.variables?.[name] || defaultVariables[name]
const entries = fileVariables.map(variable => {
return [variable, variables[variable]]
}
const file = `
<script>
const _= ${JSON.stringify(Object.fromEntries(entries))}
</script>
`
// write file
}
Then in a config file we could easily add or remove the variables we need
{
variables: {
register: ["url", "realm", ..., "social"]
}
}
I don't know much about how the lib works, so I hope this helps to find a way to solve this problem.
Hi. I got a type error during build.
βkeycloak_11.0.3_builtin_themes.zipβ saved but there is an error for callback.
...
11650K .......... .......... .......... .......... .......... 99% 3.26M 0s
11700K .......... .......... .......... .......... .......... 99% 4.71M 0s
11750K .......... .......... .......... .......... .......... 99% 2.75M 0s
11800K .......... ..... 100% 3.30M=3.6s
2021-09-29 14:37:02 (3.23 MB/s) - βkeycloak_11.0.3_builtin_themes.zipβ saved [12098580/12098580]
fs.js:177
throw new ERR_INVALID_CALLBACK(cb);
^
TypeError [ERR_INVALID_CALLBACK]: Callback must be a function. Received undefined
at makeCallback (fs.js:177:11)
at Object.mkdir (fs.js:978:14)
at Object.target.init (/home/cindy/.nvm/versions/node/v14.17.1/lib/node_modules/mvn/target.js:25:10)
at Object.<anonymous> (/home/cindy/.nvm/versions/node/v14.17.1/lib/node_modules/mvn/target.js:39:8)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:14)
at Module.require (internal/modules/cjs/loader.js:974:19)
at require (internal/modules/cjs/helpers.js:92:18) {
code: 'ERR_INVALID_CALLBACK'
}
child_process.js:682
throw err;
^
Error: Command failed: mvn package
fs.js:177
throw new ERR_INVALID_CALLBACK(cb);
^
TypeError [ERR_INVALID_CALLBACK]: Callback must be a function. Received undefined
at makeCallback (fs.js:177:11)
at Object.mkdir (fs.js:978:14)
at Object.target.init (/home/cindy/.nvm/versions/node/v14.17.1/lib/node_modules/mvn/target.js:25:10)
at Object.<anonymous> (/home/cindy/.nvm/versions/node/v14.17.1/lib/node_modules/mvn/target.js:39:8)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:14)
at Module.require (internal/modules/cjs/loader.js:974:19)
at require (internal/modules/cjs/helpers.js:92:18) {
code: 'ERR_INVALID_CALLBACK'
}
at checkExecSyncError (child_process.js:643:11)
at Object.execSync (child_process.js:679:15)
at main (/home/cindy/dev/ndc-ui/node_modules/keycloakify/bin/build-keycloak-theme/build-keycloak-theme.js:80:19)
at Object.<anonymous> (/home/cindy/dev/ndc-ui/node_modules/keycloakify/bin/build-keycloak-theme/index.js:17:37)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
at internal/main/run_main_module.js:17:47 {
status: 1,
signal: null,
output: [
null,
Buffer(0) [Uint8Array] [],
Buffer(840) [Uint8Array] [
102, 115, 46, 106, 115, 58, 49, 55, 55, 10, 32, 32,
32, 32, 116, 104, 114, 111, 119, 32, 110, 101, 119, 32,
69, 82, 82, 95, 73, 78, 86, 65, 76, 73, 68, 95,
67, 65, 76, 76, 66, 65, 67, 75, 40, 99, 98, 41,
59, 10, 32, 32, 32, 32, 94, 10, 10, 84, 121, 112,
101, 69, 114, 114, 111, 114, 32, 91, 69, 82, 82, 95,
73, 78, 86, 65, 76, 73, 68, 95, 67, 65, 76, 76,
66, 65, 67, 75, 93, 58, 32, 67, 97, 108, 108, 98,
97, 99, 107, 32,
... 740 more items
]
],
pid: 10978,
stdout: Buffer(0) [Uint8Array] [],
stderr: Buffer(840) [Uint8Array] [
102, 115, 46, 106, 115, 58, 49, 55, 55, 10, 32, 32,
32, 32, 116, 104, 114, 111, 119, 32, 110, 101, 119, 32,
69, 82, 82, 95, 73, 78, 86, 65, 76, 73, 68, 95,
67, 65, 76, 76, 66, 65, 67, 75, 40, 99, 98, 41,
59, 10, 32, 32, 32, 32, 94, 10, 10, 84, 121, 112,
101, 69, 114, 114, 111, 114, 32, 91, 69, 82, 82, 95,
73, 78, 86, 65, 76, 73, 68, 95, 67, 65, 76, 76,
66, 65, 67, 75, 93, 58, 32, 67, 97, 108, 108, 98,
97, 99, 107, 32,
... 740 more items
]
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] keycloak: `craco build && build-keycloak-theme`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] keycloak script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
May I know what am I missing?
Is there a problem with the configuration of the environment?
Just want to say I think this is an extremely cool project! It's cool to see how much energy you are putting into it.
I am curious to learn more about how the build system works, including what inputs are expected and how they might be structured. What dependencies (for instance, running the demo app, i had to install maven
and wget
on Mac), and what outputs, and intermediate outputs are generated.?
As far as I can tell, the build tool uses webpack to generate some modules, and then those modules are injected into the ftl templates? How is the window.kcContext
context populated?
Anyway, maybe i'm just that kind of person who needs to know how things work before moving forward, but it would also help with integrating with other build tools such as Bazel, and maybe would help in getting a little more traction :-)
Using Ubuntu 20
ares@ares:~/gitt/main/keycloakify-main$ sudo yarn keycloak
yarn run v1.22.10
$ yarn build && build-keycloak-theme
$ yarn clean && tsc && yarn grant-exec-perms && yarn copy-files
$ rimraf dist/
$ node dist/bin/tools/grant-exec-perms.js
$ copyfiles -u 1 src//*.ftl src//.xml src/**/.js dist/
π Building the keycloak theme...β
/home/ares/gitt/main/keycloakify-main/node_modules/keycloakify/bin/tools/transformCodebase.js:66
finally { if (e_1) throw e_1.error; }
^
Error: ENOENT: no such file or directory, scandir '/home/ares/gitt/main/keycloakify-main/build'
at Object.readdirSync (fs.js:790:3)
at crawlRec (/home/ares/gitt/main/keycloakify-main/node_modules/keycloakify/bin/tools/crawl.js:41:39)
at Object.crawl (/home/ares/gitt/main/keycloakify-main/node_modules/keycloakify/bin/tools/crawl.js:61:9)
at Object.transformCodebase (/home/ares/gitt/main/keycloakify-main/node_modules/keycloakify/bin/tools/transformCodebase.js:46:40)
at Object.generateKeycloakThemeResources (/home/ares/gitt/main/keycloakify-main/node_modules/keycloakify/bin/build-keycloak-theme/generateKeycloakThemeResources.js:69:25)
at Object.main (/home/ares/gitt/main/keycloakify-main/node_modules/keycloakify/bin/build-keycloak-theme/build-keycloak-theme.js:50:38)
at Object. (/home/ares/gitt/main/keycloakify-main/node_modules/keycloakify/bin/build-keycloak-theme/index.js:17:28)
at Module._compile (internal/modules/cjs/loader.js:778:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
From reading this issue #5 it sounds like this project is pretty tied to create-react-app. Unfortunately for me the app I'm working on is using (normally ssr'd) next.js. I'm no next.js pro yet so I'll have to think about how to make this work a bit. Do you have any ideas?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.