Async HTTP/1.1 client whose TLS handshake is identical to the `requests` library.
Project description
async-requests-tls
Async Python HTTP/1.1 client whose TLS ClientHello is byte-for-byte
identical to what the requests
library sends — same JA3, same JA4. Useful when a site fingerprints the TLS
handshake and rejects modern async clients (httpx, niquests, …) while
happily accepting plain requests.
The trick: requests builds its ssl.SSLContext through
urllib3.util.ssl_.create_urllib3_context(). So do we. The context is then
fed into asyncio.open_connection(..., ssl=ctx), so both stacks drive the
same OpenSSL build with the same cipher list, options, ALPN, curves, and
sigalgs.
Install
pip install async-requests-tls
# or with uv:
uv add async-requests-tls
The PyPI distribution name is
async-requests-tlsbut the Python import name isasync_requests_tls.
For development from a clone of this repo:
pip install -e .[dev]
# or:
uv sync --extra dev
Requires Python 3.13+ and urllib3>=2.0.
Quickstart
import asyncio
from async_requests_tls import AsyncSession
async def main():
async with AsyncSession() as s:
# GET
r = await s.get("https://httpbin.org/get", params={"hello": "world"})
print(r.status_code, r.json())
# POST with JSON
r = await s.post("https://httpbin.org/post", json={"x": 1})
print(r.json())
# Session-wide base_url, headers, and cookie jar
async with AsyncSession(
base_url="https://api.example.com",
headers={"X-Token": "secret"},
) as api:
await api.get("/users") # GET https://api.example.com/users
await api.post("/orders", data={"sku": "abc"})
asyncio.run(main())
AsyncSession supports get / post / put / patch / delete /
head / options, with a requests-style API: params, headers,
data, json, cookies, allow_redirects. Responses expose
status_code, headers, content, text, json(), ok, and
cookies.
Caveats
- HTTP/1.1 only. ALPN defaults to
["http/1.1"]so the server never upgrades us to h2. If you passalpn=alpn_protocols_like_urllib3()(to match the exact ALPN bytesrequestssends when urllib3-future is installed) and the server picksh2, the session raisesNotImplementedError— the TLS handshake still matched, the wire protocol did not. - No connection pooling, no proxies, no streaming, no multipart, no HTTP/2. This is a small, focused library.
- JA3 parity ≠ detection-evasion parity. Modern detectors also look at HTTP/2 SETTINGS frames, header order (JA4_H), and Akamai-style timing. This library only matches the TLS layer.
Testing
uv run pytest # or: pytest
All tests are unit tests — they don't open real sockets. The wire-level
tests drive asyncio.StreamReader with canned bytes; the session tests
patch _send_once with a fake.
Public API
from async_requests_tls import (
AsyncSession,
Response,
build_ssl_context, # if you want the SSLContext directly
alpn_protocols_like_urllib3, # exact ALPN list urllib3 would send
)
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file async_requests_tls-0.1.0.tar.gz.
File metadata
- Download URL: async_requests_tls-0.1.0.tar.gz
- Upload date:
- Size: 16.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b248cf0f9aa726d7a92173eb585cb467ec561c252088a6099516a544023754b1
|
|
| MD5 |
fd7137bdbdebcae88823f3abdbc879c4
|
|
| BLAKE2b-256 |
02b644fd89894889e9d4edb607bd8d342eb29ad9610cceb1168b0e0853b4d2a3
|
File details
Details for the file async_requests_tls-0.1.0-py3-none-any.whl.
File metadata
- Download URL: async_requests_tls-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
accd43546258a371227a1a313fa74ebb5fb60735f131b0781b80463d7c664dba
|
|
| MD5 |
b51b4c4a30a3919bea9c96de35baaa69
|
|
| BLAKE2b-256 |
a4a1ed4d7aeb7bf86d27e24ce6e6eccc6a1ee9fd042cd4dffee68ab6ff05ebb0
|