From f93d0425aa28a44b15bfc6e35db76f545afb9a4f Mon Sep 17 00:00:00 2001
From: Bugra Ozturk <ozturkbugra93@gmail.com>
Date: Wed, 6 Aug 2025 22:21:39 +0200
Subject: [PATCH 1/6] feat(doc): Add Refresh Token logic to auth manager docs

---
 .../docs/core-concepts/auth-manager/index.rst | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/airflow-core/docs/core-concepts/auth-manager/index.rst b/airflow-core/docs/core-concepts/auth-manager/index.rst
index d48828a1b2637..e585d89a3c41a 100644
--- a/airflow-core/docs/core-concepts/auth-manager/index.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/index.rst
@@ -172,6 +172,39 @@ cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI wil
 .. note::
     Do not set the cookie parameter ``httponly`` to ``True``. Airflow UI needs to access the JWT token from the cookie.
 
+Refreshing JWT Token
+''''''''''''''''''''
+The refresh token endpoint is ``POST /auth/token/refresh`` with the current JWT token in the cookie or acquired from the API.
+This endpoint is used to refresh the JWT token when it is about to expire.
+The auth manager should implement this endpoint to allow the Airflow UI/API to refresh the JWT token.
+If the auth manager does not implement this endpoint, the Airflow UI/API will not be able to refresh the JWT token.
+The user will be logged out when the JWT token expires in that case, and they will have to log in again.
+
+This procedure is following the same pattern as the initial token generation endpoints and login/logout logic.
+A typical implementation of the refresh token endpoint would look like this:
+
+
+.. code-block:: python
+
+    @router.post("/auth/token/refresh")
+    def refresh_token(
+        request: Request,
+        user: T = Depends(get_current_user),
+    ) -> TokenResponse:
+        """
+        Refresh the JWT token for the current user.
+        """
+        # Generate a new token for the user
+        new_token = auth_manager.generate_token(user)  # Or similar with calling the client from auth manager
+
+        # Set the new token in the cookie
+        secure = request.base_url.scheme == "https" or bool(conf.get("api", "ssl_cert", fallback=""))
+        response = RedirectResponse(url="/")
+        response.set_cookie(COOKIE_NAME_JWT_TOKEN, new_token, secure=secure)
+
+        return response
+.. note::
+    Do not set the cookie parameter ``httponly`` to ``True``. Airflow UI needs to access the JWT token from the cookie.
 
 Optional methods recommended to override for optimization
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

From c1457e1aadbdebdf8f9f1084fd33482b7f6994be Mon Sep 17 00:00:00 2001
From: Bugra Ozturk <ozturkbugra93@gmail.com>
Date: Fri, 8 Aug 2025 01:51:56 +0200
Subject: [PATCH 2/6] feat(doc): make sentences more understandable

---
 airflow-core/docs/core-concepts/auth-manager/index.rst | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/airflow-core/docs/core-concepts/auth-manager/index.rst b/airflow-core/docs/core-concepts/auth-manager/index.rst
index e585d89a3c41a..e7f0658f9a33f 100644
--- a/airflow-core/docs/core-concepts/auth-manager/index.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/index.rst
@@ -174,7 +174,8 @@ cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI wil
 
 Refreshing JWT Token
 ''''''''''''''''''''
-The refresh token endpoint is ``POST /auth/token/refresh`` with the current JWT token in the cookie or acquired from the API.
+The refresh token ``<METHOD> <PATH>`` is ``POST /auth/token/refresh``. It returns a new JWT token in the cookie where updated token is stored.
+It requires the user to be authenticated, and it is usually called by the Airflow UI/API when the JWT token is about to expire.
 This endpoint is used to refresh the JWT token when it is about to expire.
 The auth manager should implement this endpoint to allow the Airflow UI/API to refresh the JWT token.
 If the auth manager does not implement this endpoint, the Airflow UI/API will not be able to refresh the JWT token.

From ec3cf9d1b2572d20968d5d69fe5574563449ca14 Mon Sep 17 00:00:00 2001
From: Bugra Ozturk <ozturkbugra93@gmail.com>
Date: Fri, 8 Aug 2025 19:11:22 +0200
Subject: [PATCH 3/6] feat(doc): add more info according to comments

---
 .../docs/core-concepts/auth-manager/index.rst | 24 ++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/airflow-core/docs/core-concepts/auth-manager/index.rst b/airflow-core/docs/core-concepts/auth-manager/index.rst
index e7f0658f9a33f..ed325a6e82809 100644
--- a/airflow-core/docs/core-concepts/auth-manager/index.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/index.rst
@@ -106,6 +106,8 @@ Authentication related methods
 * ``get_url_login``: Return the URL the user is redirected to for signing in.
 * ``get_url_logout``: Return the URL the user is redirected to when logging out. This is an optional method,
   this redirection is usually needed to invalidate resources when logging out, such as a session.
