{"record":{"id":"8561363a99d1839d","repo":"MagicMirrorOrg/MagicMirror","slug":"this-device-is-not-allowed-to-access-your-mirror","errorCode":null,"errorMessage":"This device is not allowed to access your mirror. <br> Please check your config.js or config.js.sample to change this.","messagePattern":"This device is not allowed to access your mirror\\. <br> Please check your config\\.js or config\\.js\\.sample to change this\\.","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"js/ip_access_control.js","lineNumber":79,"sourceCode":" */\nfunction ipAccessControl (whitelist) {\n\t// Empty whitelist means allow all\n\tif (!Array.isArray(whitelist) || whitelist.length === 0) {\n\t\treturn function (req, res, next) {\n\t\t\tres.header(\"Access-Control-Allow-Origin\", \"*\");\n\t\t\tnext();\n\t\t};\n\t}\n\n\treturn function (req, res, next) {\n\t\tconst clientIp = resolveClientIp(req);\n\n\t\tif (isAllowed(clientIp, whitelist)) {\n\t\t\tres.header(\"Access-Control-Allow-Origin\", \"*\");\n\t\t\tnext();\n\t\t} else {\n\t\t\tLog.warn(`IP ${clientIp} is not allowed to access the mirror`);\n\t\t\tres.status(403).send(\"This device is not allowed to access your mirror. <br> Please check your config.js or config.js.sample to change this.\");\n\t\t}\n\t};\n}\n\n/**\n * Creates a Socket.IO `allowRequest` handler that enforces the same IP whitelist as the HTTP middleware.\n * This closes the gap where Socket.IO handshakes bypassed the Express-only `ipAccessControl` middleware.\n * @param {string[]} whitelist - Array of allowed IP addresses or CIDR ranges\n * @returns {(req: object, callback: (err: string | null, success: boolean) => void) => void} Socket.IO allowRequest handler\n */\nfunction socketIpAccessControl (whitelist) {\n\t// Empty whitelist means allow all\n\tif (!Array.isArray(whitelist) || whitelist.length === 0) {\n\t\treturn function (req, callback) {\n\t\t\tcallback(null, true); // allow the connection\n\t\t};\n\t}\n","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/MagicMirrorOrg/MagicMirror/blob/4b4a59534f7da01e4030e46029fe9dd649a7675e/js/ip_access_control.js#L61-L97","documentation":"MagicMirror's `ipAccessControl` middleware (js/ip_access_control.js:79) rejects any HTTP request whose client IP is not in the configured `ipWhitelist`. Instead of proceeding with `next()`, it responds with HTTP 403 and this HTML/text message, and logs a warning via `Log.warn`. This is intentional access control: the mirror only serves devices explicitly allowed by the whitelist (which may include the special value `[]` to allow all, or entries like `127.0.0.1`, `::ffff:127.0.0.1`, subnets, or `ddns` names).","triggerScenarios":"An HTTP request arrives from a client IP that `isAllowed(clientIp, whitelist)` evaluates as not matching any entry in `config.ipWhitelist` — e.g. default whitelist only allows localhost but you browse from another LAN device; IPv6 requests arriving as `::1` or `::ffff:192.168.x.x` while the whitelist only lists IPv4 forms; a reverse proxy forwards so the seen IP is the proxy's; Socket.IO `allowRequest` enforces the same whitelist and rejects the socket handshake.","commonSituations":"Opening the mirror from a phone/other computer on the LAN while `ipWhitelist` is left at the default `['127.0.0.1', '::ffff:127.0.0.1', '::1']`; Docker/Kubernetes deployments where the container sees the bridge/proxy IP instead of the real client IP; adding an IPv4 entry but the browser connects over IPv6; using a DDNS hostname without the required `ddns: true` flag on the whitelist entry.","solutions":["Add the client's IP (both IPv4 and IPv6-mapped forms, e.g. '192.168.1.10' and '::ffff:192.168.1.10') to `ipWhitelist` in config.js and restart the mirror.","For a trusted LAN with no access control, set `ipWhitelist: []` — an empty array allows all addresses.","If behind a reverse proxy, whitelist the proxy address and configure the proxy to pass the real client IP (X-Forwarded-For/Express 'trust proxy'), since the middleware checks the apparent peer IP.","For dynamic remote access, use a DDNS whitelist entry with `ddns: true` rather than a static IP.","Check the server log line `IP <address> is not allowed to access the mirror` to learn the exact IP string the server sees, then whitelist that literal."],"exampleFix":"// before (config.js — default, localhost only)\nipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1', '::1'],\n// after — allow one LAN device over IPv4+IPv6, or use [] to allow all\nipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1', '::1', '192.168.1.10', '::ffff:192.168.1.10'],\n// or: ipWhitelist: [],","handlingStrategy":"validation","validationCode":"// Client-side pre-check before loading the mirror:\nconst WHITELISTED = ['127.0.0.1', '::ffff:127.0.0.1', '::1', '192.168.1.10'];\nasync function checkAccess(baseUrl) {\n  const res = await fetch(baseUrl, { redirect: 'manual' });\n  if (res.status === 403) throw new Error('Device IP not in mirror ipWhitelist');\n  return res.ok;\n}","typeGuard":"function isWhitelistConfig(v) {\n  return Array.isArray(v) && v.every(e => typeof e === 'string' || (typeof e === 'object' && e !== null && typeof e.ip === 'string'));\n}","tryCatchPattern":"try {\n  const ok = await checkAccess('http://mirror.local:8080');\n} catch (e) {\n  // e.message mentions ipWhitelist -> fix config.js on the server, not client code\n  console.error('Access blocked; add this device IP to ipWhitelist in config.js', e);\n}","preventionTips":["Log the exact IP string the server sees (from `IP ... is not allowed`) and whitelist that literal, including the ::ffff: prefix","Always list both IPv4 and IPv6-mapped forms for each allowed device","Use `ipWhitelist: []` for trusted LANs to eliminate this class of failure","When behind a reverse proxy, configure Express `trust proxy` and whitelist accordingly","After changing ipWhitelist, restart the MagicMirror process — the config is read at startup"],"tags":["http-403","ip-whitelist","access-control","configuration"],"backgroundTag":"ip-whitelist-rejected","analyzedSha":"4b4a59534f7da01e4030e46029fe9dd649a7675e","analyzedAt":"2026-08-31T21:49:42.591Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}