fix(auth): wire Microsoft SSO launch
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
+22
@@ -27,6 +27,28 @@ server {
|
||||
# way it does from the public internet.
|
||||
resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;
|
||||
|
||||
# Microsoft SSO is implemented by auth-service, but the demo API
|
||||
# gateway currently does not expose /api/v1/auth/microsoft/*. Keep the
|
||||
# FlowMaster/fm-shell contract same-origin by routing this one auth
|
||||
# surface directly to auth-service; the callback keeps X-Forwarded-Host
|
||||
# so auth-service returns to https://canvas.flow-master.ai/auth/sso-callback#...
|
||||
location ^~ /api/v1/auth/microsoft/ {
|
||||
# Use the Kubernetes ClusterIP directly. The server-wide resolver is
|
||||
# deliberately pinned to public DNS for external demo/dev hostnames,
|
||||
# and public DNS resolves *.svc.cluster.local to the node wildcard,
|
||||
# not the in-cluster Service.
|
||||
proxy_pass http://10.43.128.185:9001;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_http_version 1.1;
|
||||
proxy_connect_timeout 8s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# Reverse-proxy /api to the demo backend so live mode is same-origin.
|
||||
# Uses $variable form so nginx queries the PUBLIC resolver above per
|
||||
# request (cached 5 minutes). Combined with proxy_next_upstream this
|
||||
|
||||
+5
-46
@@ -12,7 +12,6 @@ export default function Login() {
|
||||
const buildAllowsDev = (import.meta.env.VITE_ENABLE_DEV_LOGIN ?? "true") !== "false";
|
||||
const [devLoginEnabled, setDevLoginEnabled] = useState(buildAllowsDev);
|
||||
const [devLoginEmail, setDevLoginEmail] = useState("dev@flow-master.ai");
|
||||
const [ssoState, setSsoState] = useState<"unknown" | "ready" | "not-configured" | "not-wired">("unknown");
|
||||
const [backendState, setBackendState] = useState<"unknown" | "up" | "auth-down" | "proxy-down">("unknown");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -31,13 +30,6 @@ export default function Login() {
|
||||
})
|
||||
.catch(() => { /* endpoint absent → keep state */ });
|
||||
}
|
||||
fetch("/api/v1/auth/microsoft/login", { method: "GET", redirect: "manual" })
|
||||
.then((r) => {
|
||||
if (r.status >= 300 && r.status < 400) setSsoState("ready");
|
||||
else if (r.status === 503) setSsoState("not-configured");
|
||||
else setSsoState("not-wired");
|
||||
})
|
||||
.catch(() => setSsoState("not-wired"));
|
||||
// Backend health precheck. /api/v1/auth/me with no token should return 401
|
||||
// when the backend is up. 502/504 means the proxy is down; 503 means the
|
||||
// auth service is down. We surface this so the operator knows BEFORE they
|
||||
@@ -52,7 +44,7 @@ export default function Login() {
|
||||
.catch(() => setBackendState("proxy-down"));
|
||||
}, [buildAllowsDev]);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
const handleSubmit = async (e: { preventDefault: () => void }) => {
|
||||
e.preventDefault();
|
||||
if (!email) return;
|
||||
if (!password) {
|
||||
@@ -93,31 +85,6 @@ export default function Login() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSSO = async () => {
|
||||
setError(null);
|
||||
setLoading(true);
|
||||
try {
|
||||
const probe = await fetch("/api/v1/auth/microsoft/login", { method: "GET", redirect: "manual" });
|
||||
if (probe.status >= 300 && probe.status < 400) {
|
||||
window.location.href = "/api/v1/auth/microsoft/login";
|
||||
return;
|
||||
}
|
||||
if (probe.status === 503) {
|
||||
setError("Microsoft sign-in is not yet enabled on this tenant. Use developer sign-in below for now.");
|
||||
return;
|
||||
}
|
||||
if (probe.status === 404) {
|
||||
setError("Microsoft sign-in is not wired to this environment yet. Use developer sign-in below for now.");
|
||||
return;
|
||||
}
|
||||
window.location.href = "/api/v1/auth/microsoft/login";
|
||||
} catch (e) {
|
||||
setError(`Microsoft sign-in unreachable: ${(e as Error).message}`);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="login-page">
|
||||
<div className="login-card">
|
||||
@@ -197,14 +164,9 @@ export default function Login() {
|
||||
<button
|
||||
type="button"
|
||||
className="sso-btn"
|
||||
onClick={handleSSO}
|
||||
disabled={loading || ssoState !== "ready"}
|
||||
title={
|
||||
ssoState === "ready" ? "Sign in with Microsoft"
|
||||
: ssoState === "not-configured" ? "Microsoft sign-in is not yet configured for this tenant"
|
||||
: ssoState === "not-wired" ? "Microsoft sign-in is not wired to this environment yet"
|
||||
: "Checking Microsoft sign-in availability…"
|
||||
}
|
||||
onClick={() => { window.location.href = "/api/v1/auth/microsoft/login"; }}
|
||||
disabled={loading}
|
||||
title="Sign in with Microsoft"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 21 21">
|
||||
<rect x="1" y="1" width="9" height="9" fill="#f25022"/>
|
||||
@@ -212,10 +174,7 @@ export default function Login() {
|
||||
<rect x="1" y="11" width="9" height="9" fill="#00a4ef"/>
|
||||
<rect x="11" y="11" width="9" height="9" fill="#ffb900"/>
|
||||
</svg>
|
||||
{ssoState === "unknown" ? "MICROSOFT SIGN-IN · CHECKING…"
|
||||
: ssoState === "not-configured" ? "MICROSOFT SIGN-IN · NOT CONFIGURED"
|
||||
: ssoState === "not-wired" ? "MICROSOFT SIGN-IN · NOT WIRED"
|
||||
: "CONTINUE WITH MICROSOFT"}
|
||||
CONTINUE WITH MICROSOFT
|
||||
</button>
|
||||
|
||||
{devLoginEnabled && (
|
||||
|
||||
Reference in New Issue
Block a user