mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-08-13 22:37:29 +00:00
fix(pwa): return the caller's own host in the CLI device-flow URLs (#105)
`logicsrc login --device` told users to open https://logicsrc-credentials-production.up.railway.app/cli/device even when they had reached the app on the real domain. /cli/device/code built verification_uri from `config.origin`, which is a single fixed value read from $PUBLIC_ORIGIN, so the response was wrong for every hostname except the one that variable happened to name. Derive the origin from the request instead: whatever host the CLI called is the host it gets sent back to. Express honours X-Forwarded-Proto/Host here because server.mjs sets `trust proxy` behind Railway's TLS terminator. Deliberately scoped to the two device-flow URLs. The WebAuthn expectedOrigin in passkey.mjs stays pinned to config.origin — validating a signature against a host the caller supplied would defeat the check. Note this fixes which URL is *printed*; the host still has to route to this service for the link to load. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0510d86f85
commit
60c0cbfbce
3 changed files with 83 additions and 2 deletions
30
apps/pwa/src/lib/origin.mjs
Normal file
30
apps/pwa/src/lib/origin.mjs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Which origin to hand back to a caller.
|
||||
//
|
||||
// `config.origin` comes from $PUBLIC_ORIGIN and is a single fixed value, so any
|
||||
// response that echoes it is wrong the moment the app is reachable on more than
|
||||
// one hostname — that is how `logicsrc login` ended up printing a generated
|
||||
// Railway hostname to users on the real domain. For URLs we hand back to the
|
||||
// caller, derive the origin from the request instead: whatever host the client
|
||||
// reached us on is the host it should be sent back to.
|
||||
//
|
||||
// Express honours X-Forwarded-Proto/X-Forwarded-Host here because server.mjs
|
||||
// sets `trust proxy` behind Railway's TLS terminator.
|
||||
//
|
||||
// NOT for security decisions. The WebAuthn `expectedOrigin` in passkey.mjs must
|
||||
// stay pinned to config.origin — validating a signature against a host the
|
||||
// caller supplied would defeat the check.
|
||||
|
||||
/**
|
||||
* The origin this request arrived on (`https://logicsrc.com`), falling back to
|
||||
* the configured origin when there is no Host header (HTTP/1.0, direct socket).
|
||||
*
|
||||
* @param {{ protocol?: string, get?: (h: string) => string | undefined, headers?: Record<string, unknown> }} req
|
||||
* @param {string} fallback - config.origin
|
||||
* @returns {string} origin with no trailing slash
|
||||
*/
|
||||
export function requestOrigin(req, fallback) {
|
||||
const host = req?.get?.("host") || req?.headers?.host;
|
||||
if (!host) return String(fallback || "").replace(/\/+$/, "");
|
||||
const protocol = req?.protocol || "https";
|
||||
return `${protocol}://${host}`.replace(/\/+$/, "");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue