This commit is contained in:
Max Peintner
2025-05-06 14:55:20 +02:00
parent 4f8aca1434
commit 2f7c628dcd
10 changed files with 8 additions and 137 deletions

View File

@@ -207,6 +207,7 @@
}
},
"error": {
"noUserCode": "Kein Benutzercode angegeben!",
"noDeviceRequest": " Es wurde keine Geräteanforderung gefunden. Bitte überprüfen Sie die URL.",
"unknownContext": "Der Kontext des Benutzers konnte nicht ermittelt werden. Stellen Sie sicher, dass Sie zuerst den Benutzernamen eingeben oder einen loginName als Suchparameter angeben.",
"sessionExpired": "Ihre aktuelle Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.",

View File

@@ -207,6 +207,7 @@
}
},
"error": {
"noUserCode": "No user code provided!",
"noDeviceRequest": "No device request found.",
"unknownContext": "Could not get the context of the user. Make sure to enter the username first or provide a loginName as searchParam.",
"sessionExpired": "Your current session has expired. Please login again.",

View File

@@ -207,6 +207,7 @@
}
},
"error": {
"noUserCode": "¡No se proporcionó código de usuario!",
"noDeviceRequest": "No se encontró ninguna solicitud de dispositivo.",
"unknownContext": "No se pudo obtener el contexto del usuario. Asegúrate de ingresar primero el nombre de usuario o proporcionar un loginName como parámetro de búsqueda.",
"sessionExpired": "Tu sesión actual ha expirado. Por favor, inicia sesión de nuevo.",

View File

@@ -207,6 +207,7 @@
}
},
"error": {
"noUserCode": "Nessun codice utente fornito!",
"noDeviceRequest": "Nessuna richiesta di dispositivo trovata.",
"unknownContext": "Impossibile ottenere il contesto dell'utente. Assicurati di inserire prima il nome utente o di fornire un loginName come parametro di ricerca.",
"sessionExpired": "La tua sessione attuale è scaduta. Effettua nuovamente l'accesso.",

View File

@@ -207,6 +207,7 @@
}
},
"error": {
"noUserCode": "Nie podano kodu użytkownika!",
"noDeviceRequest": "Nie znaleziono żądania urządzenia.",
"unknownContext": "Nie udało się pobrać kontekstu użytkownika. Upewnij się, że najpierw wprowadziłeś nazwę użytkownika lub podałeś login jako parametr wyszukiwania.",
"sessionExpired": "Twoja sesja wygasła. Zaloguj się ponownie.",

View File

@@ -207,6 +207,7 @@
}
},
"error": {
"noUserCode": "Не указан код пользователя!",
"noDeviceRequest": "Не найдена ни одна заявка на устройство.",
"unknownContext": "Не удалось получить контекст пользователя. Укажите имя пользователя или loginName в параметрах поиска.",
"sessionExpired": "Ваша сессия истекла. Войдите снова.",

View File

@@ -207,6 +207,7 @@
}
},
"error": {
"noUserCode": "未提供用户代码!",
"noDeviceRequest": "没有找到设备请求。",
"unknownContext": "无法获取用户的上下文。请先输入用户名或提供 loginName 作为搜索参数。",
"sessionExpired": "当前会话已过期,请重新登录。",

View File

@@ -22,7 +22,7 @@ export default async function Page(props: {
const organization = searchParams?.organization;
if (!userCode || !requestId) {
return <div>{t("error.no_user_code")}</div>;
return <div>{t("error.noUserCode")}</div>;
}
const _headers = await headers();

View File

@@ -1,5 +1,4 @@
import { getAllSessions } from "@/lib/cookies";
import { loginWithDeviceAndSession } from "@/lib/device";
import { idpTypeToSlug } from "@/lib/idp";
import { loginWithOIDCAndSession } from "@/lib/oidc";
import { loginWithSAMLAndSession } from "@/lib/saml";
@@ -126,16 +125,6 @@ export async function GET(request: NextRequest) {
sessionCookies,
request,
});
} else if (requestId.startsWith("device_")) {
// this finishes the login process for Device Authorization
return loginWithDeviceAndSession({
serviceUrl,
deviceRequest: requestId.replace("device_", ""),
sessionId,
sessions,
sessionCookies,
request,
});
}
}

View File

@@ -1,125 +0,0 @@
import { Cookie } from "@/lib/cookies";
import { sendLoginname, SendLoginnameCommand } from "@/lib/server/loginname";
import {
authorizeOrDenyDeviceAuthorization,
getLoginSettings,
} from "@/lib/zitadel";
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
import { NextRequest, NextResponse } from "next/server";
import { constructUrl } from "./service";
import { isSessionValid } from "./session";
type LoginWithOIDCandSession = {
serviceUrl: string;
deviceRequest: string;
sessionId: string;
sessions: Session[];
sessionCookies: Cookie[];
request: NextRequest;
};
export async function loginWithDeviceAndSession({
serviceUrl,
deviceRequest,
sessionId,
sessions,
sessionCookies,
request,
}: LoginWithOIDCandSession) {
console.log(
`Login with session: ${sessionId} and deviceRequest: ${deviceRequest}`,
);
const selectedSession = sessions.find((s) => s.id === sessionId);
if (selectedSession && selectedSession.id) {
console.log(`Found session ${selectedSession.id}`);
const isValid = await isSessionValid({
serviceUrl,
session: selectedSession,
});
console.log("Session is valid:", isValid);
if (!isValid && selectedSession.factors?.user) {
// if the session is not valid anymore, we need to redirect the user to re-authenticate /
// TODO: handle IDP intent direcly if available
const command: SendLoginnameCommand = {
loginName: selectedSession.factors.user?.loginName,
organization: selectedSession.factors?.user?.organizationId,
requestId: `device_${deviceRequest}`,
};
const res = await sendLoginname(command);
if (res && "redirect" in res && res?.redirect) {
const absoluteUrl = constructUrl(request, res.redirect);
return NextResponse.redirect(absoluteUrl.toString());
}
}
const cookie = sessionCookies.find(
(cookie) => cookie.id === selectedSession?.id,
);
if (cookie && cookie.id && cookie.token) {
const session = {
sessionId: cookie?.id,
sessionToken: cookie?.token,
};
// works not with _rsc request
try {
const authResponse = await authorizeOrDenyDeviceAuthorization({
serviceUrl,
deviceAuthorizationId: deviceRequest,
session,
});
if (!authResponse) {
return NextResponse.json(
{ error: "An error occurred!" },
{ status: 500 },
);
}
} catch (error: unknown) {
// handle already handled gracefully as these could come up if old emails with requestId are used (reset password, register emails etc.)
console.error(error);
if (
error &&
typeof error === "object" &&
"code" in error &&
error?.code === 9
) {
const loginSettings = await getLoginSettings({
serviceUrl,
organization: selectedSession.factors?.user?.organizationId,
});
if (loginSettings?.defaultRedirectUri) {
return NextResponse.redirect(loginSettings.defaultRedirectUri);
}
const signedinUrl = constructUrl(request, "/signedin");
signedinUrl.searchParams.set("requestId", `device_${deviceRequest}`);
if (selectedSession.factors?.user?.loginName) {
signedinUrl.searchParams.set(
"loginName",
selectedSession.factors?.user?.loginName,
);
}
if (selectedSession.factors?.user?.organizationId) {
signedinUrl.searchParams.set(
"organization",
selectedSession.factors?.user?.organizationId,
);
}
return NextResponse.redirect(signedinUrl);
} else {
return NextResponse.json({ error }, { status: 500 });
}
}
}
}
}