+* ``get_url_refresh``: Return the URL the user is redirected to when refreshing the JWT token.
+  This is an optional method, if not implemented, the Airflow UI/API will fall to log out if the auth manager needs to refresh the JWT token.
 * ``serialize_user``: Serialize a user instance to a dict. This dict is the actual content of the JWT token.
   It should contain all the information needed to identify the user and make an authorization request.
 * ``deserialize_user``: Create a user instance from a dict. The dict is the payload of the JWT token.
@@ -174,7 +176,9 @@ cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI wil
 
 Refreshing JWT Token
 ''''''''''''''''''''
-The refresh token ``<METHOD> <PATH>`` is ``POST /auth/token/refresh``. It returns a new JWT token in the cookie where updated token is stored.
+The refresh token logic is to automatically refresh the JWT token when it is about to expire.
+The auth manager should implement ``get_url_refresh`` method to return the URL of the refresh token endpoint.
+
 It requires the user to be authenticated, and it is usually called by the Airflow UI/API when the JWT token is about to expire.
 This endpoint is used to refresh the JWT token when it is about to expire.
 The auth manager should implement this endpoint to allow the Airflow UI/API to refresh the JWT token.
@@ -182,6 +186,24 @@ If the auth manager does not implement this endpoint, the Airflow UI/API will no
 The user will be logged out when the JWT token expires in that case, and they will have to log in again.
 
 This procedure is following the same pattern as the initial token generation endpoints and login/logout logic.
+
+If the auth manager have a token which expires and need to be refreshed, it should override the endpoint.
+
+Example token structure below shows that we need to refresh the token via using the ``refresh_token`` key in the token dict.
+This is example and the names can be different in your auth manager implementation.
+If this is not the case, auth manager don't need to implement the refresh token endpoint.
+
+.. code-block:: python
+
+  token = {
+      "access_token": "ACCESS_TOKEN",
+      "refresh_token": "REFRESH_TOKEN",
+      "param1": "value1",
+      "param2": "value2",
+      "...": "...",
+  }
+
+
 A typical implementation of the refresh token endpoint would look like this:
 
 

From b2cb4082a6d139a8a4b132fb3550db260d7ad9ef Mon Sep 17 00:00:00 2001
From: bugraoz93 <ozturkbugra93@gmail.com>
Date: Thu, 11 Dec 2025 20:22:12 +0100
Subject: [PATCH 4/6] update refresh token logic and clarify implementation
 details

---
 .../docs/core-concepts/auth-manager/index.rst | 94 +++++++++++--------
 1 file changed, 53 insertions(+), 41 deletions(-)

diff --git a/airflow-core/docs/core-concepts/auth-manager/index.rst b/airflow-core/docs/core-concepts/auth-manager/index.rst
index ed325a6e82809..1cb092f3e4f3c 100644
--- a/airflow-core/docs/core-concepts/auth-manager/index.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/index.rst
@@ -106,8 +106,6 @@ Authentication related methods
 * ``get_url_login``: Return the URL the user is redirected to for signing in.
 * ``get_url_logout``: Return the URL the user is redirected to when logging out. This is an optional method,
   this redirection is usually needed to invalidate resources when logging out, such as a session.
-* ``get_url_refresh``: Return the URL the user is redirected to when refreshing the JWT token.
-  This is an optional method, if not implemented, the Airflow UI/API will fall to log out if the auth manager needs to refresh the JWT token.
 * ``serialize_user``: Serialize a user instance to a dict. This dict is the actual content of the JWT token.
   It should contain all the information needed to identify the user and make an authorization request.
 * ``deserialize_user``: Create a user instance from a dict. The dict is the payload of the JWT token.
@@ -176,58 +174,72 @@ cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI wil
 
 Refreshing JWT Token
 ''''''''''''''''''''
-The refresh token logic is to automatically refresh the JWT token when it is about to expire.
-The auth manager should implement ``get_url_refresh`` method to return the URL of the refresh token endpoint.
+Refreshing token is optional feature and its availability depends on the specific implementation of the auth manager.
+The auth manager is responsible for refreshing the JWT token when it expires.
+The Airflow API uses middleware that intercepts every request and checks the validity of the JWT token.
+Token communication is handled through ``httponly`` cookies to improve security.
+When the token expires, the middleware calls the auth manager's ``refresh_token`` method to obtain a new token.
 
-It requires the user to be authenticated, and it is usually called by the Airflow UI/API when the JWT token is about to expire.
-This endpoint is used to refresh the JWT token when it is about to expire.
-The auth manager should implement this endpoint to allow the Airflow UI/API to refresh the JWT token.
-If the auth manager does not implement this endpoint, the Airflow UI/API will not be able to refresh the JWT token.
-The user will be logged out when the JWT token expires in that case, and they will have to log in again.
+To support token refresh operations, the auth manager must implement the ``refresh_token`` method.
+This method receives an expired token and must return a new valid token.
+User information is extracted from the expired token and used to generate a fresh token.
 
