# Troubleshooting Common issues and fixes: connection, auth, Redis, CORS. ## Connection ### Controller unreachable - Confirm **MISO_CONTROLLER_URL** is correct and reachable from your environment (no typo, right protocol, right host/port). - Test: `curl -I /health` (or the controller’s health endpoint). - Check firewall/network: the app server must be allowed to open outbound connections to the controller. ### SSL/TLS errors - Update Node and system CA certificates. - For **development only** with self-signed certs you can set `NODE_TLS_REJECT_UNAUTHORIZED=0`; never use this in production. ### Duplicated path segments in URLs (double-prefix) Symptoms: requests hit URLs like `…/miso/miso/api/v1/…` or `…/data/data/api/…` and return 404. Cause: the virtual-directory segment appears **twice** in the final URL. Common cases: - **Host-side duplication:** `controllerPublicUrl` or `baseUrl` already includes `/miso` (or `/data`), and the same segment is added again (e.g. React Router `basename` + manual string concat for API calls, or a custom `clientTokenUri` that repeats the mount). - **Misused SDK compatibility fields:** optional **`controllerBasePath`** / DataClient **`basePath`** are for an **origin-only** root plus a separate path. If the root URL already contains that path, leave `controllerBasePath` / `basePath` unset, or the merge will no-op — but if you **also** duplicate the segment in env or host code, you can still get a double-prefix. Fix: keep the segment in the effective API root **exactly once**. Prefer one full URL (`https://domain.com/miso`). If you use **`controllerBasePath`** or **`basePath`**, use origin-only controller/dataplane URLs and let the SDK merge once; do not add the same prefix again elsewhere. See [configuration.md](configuration.md#full-urls-and-virtual-directories). ## Authentication ### Token validation fails - Ensure the request sends the user JWT: `Authorization: Bearer `. - Check token format (JWT has three dot-separated parts). - Confirm the token is not expired (decode the JWT payload and check `exp`). - Verify **MISO_CLIENTID** and **MISO_CLIENTSECRET** are correct and that the controller can validate the token (same Keycloak/realm as the token issuer). ### Client token / “Failed to get environment token” - Backend only: ensure **MISO_CLIENTID** and **MISO_CLIENTSECRET** are set and valid in the environment that runs the backend. - Ensure the controller’s token endpoint (e.g. `/api/auth/token`) is reachable from the backend and returns 200 with a token. - For frontend: never use client secret in the browser; use a backend route that returns a client token (see [backend-client-token.md](backend-client-token.md)). ### User info not returned - Call **validateToken** first; if it returns false, **getUser** may not return data. - Ensure the token is the same one issued for your app / realm. ### Browser cookie session / redirect loop (split-port dev) Symptoms: OAuth succeeds but the app loops on login; DevTools shows `Failed to fetch` on auth calls; `miso_refresh_token` cookie exists but access token is missing after reload. Common causes: - **Cross-origin auth calls:** UI on port `3610`, controller on `3600` — browser blocks or drops cookies. Use the **UI origin** for API calls (Vite/nginx proxy to controller) via `resolveBrowserApiBaseUrl` (see [authentication.md](authentication.md#browser-ui-helpers-416)). - **localhost vs 127.0.0.1:** Cookie host must match the tab hostname. Use `alignLoopbackHostnameWithPage` on controller URLs. - **Missing `credentials: 'include'`** on session/refresh/login/callback — HttpOnly refresh cookie is not sent. - **Stale local token** after failed restore — call `clearCachedBrowserAuthState` (or app equivalent) then retry; use `recoverBrowserSessionWithStaleCleanup` for the standard retry order. Wire DataClient with `createCookieSessionCallbacks` and `preferCookieSessionRestore: true` ([dataclient.md](dataclient.md#enterprise-auth-flow)). ## Redis ### Redis connection failed - SDK continues to work without Redis: it falls back to the controller (no cache). - To use Redis: set **REDIS_HOST** and **REDIS_PORT** (and **REDIS_PASSWORD** if required). Check that Redis is running and reachable: `redis-cli -h -p ping`. - If Redis is optional for you, you can leave it unset and rely on controller-only mode. ### Slow role/permission checks - Add Redis and optional cache TTL tuning so roles/permissions are cached. See [redis.md](redis.md) and [configuration.md](configuration.md). ## CORS ### Browser CORS errors when calling controller or API CORS is required for **all** cross-origin browser requests—whether the request is authenticated or not. The SDK does not set CORS headers; your server (or the controller) must. - The **controller** (or the API the browser calls) must allow your frontend origin (e.g. `Access-Control-Allow-Origin`). If you send credentials (cookies, `credentials: 'include'`), also set `Access-Control-Allow-Credentials: true`. - **Unauthenticated endpoints:** Same CORS policy applies; the browser still checks origin before the request. - In development, a proxy (e.g. Vite proxy, or your backend proxying to the controller) can avoid CORS by having the browser call your app’s origin only. - Ensure the backend client-token route is on the same origin as the frontend or that its CORS policy allows the frontend origin. ## Configuration ### Invalid or missing config - Use **loadConfig()** so required env vars are validated at startup; it throws if **MISO_CLIENTID**, **MISO_CLIENTSECRET**, or **MISO_CONTROLLER_URL** are missing. - Do not log **MISO_CLIENTSECRET** (or any secret); log only non-sensitive settings (e.g. controller URL, client ID) when debugging. ## Getting help - Check the docs: [quick-start](quick-start.md), [authentication](authentication.md), [backend-client-token](backend-client-token.md), [errors](errors.md), [redis](redis.md), [configuration](configuration.md). - Open an issue in the repository with: SDK version, Node version, what you did, what you expected, and the error message or logs (with secrets removed).