diff --git a/src/bin/keycloakify/generateFtl/pageId.ts b/src/bin/keycloakify/generateFtl/pageId.ts index fc93e917..da3525f6 100644 --- a/src/bin/keycloakify/generateFtl/pageId.ts +++ b/src/bin/keycloakify/generateFtl/pageId.ts @@ -10,6 +10,8 @@ export const loginThemePageIds = [ "login-reset-password.ftl", "login-verify-email.ftl", "terms.ftl", + "login-oauth2-device-verify-user-code.ftl", + "login-oauth-grant.ftl", "login-otp.ftl", "login-update-profile.ftl", "login-update-password.ftl", diff --git a/src/login/Fallback.tsx b/src/login/Fallback.tsx index bffb3a78..80d5c12b 100644 --- a/src/login/Fallback.tsx +++ b/src/login/Fallback.tsx @@ -12,6 +12,8 @@ const Error = lazy(() => import("keycloakify/login/pages/Error")); const LoginResetPassword = lazy(() => import("keycloakify/login/pages/LoginResetPassword")); const LoginVerifyEmail = lazy(() => import("keycloakify/login/pages/LoginVerifyEmail")); const Terms = lazy(() => import("keycloakify/login/pages/Terms")); +const LoginDeviceVerifyUserCode = lazy(() => import("keycloakify/login/pages/LoginDeviceVerifyUserCode")); +const LoginOauthGrant = lazy(() => import("keycloakify/login/pages/LoginOauthGrant")); const LoginOtp = lazy(() => import("keycloakify/login/pages/LoginOtp")); const LoginPassword = lazy(() => import("keycloakify/login/pages/LoginPassword")); const LoginUsername = lazy(() => import("keycloakify/login/pages/LoginUsername")); @@ -52,6 +54,10 @@ export default function Fallback(props: PageProps) { return ; case "terms.ftl": return ; + case "login-oauth2-device-verify-user-code.ftl": + return ; + case "login-oauth-grant.ftl": + return ; case "login-otp.ftl": return ; case "login-username.ftl": diff --git a/src/login/TemplateProps.ts b/src/login/TemplateProps.ts index 1e50c4a0..22e8cadd 100644 --- a/src/login/TemplateProps.ts +++ b/src/login/TemplateProps.ts @@ -94,4 +94,5 @@ export type ClassKey = | "kcSelectOTPListItemClass" | "kcAuthenticatorOtpCircleClass" | "kcSelectOTPItemHeadingClass" - | "kcFormOptionsWrapperClass"; + | "kcFormOptionsWrapperClass" + | "kcFormButtonsWrapperClass"; diff --git a/src/login/kcContext/KcContext.ts b/src/login/kcContext/KcContext.ts index b7164e58..9b61648d 100644 --- a/src/login/kcContext/KcContext.ts +++ b/src/login/kcContext/KcContext.ts @@ -18,6 +18,8 @@ export type KcContext = | KcContext.LoginResetPassword | KcContext.LoginVerifyEmail | KcContext.Terms + | KcContext.LoginDeviceVerifyUserCode + | KcContext.LoginOauthGrant | KcContext.LoginOtp | KcContext.LoginUsername | KcContext.WebauthnAuthenticate @@ -241,6 +243,27 @@ export declare namespace KcContext { pageId: "terms.ftl"; }; + export type LoginDeviceVerifyUserCode = Common & { + pageId: "login-oauth2-device-verify-user-code.ftl"; + url: { + oauth2DeviceVerificationAction: string; + }; + }; + + export type LoginOauthGrant = Common & { + pageId: "login-oauth-grant.ftl"; + oauth: { + code: string; + client: string; + clientScopesRequested: { + consentScreenText: string; + }[]; + }; + url: { + oauthAction: string; + }; + }; + export type LoginOtp = Common & { pageId: "login-otp.ftl"; otpLogin: { diff --git a/src/login/kcContext/kcContextMocks.ts b/src/login/kcContext/kcContextMocks.ts index 9f054fcc..2ed52faf 100644 --- a/src/login/kcContext/kcContextMocks.ts +++ b/src/login/kcContext/kcContextMocks.ts @@ -240,7 +240,9 @@ export const kcContextCommonMock: KcContext.Common = { const loginUrl = { ...kcContextCommonMock.url, "loginResetCredentialsUrl": "/auth/realms/myrealm/login-actions/reset-credentials?client_id=account&tab_id=HoAx28ja4xg", - "registrationUrl": "/auth/realms/myrealm/login-actions/registration?client_id=account&tab_id=HoAx28ja4xg" + "registrationUrl": "/auth/realms/myrealm/login-actions/registration?client_id=account&tab_id=HoAx28ja4xg", + "oauth2DeviceVerificationAction": "/auth/realms/myrealm/device", + "oauthAction": "/auth/realms/myrealm/login-actions/consent?client_id=account&tab_id=HoAx28ja4xg" }; export const kcContextMocks = [ @@ -344,6 +346,25 @@ export const kcContextMocks = [ ...kcContextCommonMock, "pageId": "terms.ftl" }), + id({ + ...kcContextCommonMock, + "pageId": "login-oauth2-device-verify-user-code.ftl", + url: loginUrl + }), + id({ + ...kcContextCommonMock, + "pageId": "login-oauth-grant.ftl", + oauth: { + code: "5-1N4CIzfi1aprIQjmylI-9e3spLCWW9i5d-GDcs-Sw", + clientScopesRequested: [ + { consentScreenText: "${profileScopeConsentText}" }, + { consentScreenText: "${rolesScopeConsentText}" }, + { consentScreenText: "${emailScopeConsentText}" } + ], + client: "account" + }, + url: loginUrl + }), id({ ...kcContextCommonMock, "pageId": "login-otp.ftl", diff --git a/src/login/lib/useGetClassName.ts b/src/login/lib/useGetClassName.ts index d81a2c0d..28a71def 100644 --- a/src/login/lib/useGetClassName.ts +++ b/src/login/lib/useGetClassName.ts @@ -45,6 +45,7 @@ export const { useGetClassName } = createUseClassName({ "kcInputClass": "form-control", "kcInputErrorMessageClass": "pf-c-form__helper-text pf-m-error required kc-feedback-text", "kcInputWrapperClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12", + "kcFormButtonsWrapperClass": undefined, "kcFormOptionsClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12", "kcFormButtonsClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12", "kcFormSettingClass": "login-pf-settings", diff --git a/src/login/pages/LoginDeviceVerifyUserCode.tsx b/src/login/pages/LoginDeviceVerifyUserCode.tsx new file mode 100644 index 00000000..4c1a6cab --- /dev/null +++ b/src/login/pages/LoginDeviceVerifyUserCode.tsx @@ -0,0 +1,68 @@ +import { clsx } from "keycloakify/tools/clsx"; +import Template from "../Template"; +import { I18n } from "../i18n"; +import { KcContext } from "../kcContext"; +import { useGetClassName } from "../lib/useGetClassName"; +import { PageProps } from "./PageProps"; + +export default function LoginOauthGrant(props: PageProps, I18n>) { + const { kcContext, i18n, doUseDefaultCss, classes } = props; + const { url } = kcContext; + + const { msg, msgStr } = i18n; + + const { getClassName } = useGetClassName({ + doUseDefaultCss, + classes + }); + + return ( + + ); +} diff --git a/src/login/pages/LoginOauthGrant.tsx b/src/login/pages/LoginOauthGrant.tsx new file mode 100644 index 00000000..cad91da1 --- /dev/null +++ b/src/login/pages/LoginOauthGrant.tsx @@ -0,0 +1,73 @@ +import { clsx } from "keycloakify/tools/clsx"; +import { PageProps } from "./PageProps"; +import { KcContext } from "../kcContext"; +import { I18n } from "../i18n"; +import Template from "../Template"; +import { useGetClassName } from "keycloakify/login/lib/useGetClassName"; + +export default function LoginOauthGrant(props: PageProps, I18n>) { + const { kcContext, i18n, doUseDefaultCss, classes } = props; + const { url, oauth, client } = kcContext; + + const { msg, msgStr, advancedMsg, advancedMsgStr } = i18n; + + const { getClassName } = useGetClassName({ + doUseDefaultCss, + classes + }); + + return ( + + ); +}