feat(FN-3047): add cancellable auth flow with recoverable pending login UX
This merge implements a recoverable pending-login auth flow (FN-3047) across three phases: cancellable in-progress auth routes in the API, an extended auth client contract, and updated ModelOnboardingModal/SettingsModal UI with proper cancel-button visibility during logout. It also adds `dashboard-r Fusion-Task-Id: FN-3047
This commit is contained in:
@@ -120,11 +120,19 @@ export const registerAuthRoutes: ApiRouteRegistrar = (ctx) => {
|
||||
const storage = getAuthStorage();
|
||||
storage.reload();
|
||||
const oauthProviders = storage.getOAuthProviders();
|
||||
const providers: { id: string; name: string; authenticated: boolean; type: "oauth" | "api_key" | "cli"; keyHint?: string }[] = oauthProviders.map((p) => ({
|
||||
const providers: {
|
||||
id: string;
|
||||
name: string;
|
||||
authenticated: boolean;
|
||||
type: "oauth" | "api_key" | "cli";
|
||||
keyHint?: string;
|
||||
loginInProgress?: boolean;
|
||||
}[] = oauthProviders.map((p) => ({
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
authenticated: storage.hasAuth(p.id),
|
||||
type: "oauth" as const,
|
||||
loginInProgress: loginInProgress.has(p.id),
|
||||
}));
|
||||
|
||||
// Include API-key-backed providers if supported
|
||||
@@ -421,6 +429,36 @@ export const registerAuthRoutes: ApiRouteRegistrar = (ctx) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/auth/cancel
|
||||
* Cancel an in-progress OAuth login for a provider.
|
||||
* Body: { provider: string }
|
||||
* Response: { success: true, cancelled: boolean }
|
||||
*/
|
||||
router.post("/auth/cancel", (req, res) => {
|
||||
try {
|
||||
const { provider } = req.body;
|
||||
if (!provider || typeof provider !== "string") {
|
||||
throw badRequest("provider is required");
|
||||
}
|
||||
|
||||
const activeLogin = loginInProgress.get(provider);
|
||||
if (!activeLogin) {
|
||||
res.json({ success: true, cancelled: false });
|
||||
return;
|
||||
}
|
||||
|
||||
loginInProgress.delete(provider);
|
||||
activeLogin.abort();
|
||||
res.json({ success: true, cancelled: true });
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof ApiError) {
|
||||
throw err;
|
||||
}
|
||||
rethrowAsApiError(err);
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/auth/oauth-callback", async (req, res) => {
|
||||
try {
|
||||
const error = typeof req.query.error === "string" ? req.query.error : undefined;
|
||||
|
||||
Reference in New Issue
Block a user