{"record":{"id":"f7872ae8420bf501","repo":"rathole-org/rathole","slug":"service-failed-the-authentication","errorCode":null,"errorMessage":"Service {} failed the authentication","messagePattern":"Service (.+?) failed the authentication","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/server.rs","lineNumber":330,"sourceCode":"\n    // Calculate the checksum\n    let mut concat = Vec::from(service_config.token.as_ref().unwrap().as_bytes());\n    concat.append(&mut nonce);\n\n    // Read auth\n    let protocol::Auth(d) = read_auth(&mut conn).await?;\n\n    // Validate\n    let session_key = protocol::digest(&concat);\n    if session_key != d {\n        conn.write_all(&bincode::serialize(&Ack::AuthFailed).unwrap())\n            .await?;\n        debug!(\n            \"Expect {}, but got {}\",\n            hex::encode(session_key),\n            hex::encode(d)\n        );\n        bail!(\"Service {} failed the authentication\", service_name);\n    } else {\n        let mut h = control_channels.write().await;\n\n        // If there's already a control channel for the service, then drop the old one.\n        // Because a control channel doesn't report back when it's dead,\n        // the handle in the map could be stall, dropping the old handle enables\n        // the client to reconnect.\n        if h.remove1(&service_digest).is_some() {\n            warn!(\n                \"Dropping previous control channel for service {}\",\n                service_name\n            );\n        }\n\n        // Send ack\n        conn.write_all(&bincode::serialize(&Ack::Ok).unwrap())\n            .await?;\n        conn.flush().await?;","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/rathole-org/rathole/blob/a292f7ed5402f840415fc6a53827da2f34337856/src/server.rs#L312-L348","documentation":"Fires in do_control_channel_handshake when the client's Auth payload does not equal protocol::digest(service_token || nonce). The server computes the expected session key from the service's token plus the nonce it sent, and the client's response mismatched, so the client does not possess the service token. The server writes Ack::AuthFailed and fails the handshake; this is the authentication step for the control channel, not a transport failure.","triggerScenarios":"Thrown at src/server.rs:330 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Ensure the client's service token matches the server's configured token for that service (it must not be None)","Check for clock/nonce corruption or protocol version mismatch between client and server","Use the debug! hex output to compare expected vs received digests when debugging","Rotate tokens consistently on both sides after any config change"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"a292f7ed5402f840415fc6a53827da2f34337856","analyzedAt":"2026-09-07T09:56:55.739Z","contentChangedAt":"2026-09-07T09:56:55.739Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}