This is an automated email from the ASF dual-hosted git repository.
vincbeck pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 7c50c50923e Fix session cookie serialization when using securecookie
backend (#66565)
7c50c50923e is described below
commit 7c50c50923eac3adc52062a15dd6e0cf4e71af9e
Author: EthanL <[email protected]>
AuthorDate: Fri May 8 16:56:42 2026 -0400
Fix session cookie serialization when using securecookie backend (#66565)
When `session_backend = securecookie`, `AirflowSecureCookieSessionInterface`
inherits a custom `_LazySafeSerializer` via `SessionExemptMixin.__init__`,
which overrides `self.serializer` with a msgpack-based serializer that
returns bytes.
Flask's `SecureCookieSessionInterface.get_signing_serializer()` passes
`self.serializer` to `itsdangerous.URLSafeTimedSerializer`. The signed
cookie value eventually reaches Werkzeug's `dump_cookie`, which expects
a string, causing:
TypeError: cannot use a string pattern on a bytes-like object
The custom `_LazySafeSerializer` was designed for the database session
interface where the `data` column is `LargeBinary` and needs bytes.
The cookie interface doesn't need it — Flask's default serializer
handles cookies correctly.
Move the custom serializer assignment from the shared `SessionExemptMixin`
into `AirflowDatabaseSessionInterface.__init__` only, so the cookie
interface uses Flask's built-in serializer.
---
providers/fab/src/airflow/providers/fab/www/session.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/providers/fab/src/airflow/providers/fab/www/session.py
b/providers/fab/src/airflow/providers/fab/www/session.py
index d6c52c4498e..1e39586a072 100644
--- a/providers/fab/src/airflow/providers/fab/www/session.py
+++ b/providers/fab/src/airflow/providers/fab/www/session.py
@@ -24,6 +24,12 @@ from flask_session.sqlalchemy import
SqlAlchemySessionInterface
class _LazySafeSerializer:
+ """
+ Serializer that handles LazyString and uses msgpack for efficient storage.
+
+ Returns bytes (suitable for database BLOB columns).
+ """
+
def dumps(self, session_dict):
encoder = msgspec.msgpack.Encoder(
enc_hook=lambda obj: str(obj) if isinstance(obj, LazyString) else
obj
@@ -42,10 +48,6 @@ class _LazySafeSerializer:
class SessionExemptMixin:
"""Exempt certain blueprints/paths from autogenerated sessions."""
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.serializer = _LazySafeSerializer()
-
def save_session(self, *args, **kwargs):
"""Prevent creating session from REST API and health requests."""
if request.path == "/health":
@@ -56,6 +58,10 @@ class SessionExemptMixin:
class AirflowDatabaseSessionInterface(SessionExemptMixin,
SqlAlchemySessionInterface):
"""Session interface that exempts some routes and stores session data in
the database."""
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.serializer = _LazySafeSerializer()
+
class AirflowSecureCookieSessionInterface(SessionExemptMixin,
SecureCookieSessionInterface):
"""Session interface that exempts some routes and stores session data in a
signed cookie."""