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 d596f4d4a98 Add documentation about Airflow API authentication (#48417)
d596f4d4a98 is described below
commit d596f4d4a982eb5ce9fb8d6bd5c007162c945f99
Author: Vincent <[email protected]>
AuthorDate: Thu Mar 27 13:46:09 2025 -0400
Add documentation about Airflow API authentication (#48417)
---
.../docs/core-concepts/auth-manager/index.rst | 43 +++++++++--------
airflow-core/docs/index.rst | 2 +-
airflow-core/docs/security/api.rst | 56 +++++++++++++++++-----
airflow-core/docs/stable-rest-api-ref.rst | 4 +-
.../api_fastapi/core_api/openapi/v1-generated.yaml | 10 +++-
.../src/airflow/api_fastapi/core_api/security.py | 12 ++++-
.../auth/managers/test_base_auth_manager.py | 20 ++++++++
docs/conf.py | 1 -
8 files changed, 112 insertions(+), 36 deletions(-)
diff --git a/airflow-core/docs/core-concepts/auth-manager/index.rst
b/airflow-core/docs/core-concepts/auth-manager/index.rst
index bd13d89ace8..98bd9360281 100644
--- a/airflow-core/docs/core-concepts/auth-manager/index.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/index.rst
@@ -98,24 +98,6 @@ Authentication related BaseAuthManager methods
* ``get_user``: Return the signed-in user.
* ``get_url_login``: Return the URL the user is redirected to for signing in.
-JWT token management by auth managers
--------------------------------------
-The auth manager is responsible of creating the JWT token and pass it to
Airflow UI. The protocol to exchange the JWT
-token between the auth manager and Airflow UI is using cookies. The auth
manager needs to save the JWT token in a
-cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI
will then read the cookie, save it and
-delete the cookie.
-
-.. code-block:: python
-
- from airflow.api_fastapi.auth.managers.base_auth_manager import
COOKIE_NAME_JWT_TOKEN
-
- response = RedirectResponse(url="/")
- response.set_cookie(COOKIE_NAME_JWT_TOKEN, token, secure=True)
- return response
-
-.. note::
- Do not set the cookie parameter ``httponly`` to ``True``. Airflow UI needs
to access the JWT token from the cookie.
-
Authorization related BaseAuthManager methods
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -147,6 +129,29 @@ These authorization methods are:
* ``is_authorized_view``: Return whether the user is authorized to access a
specific view in Airflow. The view is specified through ``access_view`` (e.g.
``AccessView.CLUSTER_ACTIVITY``).
* ``is_authorized_custom_view``: Return whether the user is authorized to
access a specific view not defined in Airflow. This view can be provided by the
auth manager itself or a plugin defined by the user.
+JWT token management by auth managers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The auth manager is responsible for creating the JWT token needed to interact
with Airflow public API.
+To achieve this, the auth manager **must** provide an endpoint to create this
JWT token. This endpoint must be
+available at ``POST /auth/token``
+
+The auth manager is also responsible of passing the JWT token to Airflow UI.
The protocol to exchange the JWT
+token between the auth manager and Airflow UI is using cookies. The auth
manager needs to save the JWT token in a
+cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI
will then read the cookie, save it and
+delete the cookie.
+
+.. code-block:: python
+
+ from airflow.api_fastapi.auth.managers.base_auth_manager import
COOKIE_NAME_JWT_TOKEN
+
+ response = RedirectResponse(url="/")
+ response.set_cookie(COOKIE_NAME_JWT_TOKEN, token, secure=True)
+ 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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -199,7 +204,7 @@ Such additional endpoints can be used to manage resources
such as users, groups,
Endpoints defined by ``get_fastapi_app`` are mounted in ``/auth``.
Next Steps
-^^^^^^^^^^
+----------
Once you have created a new auth manager class implementing the
:class:`~airflow.api_fastapi.auth.managers.base_auth_manager.BaseAuthManager`
interface, you can configure Airflow to use it by setting the
``core.auth_manager`` configuration value to the module path of your auth
manager:
diff --git a/airflow-core/docs/index.rst b/airflow-core/docs/index.rst
index 78c33348d3f..c25a724792b 100644
--- a/airflow-core/docs/index.rst
+++ b/airflow-core/docs/index.rst
@@ -176,7 +176,7 @@ so coding will always be required.
Operators and hooks <operators-and-hooks-ref>
CLI <cli-and-env-variables-ref>
Templates <templates-ref>
- Stable REST API <stable-rest-api-ref>
+ Airflow public API <stable-rest-api-ref>
Configurations <configurations-ref>
Extra packages <extra-packages-ref>
diff --git a/airflow-core/docs/security/api.rst
b/airflow-core/docs/security/api.rst
index 0bae61d7363..1ed568f69b3 100644
--- a/airflow-core/docs/security/api.rst
+++ b/airflow-core/docs/security/api.rst
@@ -15,20 +15,54 @@
specific language governing permissions and limitations
under the License.
-API
-===
+Public API
+==========
-API Authentication
-------------------
+Airflow public API authentication
+---------------------------------
-The API authentication is handled by the auth manager.
-For more information about API authentication, please refer to the auth
manager documentation used by your environment.
-By default Airflow uses the ``Simple Auth Manager``, if you did not specify
any other auth manager.
-``Simple Auth Manager`` is a basic auth manager that persisted under Airflow
core.
-It is not recommended to use it in production and currently aiming for
development purposes.
+The Airflow public API uses JWT (JSON Web Token) for authenticating API
requests.
+Each request made to the Airflow API must include a valid JWT token in the
``Authorization`` header to verify the
+identity and permissions of the client.
-Please install ``apache-airflow-providers-fab`` to use the auth manager that
is aimed for production.
-For that, please look at
:doc:`apache-airflow-providers-fab:auth-manager/api-authentication`.
+Generate a JWT token
+^^^^^^^^^^^^^^^^^^^^
+
+To interact with the Airflow API, clients must first authenticate and obtain a
JWT token.
+The token can be generated by making a ``POST`` request to the ``/auth/token``
endpoint, passing the necessary
+credentials (e.g., username and password). The ``/auth/token`` endpoint is
provided by the auth manager, therefore,
+please read the documentation of the auth manager configured in your
environment for more details.
+
+Example
+*******
+
+Request
+
+.. code-block:: bash
+
+ ENDPOINT_URL="http://localhost:8080/"
+ curl -X POST ${ENDPOINT_URL}/auth/token \
+ -H "Content-Type: application/json" \
+ -d '{
+ "username": "your-username",
+ "password": "your-password"
+ }'
+
+Response
+
+.. code-block:: json
+
+ {
+ "jwt_token": "<JWT-TOKEN>"
+ }
+
+Use the JWT token to call Airflow public API
+
+.. code-block:: bash
+
+ ENDPOINT_URL="http://localhost:8080/"
+ curl -X GET ${ENDPOINT_URL}/api/v2/dags \
+ -H "Authorization: Bearer <JWT-TOKEN>"
Enabling CORS
-------------
diff --git a/airflow-core/docs/stable-rest-api-ref.rst
b/airflow-core/docs/stable-rest-api-ref.rst
index 673b88cc35b..0996dd69dc9 100644
--- a/airflow-core/docs/stable-rest-api-ref.rst
+++ b/airflow-core/docs/stable-rest-api-ref.rst
@@ -16,8 +16,8 @@
specific language governing permissions and limitations
under the License.
-REST API Reference
-==================
+Airflow public API reference
+============================
It's a stub file. It will be converted automatically during the build process
to the valid documentation by the Sphinx plugin. See: /docs/conf.py
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
index 97f43ee8d9a..cb0b38960de 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
+++ b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
@@ -11782,7 +11782,15 @@ components:
securitySchemes:
OAuth2PasswordBearer:
type: oauth2
+ description: To authenticate Airflow API requests, clients must include
a JWT
+ (JSON Web Token) in the Authorization header of each request. This
token is
+ used to verify the identity of the client and ensure that they have
the appropriate
+ permissions to access the requested resources. You can use the
endpoint ``POST
+ /auth/token`` in order to generate a JWT token. Upon successful
authentication,
+ the server will issue a JWT token that contains the necessary
information
+ (such as user identity and scope) to authenticate subsequent requests.
To
+ learn more about Airflow public API authentication, please read
https://airflow.apache.org/docs/apache-airflow/stable/security/api.html.
flows:
password:
scopes: {}
- tokenUrl: token
+ tokenUrl: /auth/token
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/security.py
b/airflow-core/src/airflow/api_fastapi/core_api/security.py
index b10f7ac8549..0b5f51d2c81 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/security.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/security.py
@@ -50,7 +50,17 @@ if TYPE_CHECKING:
from airflow.api_fastapi.auth.managers.base_auth_manager import
BaseAuthManager, ResourceMethod
-oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+auth_description = (
+ "To authenticate Airflow API requests, clients must include a JWT (JSON
Web Token) in "
+ "the Authorization header of each request. This token is used to verify
the identity of "
+ "the client and ensure that they have the appropriate permissions to
access the "
+ "requested resources. "
+ "You can use the endpoint ``POST /auth/token`` in order to generate a JWT
token. "
+ "Upon successful authentication, the server will issue a JWT token that
contains the necessary "
+ "information (such as user identity and scope) to authenticate subsequent
requests. "
+ "To learn more about Airflow public API authentication, please read
https://airflow.apache.org/docs/apache-airflow/stable/security/api.html."
+)
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token",
description=auth_description)
async def get_user(token_str: Annotated[str, Depends(oauth2_scheme)]) ->
BaseUser:
diff --git
a/airflow-core/tests/unit/api_fastapi/auth/managers/test_base_auth_manager.py
b/airflow-core/tests/unit/api_fastapi/auth/managers/test_base_auth_manager.py
index 741c4962f34..bd37351fd63 100644
---
a/airflow-core/tests/unit/api_fastapi/auth/managers/test_base_auth_manager.py
+++
b/airflow-core/tests/unit/api_fastapi/auth/managers/test_base_auth_manager.py
@@ -33,6 +33,8 @@ from
airflow.api_fastapi.auth.managers.models.resource_details import (
)
from airflow.api_fastapi.auth.tokens import JWTGenerator, JWTValidator
from airflow.api_fastapi.common.types import MenuItem
+from airflow.providers_manager import ProvidersManager
+from airflow.utils.module_loading import import_string
if TYPE_CHECKING:
from airflow.api_fastapi.auth.managers.base_auth_manager import
ResourceMethod
@@ -366,3 +368,21 @@ class TestBaseAuthManager:
session.execute.return_value = dags
result = auth_manager.get_authorized_dag_ids(user=user,
session=session)
assert result == expected
+
+
+def test_auth_managers_have_create_token_endpoint(test_client):
+ auth_managers = ProvidersManager().auth_managers
+
auth_managers.append("airflow.api_fastapi.auth.managers.simple.simple_auth_manager.SimpleAuthManager")
+
+ for auth_manager_module in auth_managers:
+ auth_manager_cls = import_string(auth_manager_module)
+ am = auth_manager_cls()
+ am.init()
+
+ response = test_client.post(
+ "/auth/token",
+ json={"username": "", "password": ""},
+ )
+ assert (
+ response.status_code not in [404, 405]
+ ), f"The auth manager {auth_manager_module} does not provide an
endpoint to create a JWT token. This endpoint should be POST /auth/token"
diff --git a/docs/conf.py b/docs/conf.py
index 823b8027a9b..6b3fc7d54d6 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -920,7 +920,6 @@ if PACKAGE_NAME == "apache-airflow":
"spec": OPENAPI_FILE.as_posix(),
"opts": {
"hide-hostname": True,
- "no-auto-auth": True,
},
},
]