Merge pull request 'fix(api): autorise l'origine WebView Capacitor dans CORS_ORIGIN' (#82) from fix/cors-origin-capacitor-app into main
All checks were successful
All checks were successful
This commit is contained in:
commit
94ef8b4133
3 changed files with 42 additions and 7 deletions
|
|
@ -11,7 +11,7 @@ JWT_SECRET=changeme-generate-a-real-random-secret-at-least-32-chars
|
||||||
# Optional — defaults shown (see src/config/env.ts)
|
# Optional — defaults shown (see src/config/env.ts)
|
||||||
# JWT_EXPIRES_IN=7d
|
# JWT_EXPIRES_IN=7d
|
||||||
# AUTH_COOKIE_NAME=session
|
# AUTH_COOKIE_NAME=session
|
||||||
# CORS_ORIGIN=http://localhost:5173
|
# CORS_ORIGIN=http://localhost:5173,https://localhost
|
||||||
# INTENT_SERVICE_BASE_URL=http://localhost:8000
|
# INTENT_SERVICE_BASE_URL=http://localhost:8000
|
||||||
|
|
||||||
# Required — services/tech-step-intent-service must be running locally (see
|
# Required — services/tech-step-intent-service must be running locally (see
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,11 @@ export function createServer(): ExpressServer {
|
||||||
// pipeline (its "finish" listener still fires for a request that never
|
// pipeline (its "finish" listener still fires for a request that never
|
||||||
// makes it past CORS/body-parsing, not just ones that reach a route).
|
// makes it past CORS/body-parsing, not just ones that reach a route).
|
||||||
server.addMiddleware(requestLogger);
|
server.addMiddleware(requestLogger);
|
||||||
// One allowed origin: the app (`CORS_ORIGIN`). The admin surface
|
// Allowed origin(s) come from `CORS_ORIGIN` (see its own doc comment in
|
||||||
// (`/admin/*`) is served by this same API and consumed by `apps/web`'s
|
// config/env.ts for why the packaged Android app's origin must always be
|
||||||
// own `/admin/*` routes — same origin as the rest of the app, so no
|
// one of them). The admin surface (`/admin/*`) is served by this same API
|
||||||
// extra CORS entry.
|
// and consumed by `apps/web`'s own `/admin/*` routes — same origin as the
|
||||||
|
// rest of the app, so no extra CORS entry.
|
||||||
server.setupCore({ corsOrigin: env.CORS_ORIGIN });
|
server.setupCore({ corsOrigin: env.CORS_ORIGIN });
|
||||||
|
|
||||||
server.addRoute("get", "/health", (_req: Request, res: Response) => {
|
server.addRoute("get", "/health", (_req: Request, res: Response) => {
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,42 @@ const envSchema = z.object({
|
||||||
JWT_EXPIRES_IN: z.string().default("7d"),
|
JWT_EXPIRES_IN: z.string().default("7d"),
|
||||||
/** Name of the httpOnly cookie carrying the session JWT. */
|
/** Name of the httpOnly cookie carrying the session JWT. */
|
||||||
AUTH_COOKIE_NAME: z.string().default("session"),
|
AUTH_COOKIE_NAME: z.string().default("session"),
|
||||||
/** Origin allowed by CORS — must match wherever apps/web is served from. */
|
/**
|
||||||
CORS_ORIGIN: z.string().default("http://localhost:5173"),
|
* Origin(s) allowed by CORS, comma-separated — parsed below into a
|
||||||
|
* `string[]` for `ExpressServerCoreOptions.corsOrigin`
|
||||||
|
* (`app.ts`/`express-server.ts`, which passes it straight to the `cors`
|
||||||
|
* package) and reused as-is for the Socket.IO handshake's own CORS config
|
||||||
|
* (`server.ts`, which needs its own since the WS upgrade never runs
|
||||||
|
* through `setupCore`'s middleware).
|
||||||
|
*
|
||||||
|
* Must always include `https://localhost`: the packaged Android app's
|
||||||
|
* WebView is served from exactly that fixed origin (Capacitor's default
|
||||||
|
* for `androidScheme`/hostname — see `apps/web/capacitor.config.ts`'s own
|
||||||
|
* doc comment), and every request it makes to this API — `/auth/login`
|
||||||
|
* and `/auth/signup` included — is genuinely cross-origin, unlike
|
||||||
|
* apps/web's *browser* build, which is served from the very same origin
|
||||||
|
* as this API in production (see docker-compose.yml's `app` service) and
|
||||||
|
* so never needs an entry here at all. Missing this origin doesn't fail
|
||||||
|
* loudly: the `cors` package still answers a preflight `OPTIONS` with 204
|
||||||
|
* for an origin it's about to reject (it only *omits*
|
||||||
|
* `Access-Control-Allow-Origin`), so the request the app's WebView logs
|
||||||
|
* looks identical to a normal one right up until the browser silently
|
||||||
|
* drops the real `POST` — surfacing client-side as a generic "unexpected
|
||||||
|
* error" with no 401/403 anywhere to point at the actual cause. Default
|
||||||
|
* covers both the Vite dev server and the packaged app out of the box; a
|
||||||
|
* real deployment's own web origin (e.g. a production domain) never needs
|
||||||
|
* adding here for the reason above, but the env var still allows
|
||||||
|
* extending/overriding this list (comma-separated) if that ever changes.
|
||||||
|
*/
|
||||||
|
CORS_ORIGIN: z
|
||||||
|
.string()
|
||||||
|
.default("http://localhost:5173,https://localhost")
|
||||||
|
.transform((value) =>
|
||||||
|
value
|
||||||
|
.split(",")
|
||||||
|
.map((origin) => origin.trim())
|
||||||
|
.filter((origin) => origin.length > 0),
|
||||||
|
),
|
||||||
/**
|
/**
|
||||||
* Absolute path to the built frontend (`apps/web/dist`), to serve
|
* Absolute path to the built frontend (`apps/web/dist`), to serve
|
||||||
* alongside the API. Optional, no default — only set inside the
|
* alongside the API. Optional, no default — only set inside the
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue