Skip to content

Fix: HTTPS + dev + API route = http://undefined/ as the request url #821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from

Conversation

AlexErrant
Copy link
Contributor

@AlexErrant AlexErrant commented Apr 2, 2023

Currently, if you use a self-signed cert, HTTPS, and try to use an API route on dev, the request.url looks like http://undefined/.

Example Setup

This is best exemplified in the with-authjs example, whose README I've updated in the first commit. Follow the instructions there, creating a .env file, Discord app, and self-signed cert. (Apologies in advance for how long this may take.) When you click "Sign in with Discord" using that self-signed cert, it will redirect you to http://undefined/api/auth/signin/discord. To demonstrate that this isn't a problem with authjs, go to with-authjs/src/routes/api/auth/[...solidauth].ts and replace export const { GET, POST } = SolidAuth(authOptions); with

import { PageEvent } from "solid-start";

export const POST = (x: PageEvent) =>  {
  console.log(x.request.url)
  return SolidAuth(authOptions).POST(x);
};

export const GET = (x: PageEvent) => {
  console.log(x.request.url)
  return SolidAuth(authOptions).GET(x);
};

If you revisit the login screen, you'll see the following in your console:

GET https://127.0.0.1:3000/
GET https://127.0.0.1:3000/api/auth/csrf
http://undefined/api/auth/csrf
POST https://127.0.0.1:3000/api/auth/signin/discord?
https://localhost:3000/api/auth/signin/discord?
GET https://127.0.0.1:3000/api/auth/signin?csrf=true
http://undefined/api/auth/signin?csrf=true

The Fix

The fix is implemented in the second commit. (Ignore the multiple force pushes below - I strived for a clean commit history.)

Here's a somewhat relevant section from the spec as to why the host header is missing; emphasis mine:

Clients that generate HTTP/2 requests directly SHOULD use the ":authority" pseudo-header field instead of the Host header field.

Note that this only works for HTTP/2 - I don't think it'll work for HTTP/1.1. From the 1.1 spec:

A client MUST include a Host header field in all HTTP/1.1 request messages

I'm unsure if we can get the correct URL anywhere else in Node. See the comment below for details.

createRequest has 3 callers, packages/start/dev/server.js, packages/start-node/server.js, and packages/start-static/entry.js, so this PR has security implications for production deployments.

@AlexErrant AlexErrant marked this pull request as draft April 2, 2023 16:11
@AlexErrant AlexErrant force-pushed the fix_self_cert branch 3 times, most recently from 4129446 to ea003f3 Compare April 2, 2023 20:24
origin = req.headers.origin || `http://${req.headers.host}`;
// It's impossible for `host` to be empty since :authority doesn't exist on HTTP/1.
// https://www.rfc-editor.org/rfc/rfc9110.html#section-7.2 A user agent MUST generate a Host header field in a request unless it sends that information as an ":authority" pseudo-header field
// We initially try the origin header because it has the scheme. The host header doesn't, and so defaults to HTTP
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would ideally like to use only the host header but I don't know how to get the scheme. createRequest has 3 callers, but I only know how to pass in the scheme to packages/start/dev/server.js (use viteServer.resolvedUrls.local[0]). I'm not good enough at Node (or Javascript) to know how to get the scheme from packages/start-node/server.js or packages/start-static/entry.js.

@AlexErrant AlexErrant marked this pull request as ready for review April 2, 2023 21:01
@AlexErrant
Copy link
Contributor Author

Svelte solves this issue here by forcing HTTP/1. Note that this solution uses the fact that Vite "downgrades to TLS only when the server.proxy option is also used". We hardcode http though, so that'll need to be switched to https... somehow. (In my examples/with-authjs reproduction, req.headers.origin is undefined.) I've still no idea how to get the scheme.

FYI this isn't blocking me, so I'm in no rush to merge. I did try to use pnpm patch and it worked great, but then I realized that my "real" code uses Cloudflare Workers... not Node... I switched to Node when attempting to create a minimal reproduction and never looked up. 🤦‍♂️ Cloudflare has its own problem that I discuss (and resolve) here. (I'm a good developer and know exactly what I'm doing 😊)

@ryansolid
Copy link
Member

In setting up for SolidStarts next Beta Phase built on Nitro and Vinxi we are closing all PRs/Issues that will not be merged due to the system changing. If you feel your issue was closed in mistake. Feel free to re-open it after updating/testing against 0.4.x release. Thank you for your patience.

See #1139 for more details.

@ryansolid ryansolid closed this Dec 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants