{"record":{"id":"35a8efa2152720ed","repo":"flarum/framework","slug":"invalid-auth-signature-provided","errorCode":null,"errorMessage":"Invalid auth signature provided.","messagePattern":"Invalid auth signature provided\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"extensions/realtime/src/Websocket/Connection/Controller.php","lineNumber":147,"sourceCode":"        $params = Arr::except($request->getQueryParams(), [\n            'auth_signature', 'body_md5', 'appId', 'appKey', 'channelName',\n        ]);\n\n        if ($this->buffer !== '') {\n            $params['body_md5'] = md5($this->buffer);\n        }\n\n        ksort($params);\n\n        $signature = \"{$request->getMethod()}\\n{$request->getUri()->getPath()}\\n\".Pusher::array_implode('=', '&', $params);\n\n        /** @var SocketSettings $settings */\n        $settings = resolve(SocketSettings::class);\n\n        $authSignature = hash_hmac('sha256', $signature, $settings->appSecret);\n\n        if ($authSignature !== $request->getQueryParams()['auth_signature']) {\n            throw new Exception('Invalid auth signature provided.');\n        }\n    }\n\n    protected function sendAndClose(ConnectionInterface $conn, mixed $response): void\n    {\n        if ($response instanceof Collection) {\n            $response = new JsonResponse($response->toArray());\n        }\n        if (is_array($response)) {\n            $response = new JsonResponse($response);\n        }\n        if (! ($response instanceof Response)) {\n            $response = new Response($response);\n        }\n\n        $conn->send(Message::toString($response));\n        $conn->close();\n    }","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/flarum/framework/blob/4b939f685389bfe8a380e9e28ddf305a1c66950c/extensions/realtime/src/Websocket/Connection/Controller.php#L129-L165","documentation":"The realtime websocket controller validates the client's signature by computing hash_hmac('sha256', signature, appSecret) and comparing it to the auth_signature query param; any mismatch throws an Exception with 'Invalid auth signature provided.'","triggerScenarios":"A websocket connection request (handleRequest -> validateSignature) whose auth_signature query parameter is missing, truncated, URL-encoded incorrectly, or computed with a different key than the configured appSecret.","commonSituations":"Client and server using different app secrets (stale config or multi-instance mismatch); client hashing the wrong payload or using plain secret comparison; query param mangled by proxies; clock/nonce handling changes between client versions.","solutions":["Regenerate the client signature as hash_hmac('sha256', signature, appSecret) using the same secret as the server's SocketSettings.","Ensure the server's configured app secret matches the one distributed to clients (sync config across instances).","Log the computed vs received auth_signature server-side (carefully, without leaking secrets) to compare values.","Check that the auth_signature query parameter survives URL encoding and proxying intact.","Update clients after any secret rotation and retry the connection."],"exampleFix":"// before\nconst sig = crypto.createHash('sha256').update(payload).digest('hex');\n// after\nconst sig = crypto.createHmac('sha256', appSecret).update(signature).digest('hex');","handlingStrategy":"try-catch","validationCode":"const expected = crypto.createHmac('sha256', appSecret).update(signature).digest('hex'); if (expected !== authSignature) { /* abort before connecting */ }","typeGuard":null,"tryCatchPattern":"try { validateSignature($request); } catch (Exception $e) { // close connection with 401-style error; log mismatch without leaking secrets }","preventionTips":["Share the app secret through one config source across client and server","Use HMAC of the signature payload, not a plain hash","URL-encode query params properly when connecting","Rotate secrets atomically across all instances"],"tags":["authentication","signature","hmac","websocket"],"backgroundTag":"checksum-mismatch","analyzedSha":"4b939f685389bfe8a380e9e28ddf305a1c66950c","analyzedAt":"2026-09-15T18:09:20.879Z","contentChangedAt":"2026-09-15T18:09:20.879Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}