mirror of
https://github.com/Chewbaccalakis/rfid-database.git
synced 2026-09-09 16:01:56 -07:00
Merge pull request #7 from Chewbaccalakis/cursor/fix-login-dynamic-oidc-e593
Fix OIDC button: force dynamic /login (was prerendered at build)
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
import { isOidcConfigured } from "@/lib/auth/oidc";
|
import { isOidcConfigured } from "@/lib/auth/oidc";
|
||||||
import { LoginPageClient } from "@/components/LoginPageClient";
|
import { LoginPageClient } from "@/components/LoginPageClient";
|
||||||
|
|
||||||
|
// OIDC env is only available at runtime (Docker). Never prerender this page
|
||||||
|
// at build time or the SSO button stays permanently hidden.
|
||||||
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const authUrl = (process.env.AUTH_URL || "").replace(/\/$/, "");
|
const authUrl = (process.env.AUTH_URL || "").replace(/\/$/, "");
|
||||||
const callbackUrlHint = authUrl
|
const callbackUrlHint = authUrl
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { FormEvent, useState } from "react";
|
import { FormEvent, useEffect, useState } from "react";
|
||||||
import { signIn } from "next-auth/react";
|
import { signIn } from "next-auth/react";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
@@ -11,6 +11,12 @@ type Props = {
|
|||||||
callbackUrlHint: string;
|
callbackUrlHint: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type AuthConfig = {
|
||||||
|
oidcEnabled: boolean;
|
||||||
|
oidcName: string;
|
||||||
|
callbackUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
function authErrorMessage(code: string | null): string | null {
|
function authErrorMessage(code: string | null): string | null {
|
||||||
if (!code) return null;
|
if (!code) return null;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
@@ -40,6 +46,23 @@ function LoginForm({ oidcEnabled, oidcName, callbackUrlHint }: Props) {
|
|||||||
authErrorMessage(params.get("error"))
|
authErrorMessage(params.get("error"))
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [runtimeOidc, setRuntimeOidc] = useState<AuthConfig | null>(null);
|
||||||
|
|
||||||
|
// Belt-and-suspenders: ask the live API so a stale static shell can't hide SSO
|
||||||
|
useEffect(() => {
|
||||||
|
fetch("/api/v1/auth/config")
|
||||||
|
.then((r) => (r.ok ? r.json() : null))
|
||||||
|
.then((data: AuthConfig | null) => {
|
||||||
|
if (data) setRuntimeOidc(data);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
/* ignore */
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const showOidc = runtimeOidc?.oidcEnabled ?? oidcEnabled;
|
||||||
|
const displayName = runtimeOidc?.oidcName || oidcName;
|
||||||
|
const redirectHint = runtimeOidc?.callbackUrl || callbackUrlHint;
|
||||||
|
|
||||||
async function onSubmit(e: FormEvent) {
|
async function onSubmit(e: FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -97,19 +120,19 @@ function LoginForm({ oidcEnabled, oidcName, callbackUrlHint }: Props) {
|
|||||||
<button className="btn" type="submit" disabled={loading}>
|
<button className="btn" type="submit" disabled={loading}>
|
||||||
{loading ? "Signing in…" : "Sign in"}
|
{loading ? "Signing in…" : "Sign in"}
|
||||||
</button>
|
</button>
|
||||||
{oidcEnabled && (
|
{showOidc && (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-secondary"
|
className="btn btn-secondary"
|
||||||
onClick={() => signIn("oidc", { callbackUrl })}
|
onClick={() => signIn("oidc", { callbackUrl })}
|
||||||
>
|
>
|
||||||
Sign in with {oidcName}
|
Sign in with {displayName}
|
||||||
</button>
|
</button>
|
||||||
<p className="muted" style={{ margin: 0, fontSize: "0.75rem" }}>
|
<p className="muted" style={{ margin: 0, fontSize: "0.75rem" }}>
|
||||||
IdP redirect URI must be exactly:
|
IdP redirect URI must be exactly:
|
||||||
<br />
|
<br />
|
||||||
<code className="mono">{callbackUrlHint}</code>
|
<code className="mono">{redirectHint}</code>
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user