-This procedure is following the same pattern as the initial token generation endpoints and login/logout logic.
+An example implementation of ``refresh_user`` could be:
 
-If the auth manager have a token which expires and need to be refreshed, it should override the endpoint.
+.. code-block:: python
+
+    def refresh_user(self, *, user: KeycloakAuthManagerUser) -> KeycloakAuthManagerUser | None:
+        if self._token_expired(user.access_token):
+            log.debug("Refreshing the token")
+            client = self.get_keycloak_client()
+            tokens = client.refresh_token(user.refresh_token)
+            user.refresh_token = tokens["refresh_token"]
+            user.access_token = tokens["access_token"]
+            return user
+
+        return None
 
-Example token structure below shows that we need to refresh the token via using the ``refresh_token`` key in the token dict.
-This is example and the names can be different in your auth manager implementation.
-If this is not the case, auth manager don't need to implement the refresh token endpoint.
+User information is derived from the ``BaseUser`` instance. It is important that the user object contains all the fields required to refresh the token. An example user class that includes all necessary fields is shown below:
 
 .. code-block:: python
 
-  token = {
-      "access_token": "ACCESS_TOKEN",
-      "refresh_token": "REFRESH_TOKEN",
-      "param1": "value1",
-      "param2": "value2",
-      "...": "...",
-  }
+    class KeycloakAuthManagerUser(BaseUser):
+        """User model for users managed by the Keycloak auth manager."""
 
+        def __init__(self, *, user_id: str, name: str, access_token: str, refresh_token: str) -> None:
+            self.user_id = user_id
+            self.name = name
+            self.access_token = access_token
+            self.refresh_token = refresh_token
 
-A typical implementation of the refresh token endpoint would look like this:
+        def get_id(self) -> str:
+            return self.user_id
 
+        def get_name(self) -> str:
+            return self.name
+
+The refresh token endpoint must implement the refresh logic required by the auth manager. An example ``refresh_token`` implementation is shown below:
 
 .. code-block:: python
 
-    @router.post("/auth/token/refresh")
-    def refresh_token(
-        request: Request,
-        user: T = Depends(get_current_user),
-    ) -> TokenResponse:
-        """
-        Refresh the JWT token for the current user.
-        """
-        # Generate a new token for the user
-        new_token = auth_manager.generate_token(user)  # Or similar with calling the client from auth manager
-
-        # Set the new token in the cookie
-        secure = request.base_url.scheme == "https" or bool(conf.get("api", "ssl_cert", fallback=""))
-        response = RedirectResponse(url="/")
-        response.set_cookie(COOKIE_NAME_JWT_TOKEN, new_token, secure=secure)
-
-        return response
-.. note::
-    Do not set the cookie parameter ``httponly`` to ``True``. Airflow UI needs to access the JWT token from the cookie.
+    def refresh_token(self, expired_token: str) -> str:
+        expired_user_dict = self.deserialize_user(jwt.decode(expired_token, options={"verify_signature": False}))
+        expired_user = cast(KeycloakAuthManagerUser, expired_user_dict)
+
+        new_access_token, new_refresh_token = self._refresh_tokens(
+            expired_user.access_token,
+            expired_user.refresh_token,
+        )
+
+        new_user = KeycloakAuthManagerUser(
+            user_id=expired_user.get_id(),
+            name=expired_user.get_name(),
+            access_token=new_access_token,
+            refresh_token=new_refresh_token,
+        )
+
+        new_token = self._create_jwt_token(new_user)
+        return new_token
 
 Optional methods recommended to override for optimization
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

From 2408bd7cfe02c087be129d6c8b0ac498e8737f1a Mon Sep 17 00:00:00 2001
From: bugraoz93 <ozturkbugra93@gmail.com>
Date: Thu, 11 Dec 2025 20:28:19 +0100
Subject: [PATCH 5/6] update cookie httponly parameter requirement for JWT
 token access

---
 airflow-core/docs/core-concepts/auth-manager/index.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/airflow-core/docs/core-concepts/auth-manager/index.rst b/airflow-core/docs/core-concepts/auth-manager/index.rst
index 1cb092f3e4f3c..f603a21a7df2e 100644
--- a/airflow-core/docs/core-concepts/auth-manager/index.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/index.rst
@@ -170,7 +170,7 @@ cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI wil
     return response
 
 .. note::
-    Do not set the cookie parameter ``httponly`` to ``True``. Airflow UI needs to access the JWT token from the cookie.
+  Ensure that the cookie parameter ``httponly`` is set to ``True``. UI no longer manages the token.
 
 Refreshing JWT Token
 ''''''''''''''''''''

