# How Hydrus Networking Sessions Handle Cookies and Authentication

> Discover how Hydrus networking sessions manage cookies and authentication using access keys and session cookies for secure, persistent connections. Learn about client-side cleanup and server account resolution.

- Repository: [Hydrus Network Developer/hydrus](https://github.com/hydrusnetwork/hydrus)
- Tags: internals
- Published: 2026-03-03

---

**Hydrus networking sessions implement a two-layer authentication system where a static access key generates a temporary session_key cookie for session persistence, with the NetworkSessionManager handling client-side cookie cleanup and the server resolving cookies to accounts via _callbackEstablishAccountFromHeader.**

Hydrus is a personal media library application with a client-server architecture that relies heavily on its networking layer for both local API access and external site scraping. The **Hydrus networking sessions** system provides the backbone for stateful HTTP communication, managing everything from session token generation to automatic cleanup of expired cookies. Understanding this architecture is essential for developers extending the platform or troubleshooting authentication failures.

## Server-Side Session Creation and Cookie Issuance

In [`hydrus/server/networking/ServerServerResources.py`](https://github.com/hydrusnetwork/hydrus/blob/main/hydrus/server/networking/ServerServerResources.py), the `HydrusResourceSessionKey` class handles the initial authentication handshake. When a client presents a valid access key, the server generates a 32-byte random session key and returns it as an HTTP cookie.

```python

# ServerServerResources.py – lines 93-106

session_key, expires = SG.server_controller.server_session_manager.AddSession(self._service_key, access_key)
now = HydrusTime.GetNow()
max_age = expires - now
cookies = [('session_key', session_key.hex(),
           {'max_age': str(max_age), 'path': '/'})]
response_context = HydrusServerResources.ResponseContext(200, cookies=cookies)

```

The `HydrusSessionManagerServer` class (defined in [`hydrus/core/HydrusSessions.py`](https://github.com/hydrusnetwork/hydrus/blob/main/hydrus/core/HydrusSessions.py)) stores the session key with an expiration timestamp, typically defaulting to 30 days. The response includes a `Set-Cookie` header with the calculated `max_age` and a path of `/`, ensuring the cookie applies to all subsequent requests to the domain.

## Server-Side Cookie-Based Authentication

All restricted API endpoints inherit from `HydrusResourceRestricted`, which relies on `_callbackEstablishAccountFromHeader` to resolve incoming requests to specific user accounts. This method first inspects the `Cookie` header for a `session_key` value before falling back to the static access key.

```python

# ServerServerResources.py – lines 225-260

session_key = None
if request.requestHeaders.hasHeader('Cookie'):
    cookie_texts = request.requestHeaders.getRawHeaders('Cookie')
    cookie_text = cookie_texts[0]
    cookies = http.cookies.SimpleCookie(cookie_text)
    if 'session_key' in cookies:
        morsel = cookies['session_key']
        session_key = bytes.fromhex(morsel.value)

if session_key is None:
    # No cookie → try access_key header

    access_key = self._parseHydrusNetworkAccessKey(request, key_required=False)
    ...
else:
    account = SG.server_controller.server_session_manager.GetAccount(self._service_key, session_key)

```

If the `session_key` cookie is present and valid, `HydrusSessionManagerServer.GetAccount` resolves it to the corresponding account object. If the cookie is malformed, the server raises `HydrusExceptions.BadRequestException`; if the session has expired, it raises `HydrusExceptions.SessionException`, which translates to a 401 HTTP response.

## Client-Side Session Management and Cookie Storage

The Hydrus client maintains persistent HTTP state using `requests.Session` objects encapsulated within `NetworkSessionManagerSessionContainer` classes, as implemented in [`hydrus/client/networking/ClientNetworkingSessions.py`](https://github.com/hydrusnetwork/hydrus/blob/main/hydrus/client/networking/ClientNetworkingSessions.py).

### Session Container Architecture

Each network context (global, per-domain, or per-Hydrus-service) receives its own session container. For local Hydrus server connections, the system disables SSL verification to accommodate self-signed certificates.

```python

# ClientNetworkingSessions.py – lines 52-60

self.session = requests.Session()
if self.network_context.context_type == CC.NETWORK_CONTEXT_HYDRUS:
    self.session.verify = False      # self-signed certs for local server

```

### Automatic Cookie Cleanup

The `NetworkSessionManager` periodically purges transient cookies to prevent memory bloat and security leakage. During the `PrepareForNewWork` cycle, it clears both session-only cookies (those without explicit expiration dates) and expired cookies based on their timestamps.

```python

# ClientNetworkingSessions.py – lines 56-63 (PrepareForNewWork)

my_session_cookies = self.session.cookies
if HydrusTime.TimeHasPassed(self.last_touched_time + self.SESSION_TIMEOUT):
    my_session_cookies.clear_session_cookies()
my_session_cookies.clear_expired_cookies()

```

### Database Persistence of Cookies

When the client persists its state to the database, the `NetworkSessionManager` serializes the cookie jar using Python's `pickle` module. To prevent stale session data from persisting across restarts, the system explicitly clears session-only cookies before serialization.

```python

# ClientNetworkingSessions.py – lines 62-70 (_GetSerialisableInfo)

self.session.cookies.clear_session_cookies()
pickled_cookies_hex = pickle.dumps(self.session.cookies).hex()
return (serialisable_network_context, pickled_cookies_hex)

```

On application restart, the client restores the pickled cookie jar and immediately clears session-only cookies again, ensuring no ephemeral authentication tokens survive between sessions.

## Public Cookie Management API

Hydrus exposes a local server API for external scripts to inspect and manipulate the client's cookie store for arbitrary domains. Implemented in [`hydrus/client/networking/api/ClientLocalServerResourcesManageCookies.py`](https://github.com/hydrusnetwork/hydrus/blob/main/hydrus/client/networking/api/ClientLocalServerResourcesManageCookies.py), this interface provides endpoints for reading and writing cookies without direct database access.

To retrieve cookies for a specific domain, the `HydrusResourceClientAPIRestrictedManageCookiesGetCookies` class iterates through the session's cookie jar:

```python

# ClientLocalServerResourcesManageCookies.py – lines 41-58 (GET)

for cookie in session.cookies:
    body_cookies_list.append([cookie.name, cookie.value,
                              cookie.domain, cookie.path,
                              cookie.expires])

```

To set or delete cookies, the `HydrusResourceClientAPIRestrictedManageCookiesSetCookies` class validates incoming cookie rows and updates the jar accordingly:

```python

# ... lines 76-102 (POST)

for cookie_row in cookie_rows:
    if len(cookie_row) != 5: raise BadRequestException(...)
    name, value, domain, path, expires = cookie_row
    if value is None:
        session.cookies.clear(domain, path, name)
    else:
        session.cookies.set(name, value, domain=domain,
                           path=path, expires=expires)

```

## Practical Authentication Flow Example

Below is a complete Python example demonstrating the authentication flow: exchanging an access key for a session cookie, then using that cookie for authenticated requests.

```python
import requests
from urllib.parse import urljoin

BASE = 'http://localhost:45871/'          # local Hydrus server

SESSION_ENDPOINT = urljoin(BASE, 'session_key')
DATA_ENDPOINT = urljoin(BASE, 'some/restricted/resource')

# 1️⃣  Obtain an access key (pre-generated by the server)

access_key = b'YOUR_ACCESS_KEY'          # bytes, not hex-encoded

# 2️⃣  Exchange for a session cookie

resp = requests.get(
    SESSION_ENDPOINT, 
    headers={'Hydrus-Access-Key': access_key.hex()}
)
resp.raise_for_status()

# Store the session_key cookie for subsequent requests

session = requests.Session()
session.cookies.update(resp.cookies)

# 3️⃣  Make an authenticated request (cookie sent automatically)

resp = session.get(DATA_ENDPOINT)
print(resp.json())

```

Alternatively, scripts that do not maintain cookie state can continue using the `Hydrus-Access-Key` header on every request; the server automatically falls back to this method when the `session_key` cookie is absent, as shown in the `_callbackEstablishAccountFromHeader` logic.

## Summary

- **Hydrus networking sessions** use a two-tier authentication model: a static **access key** creates a temporary **session_key** cookie that maintains state for subsequent requests.
- The server resolves cookies to accounts through [`hydrus/server/networking/ServerServerResources.py`](https://github.com/hydrusnetwork/hydrus/blob/main/hydrus/server/networking/ServerServerResources.py), specifically within the `_callbackEstablishAccountFromHeader` method.
- Client-side cookie hygiene is enforced by `NetworkSessionManager` in [`hydrus/client/networking/ClientNetworkingSessions.py`](https://github.com/hydrusnetwork/hydrus/blob/main/hydrus/client/networking/ClientNetworkingSessions.py), which automatically clears expired and session-only cookies both in memory and during database serialization.
- A **public REST API** at `/manage_cookies/*` allows external scripts to query and modify domain-specific cookies, enabling custom login flows for third-party sites.
- Login scripts in [`hydrus/client/networking/ClientNetworkingLogin.py`](https://github.com/hydrusnetwork/hydrus/blob/main/hydrus/client/networking/ClientNetworkingLogin.py) verify successful authentication by checking for the presence of valid `session_key` cookies in the session jar.

## Frequently Asked Questions

### How long do Hydrus session cookies last?

By default, session cookies generated by `HydrusResourceSessionKey` expire after 30 days. The server calculates the `max_age` parameter dynamically based on the difference between the current time and the expiration timestamp stored in `HydrusSessionManagerServer`. Clients can force earlier expiration by clearing cookies manually through the API or GUI.

### Can I use Hydrus networking sessions without cookies?

Yes. While the preferred method uses the `session_key` cookie for stateful sessions, the server accepts a `Hydrus-Access-Key` header on every request as a fallback. In [`ServerServerResources.py`](https://github.com/hydrusnetwork/hydrus/blob/main/ServerServerResources.py), the `_callbackEstablishAccountFromHeader` method checks for the access key header whenever the session cookie is missing or invalid, allowing stateless clients to authenticate each request independently.

### How does Hydrus handle expired or invalid session cookies?

When the server encounters an expired session key, `HydrusSessionManagerServer.GetAccount` raises `HydrusExceptions.SessionException`, which translates to a 401 Unauthorized HTTP response. Malformed cookie syntax triggers `HydrusExceptions.BadRequestException`. On the client side, `NetworkSessionManager` proactively removes expired cookies via `clear_expired_cookies()` before each request cycle, preventing the transmission of stale authentication tokens.

### Where does Hydrus store cookies between application restarts?

The client serializes the `requests.Session` cookie jar to the SQLite database using Python's `pickle` module. In [`ClientNetworkingSessions.py`](https://github.com/hydrusnetwork/hydrus/blob/main/ClientNetworkingSessions.py), the `_GetSerialisableInfo` method converts the cookie jar to a hexadecimal string after first purging session-only cookies. During application startup, the system restores these cookies and immediately clears any residual session-only entries to ensure a clean state.