This commit is contained in:
Max Peintner
2025-05-06 14:41:44 +02:00
parent 6e20bd3beb
commit a4e08b5419
11 changed files with 23 additions and 92 deletions

View File

@@ -200,6 +200,7 @@
"deny": "Ablehnen" "deny": "Ablehnen"
}, },
"scope": { "scope": {
"openid": "Überprüfen Sie Ihre Identität.",
"email": "Zugriff auf Ihre E-Mail-Adresse.", "email": "Zugriff auf Ihre E-Mail-Adresse.",
"profile": "Zugriff auf Ihre vollständigen Profilinformationen.", "profile": "Zugriff auf Ihre vollständigen Profilinformationen.",
"offline_access": "Erlauben Sie den Offline-Zugriff auf Ihr Konto." "offline_access": "Erlauben Sie den Offline-Zugriff auf Ihr Konto."

View File

@@ -190,7 +190,7 @@
"device": { "device": {
"usercode": { "usercode": {
"title": "Device code", "title": "Device code",
"description": "Enter the code.", "description": "Enter the code displayed on your app or device.",
"submit": "Continue" "submit": "Continue"
}, },
"request": { "request": {
@@ -200,8 +200,9 @@
"deny": "Deny" "deny": "Deny"
}, },
"scope": { "scope": {
"email": "Access your email address.", "openid": "Verify your identity.",
"profile": "Access your full profile information.", "email": "Access to your email address.",
"profile": "Access to your full profile information.",
"offline_access": "Allow offline access to your account." "offline_access": "Allow offline access to your account."
} }
}, },

View File

@@ -200,6 +200,7 @@
"deny": "Denegar" "deny": "Denegar"
}, },
"scope": { "scope": {
"openid": "Verifica tu identidad.",
"email": "Accede a tu dirección de correo electrónico.", "email": "Accede a tu dirección de correo electrónico.",
"profile": "Accede a la información completa de tu perfil.", "profile": "Accede a la información completa de tu perfil.",
"offline_access": "Permitir acceso sin conexión a tu cuenta." "offline_access": "Permitir acceso sin conexión a tu cuenta."

View File

@@ -200,6 +200,7 @@
"deny": "Nega" "deny": "Nega"
}, },
"scope": { "scope": {
"openid": "Verifica la tua identità.",
"email": "Accedi al tuo indirizzo email.", "email": "Accedi al tuo indirizzo email.",
"profile": "Accedi alle informazioni complete del tuo profilo.", "profile": "Accedi alle informazioni complete del tuo profilo.",
"offline_access": "Consenti l'accesso offline al tuo account." "offline_access": "Consenti l'accesso offline al tuo account."

View File

@@ -200,6 +200,7 @@
"deny": "Odmów" "deny": "Odmów"
}, },
"scope": { "scope": {
"openid": "Zweryfikuj swoją tożsamość.",
"email": "Uzyskaj dostęp do swojego adresu e-mail.", "email": "Uzyskaj dostęp do swojego adresu e-mail.",
"profile": "Uzyskaj dostęp do pełnych informacji o swoim profilu.", "profile": "Uzyskaj dostęp do pełnych informacji o swoim profilu.",
"offline_access": "Zezwól na dostęp offline do swojego konta." "offline_access": "Zezwól na dostęp offline do swojego konta."

View File

@@ -200,6 +200,7 @@
"deny": "Запретить" "deny": "Запретить"
}, },
"scope": { "scope": {
"openid": "Проверка вашей личности.",
"email": "Доступ к вашему адресу электронной почты.", "email": "Доступ к вашему адресу электронной почты.",
"profile": "Доступ к полной информации вашего профиля.", "profile": "Доступ к полной информации вашего профиля.",
"offline_access": "Разрешить офлайн-доступ к вашему аккаунту." "offline_access": "Разрешить офлайн-доступ к вашему аккаунту."

View File

@@ -200,6 +200,7 @@
"deny": "拒绝" "deny": "拒绝"
}, },
"scope": { "scope": {
"openid": "验证您的身份。",
"email": "访问您的电子邮件地址。", "email": "访问您的电子邮件地址。",
"profile": "访问您的完整个人资料信息。", "profile": "访问您的完整个人资料信息。",
"offline_access": "允许离线访问您的账户。" "offline_access": "允许离线访问您的账户。"

View File

@@ -63,10 +63,7 @@ export default async function Page(props: {
} }
return ( return (
<DynamicTheme <DynamicTheme branding={branding}>
branding={branding}
appName={deviceAuthorizationRequest?.appName}
>
<div className="flex flex-col items-center space-y-4"> <div className="flex flex-col items-center space-y-4">
<h1> <h1>
{t("request.title", { appName: deviceAuthorizationRequest?.appName })} {t("request.title", { appName: deviceAuthorizationRequest?.appName })}

View File

@@ -2,95 +2,17 @@ import { Alert, AlertType } from "@/components/alert";
import { Button, ButtonVariants } from "@/components/button"; import { Button, ButtonVariants } from "@/components/button";
import { DynamicTheme } from "@/components/dynamic-theme"; import { DynamicTheme } from "@/components/dynamic-theme";
import { UserAvatar } from "@/components/user-avatar"; import { UserAvatar } from "@/components/user-avatar";
import { import { getSessionCookieById } from "@/lib/cookies";
getMostRecentCookieWithLoginname,
getSessionCookieById,
} from "@/lib/cookies";
import { getServiceUrlFromHeaders } from "@/lib/service"; import { getServiceUrlFromHeaders } from "@/lib/service";
import { loadMostRecentSession } from "@/lib/session"; import { loadMostRecentSession } from "@/lib/session";
import { import {
authorizeOrDenyDeviceAuthorization,
createCallback,
createResponse,
getBrandingSettings, getBrandingSettings,
getLoginSettings, getLoginSettings,
getSession, getSession,
} from "@/lib/zitadel"; } from "@/lib/zitadel";
import { create } from "@zitadel/client";
import {
CreateCallbackRequestSchema,
SessionSchema,
} from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb";
import { CreateResponseRequestSchema } from "@zitadel/proto/zitadel/saml/v2/saml_service_pb";
import { getLocale, getTranslations } from "next-intl/server"; import { getLocale, getTranslations } from "next-intl/server";
import { headers } from "next/headers"; import { headers } from "next/headers";
import Link from "next/link"; import Link from "next/link";
import { redirect } from "next/navigation";
async function loadSession(
serviceUrl: string,
loginName: string,
requestId?: string,
) {
const recent = await getMostRecentCookieWithLoginname({ loginName });
if (requestId && requestId.startsWith("oidc_")) {
return createCallback({
serviceUrl,
req: create(CreateCallbackRequestSchema, {
authRequestId: requestId,
callbackKind: {
case: "session",
value: create(SessionSchema, {
sessionId: recent.id,
sessionToken: recent.token,
}),
},
}),
}).then(({ callbackUrl }) => {
return redirect(callbackUrl);
});
} else if (requestId && requestId.startsWith("saml_")) {
return createResponse({
serviceUrl,
req: create(CreateResponseRequestSchema, {
samlRequestId: requestId.replace("saml_", ""),
responseKind: {
case: "session",
value: {
sessionId: recent.id,
sessionToken: recent.token,
},
},
}),
}).then(({ url }) => {
return redirect(url);
});
} else if (requestId && requestId.startsWith("device_")) {
const session = {
sessionId: recent.id,
sessionToken: recent.token,
};
return authorizeOrDenyDeviceAuthorization({
serviceUrl,
deviceAuthorizationId: requestId.replace("device_", ""),
session,
}).then(() => {
return session;
});
}
return getSession({
serviceUrl,
sessionId: recent.id,
sessionToken: recent.token,
}).then((response) => {
if (response?.session) {
return response.session;
}
});
}
async function loadSessionById( async function loadSessionById(
serviceUrl: string, serviceUrl: string,

View File

@@ -1,3 +1,5 @@
"use client";
import { denyDeviceAuthorization } from "@/lib/server/oidc"; import { denyDeviceAuthorization } from "@/lib/server/oidc";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import Link from "next/link"; import Link from "next/link";
@@ -32,11 +34,9 @@ export function ConsentScreen({
setLoading(false); setLoading(false);
}); });
if (response && "redirect" in response && response.redirect) { if (response) {
return router.push("/device"); return router.push("/device");
} }
return response;
} }
return ( return (
@@ -77,7 +77,7 @@ export function ConsentScreen({
onClick={() => { onClick={() => {
denyDeviceAuth(); denyDeviceAuth();
}} }}
variant={ButtonVariants.Destructive} variant={ButtonVariants.Secondary}
data-testid="deny-button" data-testid="deny-button"
> >
{loading && <Spinner className="h-5 w-5 mr-2" />} {loading && <Spinner className="h-5 w-5 mr-2" />}

View File

@@ -7,8 +7,8 @@ type FinishFlowCommand =
function goToSignedInPage( function goToSignedInPage(
props: props:
| { sessionId: string; organization?: string } | { sessionId: string; organization?: string; requestId?: string }
| { organization?: string; loginName: string }, | { organization?: string; loginName: string; requestId?: string },
) { ) {
const params = new URLSearchParams({}); const params = new URLSearchParams({});
@@ -24,6 +24,11 @@ function goToSignedInPage(
params.append("organization", props.organization); params.append("organization", props.organization);
} }
// required to show conditional UI for device flow
if (props.requestId) {
params.append("requestId", props.requestId);
}
return `/signedin?` + params; return `/signedin?` + params;
} }