From 912c5c99185906248cd8e7275ff15a666c747014 Mon Sep 17 00:00:00 2001
From: bugraoz93 <ozturkbugra93@gmail.com>
Date: Sat, 13 Dec 2025 14:29:51 +0100
Subject: [PATCH 6/6] clarify refresh token logic and update method references

---
 .../docs/core-concepts/auth-manager/index.rst | 66 +++----------------
 1 file changed, 8 insertions(+), 58 deletions(-)

diff --git a/airflow-core/docs/core-concepts/auth-manager/index.rst b/airflow-core/docs/core-concepts/auth-manager/index.rst
index f603a21a7df2e..597507d06cf24 100644
--- a/airflow-core/docs/core-concepts/auth-manager/index.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/index.rst
@@ -170,7 +170,7 @@ cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI wil
     return response
 
 .. note::
-  Ensure that the cookie parameter ``httponly`` is set to ``True``. UI no longer manages the token.
+  Ensure that the cookie parameter ``httponly`` is set to ``True``. The UI does not manage the token.
 
 Refreshing JWT Token
 ''''''''''''''''''''
@@ -178,68 +178,18 @@ Refreshing token is optional feature and its availability depends on the specifi
 The auth manager is responsible for refreshing the JWT token when it expires.
 The Airflow API uses middleware that intercepts every request and checks the validity of the JWT token.
 Token communication is handled through ``httponly`` cookies to improve security.
-When the token expires, the middleware calls the auth manager's ``refresh_token`` method to obtain a new token.
+When the token expires, the `JWTRefreshMiddleware <https://github.com/apache/airflow/blob/3.1.5/airflow-core/src/airflow/api_fastapi/auth/middlewares/refresh_token.py>`_ middleware calls the auth manager's ``refresh_user`` method to obtain a new token.
 
-To support token refresh operations, the auth manager must implement the ``refresh_token`` method.
+
+To support token refresh operations, the auth manager must implement the ``refresh_user`` method.
 This method receives an expired token and must return a new valid token.
 User information is extracted from the expired token and used to generate a fresh token.
 
 An example implementation of ``refresh_user`` could be:
-
-.. code-block:: python
-
-    def refresh_user(self, *, user: KeycloakAuthManagerUser) -> KeycloakAuthManagerUser | None:
-        if self._token_expired(user.access_token):
-            log.debug("Refreshing the token")
-            client = self.get_keycloak_client()
-            tokens = client.refresh_token(user.refresh_token)
-            user.refresh_token = tokens["refresh_token"]
-            user.access_token = tokens["access_token"]
-            return user
-
-        return None
-
-User information is derived from the ``BaseUser`` instance. It is important that the user object contains all the fields required to refresh the token. An example user class that includes all necessary fields is shown below:
-
-.. code-block:: python
-
-    class KeycloakAuthManagerUser(BaseUser):
-        """User model for users managed by the Keycloak auth manager."""
-
-        def __init__(self, *, user_id: str, name: str, access_token: str, refresh_token: str) -> None:
-            self.user_id = user_id
-            self.name = name
-            self.access_token = access_token
-            self.refresh_token = refresh_token
-
-        def get_id(self) -> str:
-            return self.user_id
-
-        def get_name(self) -> str:
-            return self.name
-
-The refresh token endpoint must implement the refresh logic required by the auth manager. An example ``refresh_token`` implementation is shown below:
-
-.. code-block:: python
-
-    def refresh_token(self, expired_token: str) -> str:
-        expired_user_dict = self.deserialize_user(jwt.decode(expired_token, options={"verify_signature": False}))
-        expired_user = cast(KeycloakAuthManagerUser, expired_user_dict)
-
-        new_access_token, new_refresh_token = self._refresh_tokens(
-            expired_user.access_token,
-            expired_user.refresh_token,
-        )
-
-        new_user = KeycloakAuthManagerUser(
-            user_id=expired_user.get_id(),
-            name=expired_user.get_name(),
-            access_token=new_access_token,
-            refresh_token=new_refresh_token,
-        )
-
-        new_token = self._create_jwt_token(new_user)
-        return new_token
+`KeycloakAuthManager::refresh_user <https://github.com/apache/airflow/blob/3.1.5/providers/keycloak/src/airflow/providers/keycloak/auth_manager/keycloak_auth_manager.py#L113-L121>`_
+User information is derived from the ``BaseUser`` instance.
+It is important that the user object contains all the fields required to refresh the token. An example user class could be:
+`KeycloakAuthManagerUser(BaseUser) <https://github.com/apache/airflow/blob/3.1.5/providers/keycloak/src/airflow/providers/keycloak/auth_manager/user.pys>`_.
 
 Optional methods recommended to override for optimization
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
