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."""

Reply via email to