{"record":{"id":"beb984c6995c79a0","repo":"aio-libs/aiohttp","slug":"a-is-not-allowed-in-login-rfc-7617-section-2","errorCode":null,"errorMessage":"A \":\" is not allowed in login (RFC 7617#section-2)","messagePattern":"A \":\" is not allowed in login \\(RFC 7617#section-2\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/helpers.py","lineNumber":167,"sourceCode":"    \"{\",\n    \"}\",\n    \" \",\n    chr(9),\n}\nTOKEN = CHAR ^ CTL ^ SEPARATORS\n\n\njson_re = re.compile(r\"^(?:application/|[\\w.-]+/[\\w.+-]+?\\+)json$\", re.IGNORECASE)\n\n\ndef encode_basic_auth(login: str, password: str = \"\", encoding: str = \"utf-8\") -> str:\n    \"\"\"Encode HTTP Basic Authentication credentials as an Authorization header value.\n\n    Returns a string of the form ``\"Basic <base64>\"`` suitable for use as the\n    value of the ``Authorization`` (or ``Proxy-Authorization``) header.\n    \"\"\"\n    if \":\" in login:\n        raise ValueError('A \":\" is not allowed in login (RFC 7617#section-2)')\n    creds = f\"{login}:{password}\".encode(encoding)\n    return \"Basic \" + base64.b64encode(creds).decode(encoding)\n\n\ndef strip_auth_from_url(url: URL) -> tuple[URL, str | None]:\n    \"\"\"Strip user/password from a URL and return the Authorization header value.\n\n    Returns a tuple of ``(url_without_credentials, authorization_header_value)``.\n    The header value is ``None`` if no credentials were present.\n    \"\"\"\n    # Check raw_user and raw_password first as yarl is likely\n    # to already have these values parsed from the netloc in the cache.\n    if url.raw_user is None and url.raw_password is None:\n        return url, None\n    return url.with_user(None), encode_basic_auth(url.user or \"\", url.password or \"\")\n\n\ndef netrc_from_env() -> netrc.netrc | None:","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/helpers.py#L149-L185","documentation":"encode_basic_auth raises ValueError when the login (username) string contains a colon character. Per RFC 7617 Section 2, the colon is the delimiter between userid and password in the Basic credentials, so it cannot appear in the userid itself. This is a hard validation, not a warning.","triggerScenarios":"Calling aiohttp.helpers.encode_basic_auth(login='user:name', password='secret'), or providing a URL with userinfo like http://user:name@host/. Also triggered indirectly when aiohttp encodes credentials from a URL or from BasicAuth(login, password) where login contains ':'.","commonSituations":"Email addresses used as usernames ('user@example.com' is fine, but 'user:name' is not); Active Directory UPN with colons; copy-pasted credentials from a config that uses colon-delimited format; URLs with encoded or raw colons in the userinfo component.","solutions":["Remove or replace the colon in the login: use a sanitized username","URL-encode the colon in the userinfo: replace ':' with '%3A' in the URL (yarl may handle this)","Pass credentials via the auth parameter instead of embedding in the URL: ClientSession(auth=BasicAuth('user', 'pass'))"],"exampleFix":"# before\nawait session.get('http://user:name@host/api')\n\n# after\nfrom aiohttp import BasicAuth\nawait session.get('http://host/api', auth=BasicAuth('user', 'password'))","handlingStrategy":"validation","validationCode":"def safe_basic_auth(login, password='', encoding='utf-8'):\n    if ':' in login:\n        raise ValueError(f'Login contains illegal colon: {login!r}')\n    from aiohttp.helpers import encode_basic_auth\n    return encode_basic_auth(login, password, encoding)","typeGuard":"def is_valid_basic_auth_login(login: str) -> bool:\n    return isinstance(login, str) and ':' not in login","tryCatchPattern":"try:\n    from aiohttp.helpers import encode_basic_auth\n    header = encode_basic_auth(login, password)\nexcept ValueError as e:\n    if 'not allowed in login' in str(e):\n        login = login.replace(':', '')\n        header = encode_basic_auth(login, password)\n    raise","preventionTips":["Validate usernames for colon characters before constructing auth","Prefer the auth= parameter over embedding credentials in URLs","Sanitize credentials from external sources before passing to BasicAuth"],"tags":["authentication","basic-auth","validation","rfc-7617"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}