{"record":{"id":"411991175265039e","repo":"louislam/dockge","slug":"the-token-is-invalid-due-to-password-change-or-old","errorCode":null,"errorMessage":"The token is invalid due to password change or old token","messagePattern":"The token is invalid due to password change or old token","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"backend/socket-handlers/main-socket-handler.ts","lineNumber":83,"sourceCode":"        // Login by token\n        socket.on(\"loginByToken\", async (token, callback) => {\n            const clientIP = await server.getClientIP(socket);\n\n            log.info(\"auth\", `Login by token. IP=${clientIP}`);\n\n            try {\n                const decoded = jwt.verify(token, server.jwtSecret) as JWTDecoded;\n\n                log.info(\"auth\", \"Username from JWT: \" + decoded.username);\n\n                const user = await R.findOne(\"user\", \" username = ? AND active = 1 \", [\n                    decoded.username,\n                ]) as User;\n\n                if (user) {\n                    // Check if the password changed\n                    if (decoded.h !== shake256(user.password, SHAKE256_LENGTH)) {\n                        throw new Error(\"The token is invalid due to password change or old token\");\n                    }\n\n                    log.debug(\"auth\", \"afterLogin\");\n                    await server.afterLogin(socket, user);\n                    log.debug(\"auth\", \"afterLogin ok\");\n\n                    log.info(\"auth\", `Successfully logged in user ${decoded.username}. IP=${clientIP}`);\n\n                    callback({\n                        ok: true,\n                    });\n                } else {\n\n                    log.info(\"auth\", `Inactive or deleted user ${decoded.username}. IP=${clientIP}`);\n\n                    callback({\n                        ok: false,\n                        msg: \"authUserInactiveOrDeleted\",","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/louislam/dockge/blob/f809ae192b571944ad773e9866d3e67064ae8043/backend/socket-handlers/main-socket-handler.ts#L65-L101","documentation":"During JWT-based auto-login (the 'loginByToken' socket event), the decoded token carries an 'h' field: a shake256 hash of the user's password hash at token-issue time. If the stored password hash no longer matches (the password was changed or the token is stale from a previous incarnation), the handler throws this Error so the client is forced to re-authenticate with credentials.","triggerScenarios":"Emitting 'loginByToken' with a JWT minted before a password change, or a token persisted from an earlier Dockge install/database where the user's password hash differed.","commonSituations":"Browser keeps a saved token while the admin rotates the password; restoring an old database while clients retain old tokens; token copied from another environment with different password hashes.","solutions":["Discard the stored token and log in again with username/password to obtain a fresh JWT.","If the password was intentionally changed, no repair is needed — the old token is invalid by design.","Clear client-side token storage (localStorage/cookie) when handling this error."],"exampleFix":"// before\nsocket.emit('loginByToken', savedToken, cb); // may throw\n// after\nsocket.emit('loginByToken', savedToken, (res) => {\n    if (!res.ok) localStorage.removeItem('token');\n});","handlingStrategy":"fallback","validationCode":"// Detect stale token by decoding expiry locally before use\nfunction tokenLooksValid(token) {\n    try {\n        const payload = JSON.parse(atob(token.split('.')[1]));\n        return payload.exp * 1000 > Date.now();\n    } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"socket.emit('loginByToken', token, (res) => {\n    if (!res.ok && /invalid/.test(res.msg || '')) {\n        localStorage.removeItem('token');\n        showLoginForm();\n    }\n});","preventionTips":["Clear stored tokens after any password change","Re-authenticate with credentials when token login fails","Avoid reusing tokens across environments or restored databases"],"tags":["jwt","authentication","token","password-change"],"backgroundTag":"jwt-token-invalidated","analyzedSha":"f809ae192b571944ad773e9866d3e67064ae8043","analyzedAt":"2026-08-31T19:13:50.919Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}