{"id":"3dd888deb00e2af6","repo":"aio-libs/aiohttp","slug":"digest-auth-error-unsupported-quality-of-protecti","errorCode":null,"errorMessage":"Digest auth error: Unsupported Quality of Protection (qop) value(s): {qop_raw}","messagePattern":"Digest auth error: Unsupported Quality of Protection \\(qop\\) value\\(s\\): (.+?)","errorType":"exception","errorClass":"ClientError","httpStatus":null,"severity":"error","filePath":"aiohttp/client_middleware_digest_auth.py","lineNumber":285,"sourceCode":"\n        # Convert string values to bytes once\n        nonce_bytes = nonce.encode(\"utf-8\")\n        realm_bytes = realm.encode(\"utf-8\")\n        # Use the encoded request-target (raw_path_qs) since that is what is\n        # transmitted on the wire and what the server signs against. Using the\n        # decoded form would cause digest verification to fail when the path\n        # or query string contains percent-encoded reserved characters.\n        path = URL(url).raw_path_qs\n\n        # Process QoP\n        qop = \"\"\n        qop_bytes = b\"\"\n        if qop_raw:\n            valid_qops = {\"auth\", \"auth-int\"}.intersection(\n                {q.strip() for q in qop_raw.split(\",\") if q.strip()}\n            )\n            if not valid_qops:\n                raise ClientError(\n                    f\"Digest auth error: Unsupported Quality of Protection (qop) value(s): {qop_raw}\"\n                )\n\n            qop = \"auth-int\" if \"auth-int\" in valid_qops else \"auth\"\n            qop_bytes = qop.encode(\"utf-8\")\n\n        if algorithm not in DigestFunctions:\n            raise ClientError(\n                f\"Digest auth error: Unsupported hash algorithm: {algorithm}. \"\n                f\"Supported algorithms: {', '.join(SUPPORTED_ALGORITHMS)}\"\n            )\n        hash_fn: Final = DigestFunctions[algorithm]\n\n        def H(x: bytes) -> bytes:\n            \"\"\"RFC 7616 Section 3: Hash function H(data) = hex(hash(data)).\"\"\"\n            return hash_fn(x).hexdigest().encode()\n\n        def KD(s: bytes, d: bytes) -> bytes:","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/client_middleware_digest_auth.py#L267-L303","documentation":"Raised as a ClientError when a Digest auth challenge includes a 'qop' (Quality of Protection) parameter whose token list contains no value aiohttp can negotiate. aiohttp only implements 'auth' and 'auth-int' (RFC 2617/7616); if the server advertises only unsupported tokens (or unparseable garbage), the client cannot compute the response digest correctly and refuses rather than send an unauthenticated-looking request.","triggerScenarios":"Fires at line 284-287 after intersecting the server's qop token set with {\"auth\",\"auth-int\"} yields an empty set. Common when the server sends qop values like \"auth-conf\", proprietary tokens, or malformed comma-separated lists.","commonSituations":"Server configured for qop=auth-conf (confidentiality, which aiohttp doesn't implement); legacy Microsoft IIS or custom DAV servers using non-standard qop tokens; typos in server config.","solutions":["Reconfigure the server to advertise qop=\"auth\" (most widely supported) instead of auth-conf or custom values.","If the server only supports auth-conf, use a different HTTP client that implements it, or tunnel via TLS and disable qop server-side.","Confirm the exact WWW-Authenticate header the server emits and verify qop parsing."],"exampleFix":"# server config (nginx example) - before:\n# auth_basic_user_file ... ; (digest module emitting qop=auth-conf)\n# after: configure digest module to qop=auth","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"from aiohttp import ClientError\ntry:\n    resp = await session.get(url, auth=DigestAuth(login, pwd))\nexcept ClientError as e:\n    if \"Unsupported Quality of Protection\" in str(e):\n        # negotiate a non-digest auth path or report server misconfig","preventionTips":["Confirm server qop advertises 'auth' before relying on digest auth.","Capture the WWW-Authenticate header in logs to diagnose qop mismatches.","Maintain a known-good server config snippet for digest auth (qop=auth, algorithm=SHA-256)."],"tags":["auth","digest-auth","http-client","configuration"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}