feat(FN-2521): add remote auth handoff endpoints and login URL flow
- Add remote auth token primitives plus login-url generation for short-lived phone auth handoff - Expose public handoff API endpoint and wire remote auth handling into dashboard server routes - Tighten remote access settings update typing to satisfy typecheck and preserve API isolation behavior - Add comprehensive dashboard tests for remote-auth helpers, route behavior, and server integration - Document the remote login-url and phone auth handoff contract in architecture docs
This commit is contained in:
@@ -47,6 +47,7 @@ import { ChatManager } from "./chat.js";
|
||||
import { stopAllDevServers } from "./dev-server-routes.js";
|
||||
import type { SkillsAdapter } from "./skills-adapter.js";
|
||||
import { createAuthMiddleware, authenticateUpgradeRequest, getDaemonToken } from "./auth-middleware.js";
|
||||
import { validateRemoteAuthToken } from "./remote-auth.js";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
@@ -895,6 +896,50 @@ export function createServer(store: TaskStore, options?: ServerOptions): ReturnT
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/remote-login", async (req, res) => {
|
||||
const remoteToken = typeof req.query.rt === "string" ? req.query.rt : undefined;
|
||||
|
||||
let settings: Awaited<ReturnType<typeof store.getSettings>>;
|
||||
try {
|
||||
settings = await store.getSettings();
|
||||
} catch {
|
||||
res.status(401).json({ error: "Unauthorized", code: "remote_token_invalid" });
|
||||
return;
|
||||
}
|
||||
|
||||
const remoteAccess = settings.remoteAccess;
|
||||
if (!remoteAccess) {
|
||||
res.status(401).json({ error: "Unauthorized", code: "remote_token_invalid" });
|
||||
return;
|
||||
}
|
||||
|
||||
const result = validateRemoteAuthToken(remoteToken, remoteAccess);
|
||||
if (result.status !== "valid") {
|
||||
const codeByStatus: Record<string, string> = {
|
||||
missing: "remote_token_missing",
|
||||
expired: "remote_token_expired",
|
||||
invalid: "remote_token_invalid",
|
||||
disabled: "remote_token_invalid",
|
||||
};
|
||||
|
||||
res.status(401).json({
|
||||
error: "Unauthorized",
|
||||
code: codeByStatus[result.status] ?? "remote_token_invalid",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const daemonTokenForRedirect = getDaemonToken(options);
|
||||
if (daemonTokenForRedirect) {
|
||||
const redirectUrl = new URL("/", `${req.protocol}://${req.get("host")}`);
|
||||
redirectUrl.searchParams.set("token", daemonTokenForRedirect);
|
||||
res.redirect(302, redirectUrl.pathname + redirectUrl.search);
|
||||
return;
|
||||
}
|
||||
|
||||
res.redirect(302, "/");
|
||||
});
|
||||
|
||||
// REST API
|
||||
app.use("/api", createApiRoutes(store, {
|
||||
...options,
|
||||
|
||||
Reference in New Issue
Block a user