diff --git a/apps/login/locales/de.json b/apps/login/locales/de.json index f01d3d8f10..87518d74a5 100644 --- a/apps/login/locales/de.json +++ b/apps/login/locales/de.json @@ -166,7 +166,11 @@ "signedin": { "title": "Willkommen {user}!", "description": "Sie sind angemeldet.", - "continue": "Weiter" + "continue": "Weiter", + "error": { + "title": "Fehler", + "description": "Ein Fehler ist aufgetreten." + } }, "verify": { "userIdMissing": "Keine Benutzer-ID angegeben!", diff --git a/apps/login/locales/en.json b/apps/login/locales/en.json index 49f1fb99da..e32d736e70 100644 --- a/apps/login/locales/en.json +++ b/apps/login/locales/en.json @@ -166,7 +166,11 @@ "signedin": { "title": "Welcome {user}!", "description": "You are signed in.", - "continue": "Continue" + "continue": "Continue", + "error": { + "title": "Error", + "description": "An error occurred while trying to sign in." + } }, "verify": { "userIdMissing": "No userId provided!", diff --git a/apps/login/locales/es.json b/apps/login/locales/es.json index 8ec58e2b55..ff2fd9a4cb 100644 --- a/apps/login/locales/es.json +++ b/apps/login/locales/es.json @@ -166,7 +166,11 @@ "signedin": { "title": "¡Bienvenido {user}!", "description": "Has iniciado sesión.", - "continue": "Continuar" + "continue": "Continuar", + "error": { + "title": "Error", + "description": "Ocurrió un error al iniciar sesión." + } }, "verify": { "userIdMissing": "¡No se proporcionó userId!", diff --git a/apps/login/locales/it.json b/apps/login/locales/it.json index c59aeda2ab..792568872d 100644 --- a/apps/login/locales/it.json +++ b/apps/login/locales/it.json @@ -166,7 +166,11 @@ "signedin": { "title": "Benvenuto {user}!", "description": "Sei connesso.", - "continue": "Continua" + "continue": "Continua", + "error": { + "title": "Errore", + "description": "Si è verificato un errore durante il tentativo di accesso." + } }, "verify": { "userIdMissing": "Nessun userId fornito!", diff --git a/apps/login/locales/pl.json b/apps/login/locales/pl.json index 132c06f10f..18326df262 100644 --- a/apps/login/locales/pl.json +++ b/apps/login/locales/pl.json @@ -166,7 +166,11 @@ "signedin": { "title": "Witaj {user}!", "description": "Jesteś zalogowany.", - "continue": "Kontynuuj" + "continue": "Kontynuuj", + "error": { + "title": "Błąd", + "description": "Nie można załadować danych. Sprawdź połączenie z internetem lub spróbuj ponownie później." + } }, "verify": { "userIdMissing": "Nie podano identyfikatora użytkownika!", diff --git a/apps/login/locales/ru.json b/apps/login/locales/ru.json index 9a3ecd7cdd..9eda1730e6 100644 --- a/apps/login/locales/ru.json +++ b/apps/login/locales/ru.json @@ -166,7 +166,11 @@ "signedin": { "title": "Добро пожаловать, {user}!", "description": "Вы вошли в систему.", - "continue": "Продолжить" + "continue": "Продолжить", + "error": { + "title": "Ошибка", + "description": "Не удалось войти в систему. Проверьте свои данные и попробуйте снова." + } }, "verify": { "userIdMissing": "Не указан userId!", diff --git a/apps/login/locales/zh.json b/apps/login/locales/zh.json index d0fdd44d16..8a6200bf33 100644 --- a/apps/login/locales/zh.json +++ b/apps/login/locales/zh.json @@ -166,7 +166,11 @@ "signedin": { "title": "欢迎 {user}!", "description": "您已登录。", - "continue": "继续" + "continue": "继续", + "error": { + "title": "错误", + "description": "登录时发生错误。" + } }, "verify": { "userIdMissing": "未提供用户 ID!", diff --git a/apps/login/src/app/(login)/signedin/page.tsx b/apps/login/src/app/(login)/signedin/page.tsx index 09c96b56d4..0150a57f84 100644 --- a/apps/login/src/app/(login)/signedin/page.tsx +++ b/apps/login/src/app/(login)/signedin/page.tsx @@ -2,7 +2,11 @@ import { Alert, AlertType } from "@/components/alert"; import { Button, ButtonVariants } from "@/components/button"; import { DynamicTheme } from "@/components/dynamic-theme"; import { UserAvatar } from "@/components/user-avatar"; -import { getSessionCookieById } from "@/lib/cookies"; +import { + getMostRecentCookieWithLoginname, + getSessionCookieById, +} from "@/lib/cookies"; +import { completeDeviceAuthorization } from "@/lib/server/device"; import { getServiceUrlFromHeaders } from "@/lib/service"; import { loadMostRecentSession } from "@/lib/session"; import { @@ -41,6 +45,36 @@ export default async function Page(props: { searchParams: Promise }) { const { loginName, requestId, organization, sessionId } = searchParams; + const branding = await getBrandingSettings({ + serviceUrl, + organization, + }); + + // complete device authorization flow if device requestId is present + if (requestId && requestId.startsWith("device_")) { + const cookie = sessionId + ? await getSessionCookieById({ sessionId, organization }) + : await getMostRecentCookieWithLoginname({ + loginName: loginName, + organization: organization, + }); + + await completeDeviceAuthorization(requestId.replace("device_", ""), { + sessionId: cookie.id, + sessionToken: cookie.token, + }).catch((err) => { + return ( + +
+

{t("error.title")}

+

{t("error.description")}

+ {err.message} +
+
+ ); + }); + } + const sessionFactors = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) : await loadMostRecentSession({ @@ -48,11 +82,6 @@ export default async function Page(props: { searchParams: Promise }) { sessionParams: { loginName, organization }, }); - const branding = await getBrandingSettings({ - serviceUrl, - organization, - }); - let loginSettings; if (!requestId) { loginSettings = await getLoginSettings({ @@ -69,6 +98,13 @@ export default async function Page(props: { searchParams: Promise }) {

{t("description")}

+ + {requestId && requestId.startsWith("device_") && ( You can now close this window and return to the device where you @@ -76,13 +112,6 @@ export default async function Page(props: { searchParams: Promise }) { )} - - {/* {sessionFactors?.id && ( )} */} diff --git a/apps/login/src/components/consent.tsx b/apps/login/src/components/consent.tsx index 755087c9e9..6ae3cade45 100644 --- a/apps/login/src/components/consent.tsx +++ b/apps/login/src/components/consent.tsx @@ -1,6 +1,6 @@ "use client"; -import { denyDeviceAuthorization } from "@/lib/server/oidc"; +import { completeDeviceAuthorization } from "@/lib/server/device"; import { useTranslations } from "next-intl"; import Link from "next/link"; import { useRouter } from "next/navigation"; @@ -27,7 +27,9 @@ export function ConsentScreen({ async function denyDeviceAuth() { setLoading(true); - const response = await denyDeviceAuthorization(deviceAuthorizationRequestId) + const response = await completeDeviceAuthorization( + deviceAuthorizationRequestId, + ) .catch(() => { setError("Could not register user"); return; diff --git a/apps/login/src/components/device-code-form.tsx b/apps/login/src/components/device-code-form.tsx index faa77c3cdd..e09adb1147 100644 --- a/apps/login/src/components/device-code-form.tsx +++ b/apps/login/src/components/device-code-form.tsx @@ -36,7 +36,7 @@ export function DeviceCodeForm({ userCode }: { userCode?: string }) { const response = await getDeviceAuthorizationRequest(value.userCode) .catch(() => { - setError("Could not complete the request"); + setError("Could not continue the request"); return; }) .finally(() => { @@ -44,7 +44,7 @@ export function DeviceCodeForm({ userCode }: { userCode?: string }) { }); if (!response || !response.deviceAuthorizationRequest?.id) { - setError("Could not complete the request"); + setError("Could not continue the request"); return; } diff --git a/apps/login/src/lib/server/device.ts b/apps/login/src/lib/server/device.ts new file mode 100644 index 0000000000..d96059f6a6 --- /dev/null +++ b/apps/login/src/lib/server/device.ts @@ -0,0 +1,20 @@ +"use server"; + +import { authorizeOrDenyDeviceAuthorization } from "@/lib/zitadel"; +import { headers } from "next/headers"; +import { getServiceUrlFromHeaders } from "../service"; + +export async function completeDeviceAuthorization( + deviceAuthorizationId: string, + session?: { sessionId: string; sessionToken: string }, +) { + const _headers = await headers(); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); + + // without the session, device auth request is denied + return authorizeOrDenyDeviceAuthorization({ + serviceUrl, + deviceAuthorizationId, + session, + }); +} diff --git a/apps/login/src/lib/server/oidc.ts b/apps/login/src/lib/server/oidc.ts index 3bd0e53df4..4ae01b4a47 100644 --- a/apps/login/src/lib/server/oidc.ts +++ b/apps/login/src/lib/server/oidc.ts @@ -1,9 +1,6 @@ "use server"; -import { - authorizeOrDenyDeviceAuthorization, - getDeviceAuthorizationRequest as zitadelGetDeviceAuthorizationRequest, -} from "@/lib/zitadel"; +import { getDeviceAuthorizationRequest as zitadelGetDeviceAuthorizationRequest } from "@/lib/zitadel"; import { headers } from "next/headers"; import { getServiceUrlFromHeaders } from "../service"; @@ -16,14 +13,3 @@ export async function getDeviceAuthorizationRequest(userCode: string) { userCode, }); } - -export async function denyDeviceAuthorization(deviceAuthorizationId: string) { - const _headers = await headers(); - const { serviceUrl } = getServiceUrlFromHeaders(_headers); - - // without the session, device auth request is denied - return authorizeOrDenyDeviceAuthorization({ - serviceUrl, - deviceAuthorizationId, - }); -} diff --git a/apps/login/src/lib/zitadel.ts b/apps/login/src/lib/zitadel.ts index da690c10e2..cc79754735 100644 --- a/apps/login/src/lib/zitadel.ts +++ b/apps/login/src/lib/zitadel.ts @@ -952,6 +952,10 @@ export async function authorizeOrDenyDeviceAuthorization({ deviceAuthorizationId: string; session?: { sessionId: string; sessionToken: string }; }) { + console.log("authorizeOrDenyDeviceAuthorization"); + + console.log("session", session); + const oidcService = await createServiceForHost(OIDCService, serviceUrl); return oidcService.authorizeOrDenyDeviceAuthorization({