diff --git a/src/app/auth/login/device/page.tsx b/src/app/auth/login/device/page.tsx
index 9b6b2bd2..7d2ed4e3 100644
--- a/src/app/auth/login/device/page.tsx
+++ b/src/app/auth/login/device/page.tsx
@@ -7,22 +7,35 @@ import { cache } from "react";
export const dynamic = "force-dynamic";
type Props = {
- searchParams: Promise<{ code?: string }>;
+ searchParams: Promise<{ code?: string; user?: string }>;
};
+function deviceRedirectSearchParams(params: {
+ code?: string;
+ user?: string;
+}): string {
+ const search = new URLSearchParams();
+ if (params.code) search.set("code", params.code);
+ if (params.user) search.set("user", params.user);
+ const q = search.toString();
+ return q ? `?${q}` : "";
+}
+
export default async function DeviceLoginPage({ searchParams }: Props) {
const user = await verifySession({ forceLogin: true });
const params = await searchParams;
const code = params.code || "";
+ const defaultUser = params.user;
if (!user) {
- const redirectDestination = code
- ? `/auth/login/device?code=${encodeURIComponent(code)}`
- : "/auth/login/device";
- redirect(
- `/auth/login?forceLogin=true&redirect=${encodeURIComponent(redirectDestination)}`
- );
+ const redirectDestination = `/auth/login/device${deviceRedirectSearchParams({ code, user: params.user })}`;
+ const loginUrl = new URL("/auth/login", "http://x");
+ loginUrl.searchParams.set("forceLogin", "true");
+ loginUrl.searchParams.set("redirect", redirectDestination);
+ if (defaultUser) loginUrl.searchParams.set("user", defaultUser);
+ console.log("loginUrl", loginUrl.pathname + loginUrl.search);
+ redirect(loginUrl.pathname + loginUrl.search);
}
const userName = user
@@ -37,6 +50,7 @@ export default async function DeviceLoginPage({ searchParams }: Props) {
userEmail={user?.email || ""}
userName={userName}
initialCode={code}
+ userQueryParam={defaultUser}
/>
);
}
diff --git a/src/app/auth/login/page.tsx b/src/app/auth/login/page.tsx
index 071020cd..2ba4d7f8 100644
--- a/src/app/auth/login/page.tsx
+++ b/src/app/auth/login/page.tsx
@@ -72,6 +72,8 @@ export default async function Page(props: {
searchParams.redirect = redirectUrl;
}
+ const defaultUser = searchParams.user as string | undefined;
+
// Only use SmartLoginForm if NOT (OSS build OR org-only IdP enabled)
const useSmartLogin =
build === "saas" || (build === "enterprise" && env.flags.useOrgOnlyIdp);
@@ -151,6 +153,7 @@ export default async function Page(props: {
@@ -165,6 +168,7 @@ export default async function Page(props: {
(build === "saas" || env.flags.useOrgOnlyIdp)
}
searchParams={searchParams}
+ defaultUser={defaultUser}
/>
)}
diff --git a/src/components/DashboardLoginForm.tsx b/src/components/DashboardLoginForm.tsx
index 8a4c611e..4484ba69 100644
--- a/src/components/DashboardLoginForm.tsx
+++ b/src/components/DashboardLoginForm.tsx
@@ -29,6 +29,7 @@ type DashboardLoginFormProps = {
searchParams?: {
[key: string]: string | string[] | undefined;
};
+ defaultUser?: string;
};
export default function DashboardLoginForm({
@@ -36,7 +37,8 @@ export default function DashboardLoginForm({
idps,
forceLogin,
showOrgLogin,
- searchParams
+ searchParams,
+ defaultUser
}: DashboardLoginFormProps) {
const router = useRouter();
const { env } = useEnvContext();
@@ -75,6 +77,7 @@ export default function DashboardLoginForm({
redirect={redirect}
idps={idps}
forceLogin={forceLogin}
+ defaultEmail={defaultUser}
onLogin={(redirectUrl) => {
if (redirectUrl) {
const safe = cleanRedirect(redirectUrl);
diff --git a/src/components/DeviceLoginForm.tsx b/src/components/DeviceLoginForm.tsx
index cadeb230..16e7f2e1 100644
--- a/src/components/DeviceLoginForm.tsx
+++ b/src/components/DeviceLoginForm.tsx
@@ -55,12 +55,14 @@ type DeviceLoginFormProps = {
userEmail: string;
userName?: string;
initialCode?: string;
+ userQueryParam?: string;
};
export default function DeviceLoginForm({
userEmail,
userName,
- initialCode = ""
+ initialCode = "",
+ userQueryParam
}: DeviceLoginFormProps) {
const router = useRouter();
const { env } = useEnvContext();
@@ -219,9 +221,12 @@ export default function DeviceLoginForm({
const currentSearch =
typeof window !== "undefined" ? window.location.search : "";
const redirectTarget = `/auth/login/device${currentSearch || ""}`;
- router.push(
- `/auth/login?forceLogin=true&redirect=${encodeURIComponent(redirectTarget)}`
- );
+ const loginUrl = new URL("/auth/login", "http://x");
+ loginUrl.searchParams.set("forceLogin", "true");
+ loginUrl.searchParams.set("redirect", redirectTarget);
+ if (userQueryParam)
+ loginUrl.searchParams.set("user", userQueryParam);
+ router.push(loginUrl.pathname + loginUrl.search);
router.refresh();
}
}
diff --git a/src/components/LoginForm.tsx b/src/components/LoginForm.tsx
index 5497826c..c3b1fc38 100644
--- a/src/components/LoginForm.tsx
+++ b/src/components/LoginForm.tsx
@@ -54,6 +54,7 @@ type LoginFormProps = {
idps?: LoginFormIDP[];
orgId?: string;
forceLogin?: boolean;
+ defaultEmail?: string;
};
export default function LoginForm({
@@ -61,7 +62,8 @@ export default function LoginForm({
onLogin,
idps,
orgId,
- forceLogin
+ forceLogin,
+ defaultEmail
}: LoginFormProps) {
const router = useRouter();
@@ -116,7 +118,7 @@ export default function LoginForm({
const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
- email: "",
+ email: defaultEmail ?? "",
password: ""
}
});
diff --git a/src/components/SmartLoginForm.tsx b/src/components/SmartLoginForm.tsx
index 5e1498ff..24f2acb7 100644
--- a/src/components/SmartLoginForm.tsx
+++ b/src/components/SmartLoginForm.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState } from "react";
+import { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
@@ -42,6 +42,7 @@ const isValidEmail = (str: string): boolean => {
type SmartLoginFormProps = {
redirect?: string;
forceLogin?: boolean;
+ defaultUser?: string;
};
type ViewState =
@@ -59,7 +60,8 @@ type ViewState =
export default function SmartLoginForm({
redirect,
- forceLogin
+ forceLogin,
+ defaultUser
}: SmartLoginFormProps) {
const router = useRouter();
const { lookup, loading, error } = useUserLookup();
@@ -72,10 +74,18 @@ export default function SmartLoginForm({
const form = useForm>({
resolver: zodResolver(identifierSchema),
defaultValues: {
- identifier: ""
+ identifier: defaultUser ?? ""
}
});
+ const hasAutoLookedUp = useRef(false);
+ useEffect(() => {
+ if (defaultUser?.trim() && !hasAutoLookedUp.current) {
+ hasAutoLookedUp.current = true;
+ void handleLookup({ identifier: defaultUser.trim() });
+ }
+ }, [defaultUser]);
+
const handleLookup = async (values: z.infer) => {
const identifier = values.identifier.trim();
const isEmail = isValidEmail(identifier);