diff --git a/app/auth/login/route.ts b/app/auth/login/route.ts index 60d0451..15100c2 100644 --- a/app/auth/login/route.ts +++ b/app/auth/login/route.ts @@ -22,17 +22,16 @@ export async function GET(req: NextRequest) { if (!coinpayConfigured()) { return new NextResponse("CoinPay login is not configured yet.", { status: 503 }); } - const mode = req.nextUrl.searchParams.get("mode") === "connect" ? "connect" : "login"; - if (mode === "connect") { - const s = readSession(req.cookies.get(SESSION_COOKIE)?.value); - if (!s?.sub?.startsWith("acct:")) { - return NextResponse.redirect(new URL("/login", req.nextUrl.origin)); - } - } const secure = requestIsHttps(req); // Send the IdP back to the host the user is actually on, so the host-only // pending cookies set below are still readable at the callback. const origin = resolveOrigin(requestHosts(req.headers), secure); + const mode = req.nextUrl.searchParams.get("mode") === "connect" ? "connect" : "login"; + if (mode === "connect") { + const s = readSession(req.cookies.get(SESSION_COOKIE)?.value); + // req.nextUrl.origin is the container's own address behind the proxy. + if (!s?.sub?.startsWith("acct:")) return NextResponse.redirect(`${origin}/login`); + } const { verifier, challenge, state, nonce } = makePkce(); const res = NextResponse.redirect(authorizeUrl(challenge, state, redirectUriFor(origin), nonce)); const opts = { httpOnly: true, sameSite: "lax" as const, secure, path: "/", maxAge: 600 }; diff --git a/tests/coinpay-signin.test.mjs b/tests/coinpay-signin.test.mjs index c64a3e3..c0dfaec 100644 --- a/tests/coinpay-signin.test.mjs +++ b/tests/coinpay-signin.test.mjs @@ -77,8 +77,9 @@ test("start sends PKCE S256, state and nonce; connect needs a password session", assert.ok(loc.searchParams.get("state") && loc.searchParams.get("nonce") && loc.searchParams.get("code_challenge")); assert.equal(loc.searchParams.get("redirect_uri"), "https://moshcoding.com/auth/coinpay/callback"); - const noSession = await loginRoute.GET(new NextRequest("https://moshcoding.com/auth/login?mode=connect", { headers: { host: "moshcoding.com" } })); - assert.equal(new URL(noSession.headers.get("location")).pathname, "/login"); + // behind the proxy the request URL is the container's own address + const noSession = await loginRoute.GET(new NextRequest("http://localhost:8080/auth/login?mode=connect", { headers: { host: "moshcoding.com", "x-forwarded-proto": "https" } })); + assert.equal(noSession.headers.get("location"), "https://moshcoding.com/login"); }); function callbackReq({ state = "s1", cookieState = "s1", mode, session } = {}) {