From 70a1387998a759373b96c836d2a651bb56ddf7d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 1 May 2026 09:20:19 +0200 Subject: [PATCH] Fix OAuth callback returnTo after settings split The connect loader was setting state to a raw user.id, but the callback parses state as base64-JSON via decodeOAuthState and falls back to {} when the parse fails. That sent users back to /settings, which now redirects to /settings/profile, hiding the freshly saved connection on a different tab. Encode the state as a proper PushOAuthState with returnTo set to /settings/connections so the callback lands on the page that initiated the flow. Co-Authored-By: Claude Opus 4.7 --- apps/journal/app/routes/api.sync.connect.$provider.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/journal/app/routes/api.sync.connect.$provider.ts b/apps/journal/app/routes/api.sync.connect.$provider.ts index e8923f4..fb32a3a 100644 --- a/apps/journal/app/routes/api.sync.connect.$provider.ts +++ b/apps/journal/app/routes/api.sync.connect.$provider.ts @@ -2,6 +2,7 @@ import { redirect, data } from "react-router"; import type { Route } from "./+types/api.sync.connect.$provider"; import { getSessionUser } from "~/lib/auth.server"; import { getProvider } from "~/lib/sync/registry"; +import { encodeOAuthState } from "~/lib/sync/pushes.server"; export async function loader({ params, request }: Route.LoaderArgs) { const user = await getSessionUser(request); @@ -12,7 +13,7 @@ export async function loader({ params, request }: Route.LoaderArgs) { const origin = process.env.ORIGIN ?? "http://localhost:3000"; const redirectUri = `${origin}/api/sync/callback/${params.provider}`; - const state = user.id; // Simple state — could use a CSRF token for production + const state = encodeOAuthState({ returnTo: "/settings/connections" }); return redirect(provider.getAuthUrl(redirectUri, state)); }