← eval8_submission_v1e

fastapi_13786

failed WRONG_FIX wrong_fix · 40 tool calls · 275 s · fastapi/fastapi

Task input

🐛 Use `401` status code in security classes when credentials are missing

## Warning

This description is partially outdated after changes described in [this comment](https://github.com/fastapi/fastapi/pull/13786#pullrequestreview-3501695067).

## Description

This PR is an attempt to finally solve the issue with security tools returning error responses with status code `403` instead of `401` when credentials are not provided.

## Breaking changes and workaround

These changes can break projects that rely on old behavior.
In order to mitigate this, the `not_authenticated_status_code` is introduced. If set to `403`, it will make it work the same way as it was before changes (return `403` status code).
This option should be treated as a temporary workaround to give developers more time to update Clients to follow the new behavior.

## Changes and reasoning

### APIKeyQuery, APIKeyHeader, APIKeyCookie

* **Standard:**
    * These schemes are not covered by standards, but developers usually follow the same rules as for other standards
* **Actions:**
    * The default status code for not providing API key was changed from 403 to 401.
    * Temporary `not_authenticated_status_code` parameter can be used to revert this behavior back to returning 403 error code without sending `WWW-Authenticate`.
* **Notes:**
    * It’s considered to be a good practice to include in `WWW-Authenticate` information needed to understand how the key is supposed to be passed. I implemented default format (`WWW-Authenticate: ApiKey in="...", name="..."` ), but it’s possible to override the template for `WWW-Authenticate` by subclassing and defining the `format_www_authenticate_header_value` method

### HTTP Basic

*  **Standard:**
    * https://datatracker.ietf.org/doc/html/rfc7617
* **Actions:**
    * No needed. This scheme already acts according to the standard in terms of returning 401 status code with `WWW-Authenticate` header on a lack of credentials
* **Notes:**
    * `realm` is required according to the RFC, but optional in the current implementation. Fixing this would introduce breaking changes. Considering this is not a problem for people who want to follow the standard, I suggest we leave it as it is.

### HTTP Digest

* **Standard:**
    * https://datatracker.ietf.org/doc/html/rfc7616
* **Actions:**
    * The default status code for not providing the authorization parameter was changed from 403 to 401.
    * `WWW-Authenticate` is just a stub for now (just `WWW-Authenticate: Digest`) (see notes)
    *  Temporary `not_authenticated_status_code` parameter can be used to revert this behavior back to returning 403 error code without sending `WWW-Authenticate`.
* **Notes:**
    * Since the current `HTTPDigest` implementation is just a stub, we can’t follow standards (we don’t generate `nonce`'s, don’t have `realm`, …). I suggest we just change the error status code and add a stub for `WWW-Authenticate` (just `WWW-Authenticate: Digest`). For now `HTTPDigest` can’t be used as it is, so, this is not a problem.
    * We can later add full implementation of `Digest` scheme. There have been made several attempts to implement it (#9825, #3071)
    * Should we add a note that `HTTPDigest` is just a stub?

### HTTP Bearer, OAuth2 schemes, OIDC

* **Standard:**
    * https://datatracker.ietf.org/doc/html/rfc6750
* **Actions:**
    * For `OAuth2PasswordBearer` and `OAuth2AuthorizationCodeBearer`:  not needed.
        * They already return a 401 error code. Implementation is probably not 100% correct (see notes), but considering nobody argued, I think we can leave it as it is for now.
    * For `HTTPBearer` and `OpenIdConnect`:
        * The default status code for not providing the authorization parameter was changed from 403 to 401. The suggested implementation will be in line with the current implementations of `OAuth2PasswordBearer` and `OAuth2AuthorizationCodeBearer`.
        * Temporary `not_authenticated_status_code` parameter added to `HTTPBearer` can be used to revert this behavior back to returning 403 error code without sending `WWW-Authenticate`.
* **Notes:**
    * It’s [recommended to return 400 error response](https://datatracker.ietf.org/doc/html/rfc6750#section-3.1) if the parameter is missed or of an unsupported type, but this is not a strict requirement (word SHOULD is used). I suggest we ignore this and follow the approach that is consistent with other schemes.
    * The format of `WWW-Authenticate` is not clearly described: It’s said that the value "Bearer" MUST be followed by one or more auth-param values. At the same time, all auth-param attributes are optional. In examples they always add `realm`. Since we don’t have `realm`, I suggest we just skip it and send just `WWW-Authenticate: Bearer`
    * We can later improve the `WWW-Authenticate` format by adding `realm` and `scope`

## Links
* https://github.com/fastapi/fastapi/issues/10177
* https://github.com/fastapi/fastapi/pull/2120
* https://github.com/fastapi/fastapi/pull/5332
* https://github.com/fastapi/fastapi/pull/12507
* https://github.com/fastapi/fastapi/pull/5310
* https://github.com/fastapi/fastapi/pull/13729
* https://github.com/fastapi/fastapi/pull/13514
* https://github.com/fastapi/fastapi/pull/13326





Tool calls (41)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"APIKeyQuery\" fastapi/security | head -20"
}
{"status": "ok", "stdout": "fastapi/security/api_key.py:24:class APIKeyQuery(APIKeyBase):\nfastapi/security/api_key.py:43: from fastapi.security import APIKeyQu
full
{"status": "ok", "stdout": "fastapi/security/api_key.py:24:class APIKeyQuery(APIKeyBase):\nfastapi/security/api_key.py:43:    from fastapi.security import APIKeyQuery\nfastapi/security/api_key.py:47:    query_scheme = APIKeyQuery(name=\"api_key\")\nfastapi/security/api_key.py:87:                By default, if the query parameter is not provided, `APIKeyQuery` will\nfastapi/security/__init__.py:3:from .api_key import APIKeyQuery as APIKeyQuery\n", "stderr": "", "exit_code": 0}
2run_command
{
 "command": "grep -rn \"HTTPBearer\" fastapi/security | head -20"
}
{"status": "ok", "stdout": "fastapi/security/__init__.py:7:from .http import HTTPBearer as HTTPBearer\nfastapi/security/http.py:8:from fastapi.openapi.models im
full
{"status": "ok", "stdout": "fastapi/security/__init__.py:7:from .http import HTTPBearer as HTTPBearer\nfastapi/security/http.py:8:from fastapi.openapi.models import HTTPBearer as HTTPBearerModel\nfastapi/security/http.py:32:    The HTTP authorization credentials in the result of using `HTTPBearer` or\nfastapi/security/http.py:221:class HTTPBearer(HTTPBase):\nfastapi/security/http.py:238:    from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer\nfastapi/security/http.py:242:    security = HTTPBearer()\nfastapi/security/http.py:282:                `Authorization` header), `HTTPBearer` will automatically cancel the\nfastapi/security/http.py:298:        self.model = HTTPBearerModel(bearerFormat=bearerFormat, description=description)\n", "stderr": "", "exit_code": 0}
3run_command
{
 "command": "ls fastapi/security"
}
{"status": "ok", "stdout": "__init__.py\napi_key.py\nbase.py\nhttp.py\noauth2.py\nopen_id_connect_url.py\nutils.py\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "__init__.py\napi_key.py\nbase.py\nhttp.py\noauth2.py\nopen_id_connect_url.py\nutils.py\n", "stderr": "", "exit_code": 0}
4run_command
{
 "command": "sed -n '1,100p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.secu
full
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass APIKeyBase(SecurityBase):\n    @staticmethod\n    def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:\n        if not api_key:\n            if auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            return None\n        return api_key\n\n\nclass APIKeyQuery(APIKeyBase):\n    \"\"\"\n    API key authentication using a query parameter.\n\n    This defines the name of the query parameter that should be provided in the request\n    with the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the query parameter automatically and provides it as the\n    dependency result. But it doesn't define how to send that API key to the client.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyQuery\n\n    app = FastAPI()\n\n    query_scheme = APIKeyQuery(name=\"api_key\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(api_key: str = Depends(query_scheme)):\n        return {\"api_key\": api_key}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[\n            str,\n            Doc(\"Query parameter name.\"),\n        ],\n        scheme_name: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Securi
5run_command
{
 "command": "sed -n '1,150p' fastapi/security/http.py"
}
{"status": "ok", "stdout": "import binascii\nfrom base64 import b64decode\nfrom typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.exceptions
full
{"status": "ok", "stdout": "import binascii\nfrom base64 import b64decode\nfrom typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.exceptions import HTTPException\nfrom fastapi.openapi.models import HTTPBase as HTTPBaseModel\nfrom fastapi.openapi.models import HTTPBearer as HTTPBearerModel\nfrom fastapi.security.base import SecurityBase\nfrom fastapi.security.utils import get_authorization_scheme_param\nfrom pydantic import BaseModel\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass HTTPBasicCredentials(BaseModel):\n    \"\"\"\n    The HTTP Basic credentials given as the result of using `HTTPBasic` in a\n    dependency.\n\n    Read more about it in the\n    [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/).\n    \"\"\"\n\n    username: Annotated[str, Doc(\"The HTTP Basic username.\")]\n    password: Annotated[str, Doc(\"The HTTP Basic password.\")]\n\n\nclass HTTPAuthorizationCredentials(BaseModel):\n    \"\"\"\n    The HTTP authorization credentials in the result of using `HTTPBearer` or\n    `HTTPDigest` in a dependency.\n\n    The HTTP authorization header value is split by the first space.\n\n    The first part is the `scheme`, the second part is the `credentials`.\n\n    For example, in an HTTP Bearer token scheme, the client will send a header\n    like:\n\n    ```\n    Authorization: Bearer deadbeef12346\n    ```\n\n    In this case:\n\n    * `scheme` will have the value `\"Bearer\"`\n    * `credentials` will have the value `\"deadbeef12346\"`\n    \"\"\"\n\n    scheme: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The HTTP authorization scheme extracted from the header value.\n            \"\"\"\n        ),\n    ]\n    credentials: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The HTTP authorization credentials extracted from t
6run_command
{
 "command": "sed -n '151,300p' fastapi/security/http.py"
}
{"status": "ok", "stdout": " ] = None,\n description: Annotated[\n Optional[str],\n Doc(\n \"\"\"\n Security scheme description.\n\n It will be included in the
full
{"status": "ok", "stdout": "        ] = None,\n        description: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the HTTP Basic authentication is not provided (a\n                header), `HTTPBasic` will automatically cancel the request and send the\n                client an error.\n\n                If `auto_error` is set to `False`, when the HTTP Basic authentication\n                is not available, instead of erroring out, the dependency result will\n                be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, in HTTP Basic\n                authentication or in an HTTP Bearer token).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        self.model = HTTPBaseModel(scheme=\"basic\", description=description)\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.realm = realm\n        self.auto_error = auto_error\n\n    async def __call__(  # type: ignore\n        self, request: Request\n    ) -> Optional[HTTPBasicCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, param = get_authorization_scheme_param(authorization)\n        if self.realm:\n            unauthorized_headers = {\"WWW-Authenticate\": f'Basic realm=\"{self.realm}\"'}\n        else:\n            unauthorized_headers = {\"WWW-Authenticate\": \"Basic\"}\n        if not authorization or scheme.lower() != \"basic\":\n            if self.auto_error:\n           
7run_command
{
 "command": "sed -n '301,400p' fastapi/security/http.py"
}
{"status": "ok", "stdout": "\n async def __call__(\n self, request: Request\n ) -> Optional[HTTPAuthorizationCredentials]:\n authorization = request.headers.get
full
{"status": "ok", "stdout": "\n    async def __call__(\n        self, request: Request\n    ) -> Optional[HTTPAuthorizationCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            else:\n                return None\n        if scheme.lower() != \"bearer\":\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN,\n                    detail=\"Invalid authentication credentials\",\n                )\n            else:\n                return None\n        return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)\n\n\nclass HTTPDigest(HTTPBase):\n    \"\"\"\n    HTTP Digest authentication.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be an `HTTPAuthorizationCredentials` object containing\n    the `scheme` and the `credentials`.\n\n    ## Example\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import Depends, FastAPI\n    from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest\n\n    app = FastAPI()\n\n    security = HTTPDigest()\n\n\n    @app.get(\"/users/me\")\n    def read_current_user(\n        credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]\n    ):\n        return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        scheme_name: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the genera
8run_command
{
 "command": "sed -n '401,500p' fastapi/security/http.py"
}
{"status": "ok", "stdout": " self.scheme_name = scheme_name or self.__class__.__name__\n self.auto_error = auto_error\n\n async def __call__(\n self, request: R
full
{"status": "ok", "stdout": "        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(\n        self, request: Request\n    ) -> Optional[HTTPAuthorizationCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            else:\n                return None\n        if scheme.lower() != \"digest\":\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN,\n                    detail=\"Invalid authentication credentials\",\n                )\n            else:\n                return None\n        return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)\n", "stderr": "", "exit_code": 0}
9run_command
{
 "command": "sed -n '101,120p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": " ] = True,\n ):\n self.model: APIKey = APIKey(\n **{\"in\": APIKeyIn.query},\n name=name,\n description=description,\n )\n self.sche
full
{"status": "ok", "stdout": "        ] = True,\n    ):\n        self.model: APIKey = APIKey(\n            **{\"in\": APIKeyIn.query},\n            name=name,\n            description=description,\n        )\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(self, request: Request) -> Optional[str]:\n        api_key = request.query_params.get(self.model.name)\n        return self.check_api_key(api_key, self.auto_error)\n\n\nclass APIKeyHeader(APIKeyBase):\n    \"\"\"\n    API key authentication using a header.\n\n    This defines the name of the header that should be provided in the request with\n", "stderr": "", "exit_code": 0}
10run_command
{
 "command": "sed -n '121,200p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": " the API key and integrates that into the OpenAPI documentation. It extracts\n the key value sent in the header automatically and pr
full
{"status": "ok", "stdout": "    the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the header automatically and provides it as the dependency\n    result. But it doesn't define how to send that key to the client.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyHeader\n\n    app = FastAPI()\n\n    header_scheme = APIKeyHeader(name=\"x-key\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(key: str = Depends(header_scheme)):\n        return {\"key\": key}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[str, Doc(\"Header name.\")],\n        scheme_name: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the header is not provided, `APIKeyHeader` will\n                automatically cancel the request and send the client an error.\n\n                If `auto_error` is set to `False`, when the header is not available,\n                instead of erroring out, the dependency result will be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It
11run_command
{
 "command": "sed -n '201,300p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": " return self.check_api_key(api_key, self.auto_error)\n\n\nclass APIKeyCookie(APIKeyBase):\n \"\"\"\n API key authentication using a
full
{"status": "ok", "stdout": "        return self.check_api_key(api_key, self.auto_error)\n\n\nclass APIKeyCookie(APIKeyBase):\n    \"\"\"\n    API key authentication using a cookie.\n\n    This defines the name of the cookie that should be provided in the request with\n    the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the cookie automatically and provides it as the dependency\n    result. But it doesn't define how to set that cookie.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyCookie\n\n    app = FastAPI()\n\n    cookie_scheme = APIKeyCookie(name=\"session\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(session: str = Depends(cookie_scheme)):\n        return {\"session\": session}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[str, Doc(\"Cookie name.\")],\n        scheme_name: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the cookie is not provided, `APIKeyCookie` will\n                automatically cancel the request and send the client an error.\n\n                If `auto
12run_command
{
 "command": "sed -n '1,20p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.secu
full
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass APIKeyBase(SecurityBase):\n    @staticmethod\n    def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:\n        if not api_key:\n            if auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            return None\n", "stderr": "", "exit_code": 0}
13run_command
{
 "command": "sed -n '1,100p' fastapi/security/base.py"
}
{"status": "ok", "stdout": "from fastapi.openapi.models import SecurityBase as SecurityBaseModel\n\n\nclass SecurityBase:\n model: SecurityBaseModel\n scheme_na
full
{"status": "ok", "stdout": "from fastapi.openapi.models import SecurityBase as SecurityBaseModel\n\n\nclass SecurityBase:\n    model: SecurityBaseModel\n    scheme_name: str\n", "stderr": "", "exit_code": 0}
14run_command
{
 "command": "sed -n '1,100p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.secu
full
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass APIKeyBase(SecurityBase):\n    @staticmethod\n    def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:\n        if not api_key:\n            if auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            return None\n        return api_key\n\n\nclass APIKeyQuery(APIKeyBase):\n    \"\"\"\n    API key authentication using a query parameter.\n\n    This defines the name of the query parameter that should be provided in the request\n    with the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the query parameter automatically and provides it as the\n    dependency result. But it doesn't define how to send that API key to the client.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyQuery\n\n    app = FastAPI()\n\n    query_scheme = APIKeyQuery(name=\"api_key\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(api_key: str = Depends(query_scheme)):\n        return {\"api_key\": api_key}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[\n            str,\n            Doc(\"Query parameter name.\"),\n        ],\n        scheme_name: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Securi
15run_command
{
 "command": "grep -n \"HTTP_401_UNAUTHORIZED\" fastapi/security/http.py"
}
{"status": "ok", "stdout": "13:from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN\n200: status_code=HTTP_401_UNAUTHORIZED,\n207: status_code
full
{"status": "ok", "stdout": "13:from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN\n200:                    status_code=HTTP_401_UNAUTHORIZED,\n207:            status_code=HTTP_401_UNAUTHORIZED,\n", "stderr": "", "exit_code": 0}
16run_command
{
 "command": "grep -n \"HTTP_403_FORBIDDEN\" fastapi/security/http.py"
}
{"status": "ok", "stdout": "13:from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN\n91: status_code=HTTP_403_FORBIDDEN, detail=\"Not authenti
full
{"status": "ok", "stdout": "13:from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN\n91:                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n310:                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n317:                    status_code=HTTP_403_FORBIDDEN,\n412:                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n419:                    status_code=HTTP_403_FORBIDDEN,\n", "stderr": "", "exit_code": 0}
17run_command
{
 "command": "grep -n \"HTTP_403_FORBIDDEN\" fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "8:from starlette.status import HTTP_403_FORBIDDEN\n18: status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n", "stderr": ""
full
{"status": "ok", "stdout": "8:from starlette.status import HTTP_403_FORBIDDEN\n18:                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n", "stderr": "", "exit_code": 0}
18run_command
{
 "command": "sed -n '1,30p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.secu
full
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass APIKeyBase(SecurityBase):\n    @staticmethod\n    def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:\n        if not api_key:\n            if auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            return None\n        return api_key\n\n\nclass APIKeyQuery(APIKeyBase):\n    \"\"\"\n    API key authentication using a query parameter.\n\n    This defines the name of the query parameter that should be provided in the request\n    with the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the query parameter automatically and provides it as the\n", "stderr": "", "exit_code": 0}
19run_command
{
 "command": "sed -n '1,100p' fastapi/security/http.py"
}
{"status": "ok", "stdout": "import binascii\nfrom base64 import b64decode\nfrom typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.exceptions
full
{"status": "ok", "stdout": "import binascii\nfrom base64 import b64decode\nfrom typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.exceptions import HTTPException\nfrom fastapi.openapi.models import HTTPBase as HTTPBaseModel\nfrom fastapi.openapi.models import HTTPBearer as HTTPBearerModel\nfrom fastapi.security.base import SecurityBase\nfrom fastapi.security.utils import get_authorization_scheme_param\nfrom pydantic import BaseModel\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass HTTPBasicCredentials(BaseModel):\n    \"\"\"\n    The HTTP Basic credentials given as the result of using `HTTPBasic` in a\n    dependency.\n\n    Read more about it in the\n    [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/).\n    \"\"\"\n\n    username: Annotated[str, Doc(\"The HTTP Basic username.\")]\n    password: Annotated[str, Doc(\"The HTTP Basic password.\")]\n\n\nclass HTTPAuthorizationCredentials(BaseModel):\n    \"\"\"\n    The HTTP authorization credentials in the result of using `HTTPBearer` or\n    `HTTPDigest` in a dependency.\n\n    The HTTP authorization header value is split by the first space.\n\n    The first part is the `scheme`, the second part is the `credentials`.\n\n    For example, in an HTTP Bearer token scheme, the client will send a header\n    like:\n\n    ```\n    Authorization: Bearer deadbeef12346\n    ```\n\n    In this case:\n\n    * `scheme` will have the value `\"Bearer\"`\n    * `credentials` will have the value `\"deadbeef12346\"`\n    \"\"\"\n\n    scheme: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The HTTP authorization scheme extracted from the header value.\n            \"\"\"\n        ),\n    ]\n    credentials: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The HTTP authorization credentials extracted from t
20run_command
{
 "command": "sed -n '80,100p' fastapi/security/http.py"
}
{"status": "ok", "stdout": " self.scheme_name = scheme_name or self.__class__.__name__\n self.auto_error = auto_error\n\n async def __call__(\n self, request: R
full
{"status": "ok", "stdout": "        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(\n        self, request: Request\n    ) -> Optional[HTTPAuthorizationCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            else:\n                return None\n        return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)\n\n\nclass HTTPBasic(HTTPBase):\n    \"\"\"\n    HTTP Basic authentication.\n", "stderr": "", "exit_code": 0}
21run_command
{
 "command": "sed -n '1,100p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.secu
full
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass APIKeyBase(SecurityBase):\n    @staticmethod\n    def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:\n        if not api_key:\n            if auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            return None\n        return api_key\n\n\nclass APIKeyQuery(APIKeyBase):\n    \"\"\"\n    API key authentication using a query parameter.\n\n    This defines the name of the query parameter that should be provided in the request\n    with the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the query parameter automatically and provides it as the\n    dependency result. But it doesn't define how to send that API key to the client.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyQuery\n\n    app = FastAPI()\n\n    query_scheme = APIKeyQuery(name=\"api_key\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(api_key: str = Depends(query_scheme)):\n        return {\"api_key\": api_key}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[\n            str,\n            Doc(\"Query parameter name.\"),\n        ],\n        scheme_name: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Securi
22run_command
{
 "command": "sed -n '101,120p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": " ] = True,\n ):\n self.model: APIKey = APIKey(\n **{\"in\": APIKeyIn.query},\n name=name,\n description=description,\n )\n self.sche
full
{"status": "ok", "stdout": "        ] = True,\n    ):\n        self.model: APIKey = APIKey(\n            **{\"in\": APIKeyIn.query},\n            name=name,\n            description=description,\n        )\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(self, request: Request) -> Optional[str]:\n        api_key = request.query_params.get(self.model.name)\n        return self.check_api_key(api_key, self.auto_error)\n\n\nclass APIKeyHeader(APIKeyBase):\n    \"\"\"\n    API key authentication using a header.\n\n    This defines the name of the header that should be provided in the request with\n", "stderr": "", "exit_code": 0}
23run_command
{
 "command": "sed -n '1,100p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.secu
full
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass APIKeyBase(SecurityBase):\n    @staticmethod\n    def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:\n        if not api_key:\n            if auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            return None\n        return api_key\n\n\nclass APIKeyQuery(APIKeyBase):\n    \"\"\"\n    API key authentication using a query parameter.\n\n    This defines the name of the query parameter that should be provided in the request\n    with the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the query parameter automatically and provides it as the\n    dependency result. But it doesn't define how to send that API key to the client.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyQuery\n\n    app = FastAPI()\n\n    query_scheme = APIKeyQuery(name=\"api_key\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(api_key: str = Depends(query_scheme)):\n        return {\"api_key\": api_key}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[\n            str,\n            Doc(\"Query parameter name.\"),\n        ],\n        scheme_name: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Securi
24run_command
{
 "command": "sed -n '101,120p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": " ] = True,\n ):\n self.model: APIKey = APIKey(\n **{\"in\": APIKeyIn.query},\n name=name,\n description=description,\n )\n self.sche
full
{"status": "ok", "stdout": "        ] = True,\n    ):\n        self.model: APIKey = APIKey(\n            **{\"in\": APIKeyIn.query},\n            name=name,\n            description=description,\n        )\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(self, request: Request) -> Optional[str]:\n        api_key = request.query_params.get(self.model.name)\n        return self.check_api_key(api_key, self.auto_error)\n\n\nclass APIKeyHeader(APIKeyBase):\n    \"\"\"\n    API key authentication using a header.\n\n    This defines the name of the header that should be provided in the request with\n", "stderr": "", "exit_code": 0}
25run_command
{
 "command": "sed -n '121,240p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": " the API key and integrates that into the OpenAPI documentation. It extracts\n the key value sent in the header automatically and pr
full
{"status": "ok", "stdout": "    the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the header automatically and provides it as the dependency\n    result. But it doesn't define how to send that key to the client.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyHeader\n\n    app = FastAPI()\n\n    header_scheme = APIKeyHeader(name=\"x-key\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(key: str = Depends(header_scheme)):\n        return {\"key\": key}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[str, Doc(\"Header name.\")],\n        scheme_name: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the header is not provided, `APIKeyHeader` will\n                automatically cancel the request and send the client an error.\n\n                If `auto_error` is set to `False`, when the header is not available,\n                instead of erroring out, the dependency result will be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It
26run_command
{
 "command": "sed -n '241,350p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": " Optional[str],\n Doc(\n \"\"\"\n Security scheme name.\n\n It will be included in the generated OpenAPI (e.g. visible at `/docs`).\
full
{"status": "ok", "stdout": "            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            Optional[str],\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the cookie is not provided, `APIKeyCookie` will\n                automatically cancel the request and send the client an error.\n\n                If `auto_error` is set to `False`, when the cookie is not available,\n                instead of erroring out, the dependency result will be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, in a cookie or\n                in an HTTP Bearer token).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        self.model: APIKey = APIKey(\n            **{\"in\": APIKeyIn.cookie},\n            name=name,\n            description=description,\n        )\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(self, request: Request) -> Optional[str]:\n        api_key = request.cookies.get(self.model.name)\n        return self.check_api_key(api_key, self.auto_error)\n", "stderr": "", "exit_code": 0}
27run_command
{
 "command": "sed -i 's/from starlette.status import HTTP_403_FORBIDDEN/from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN/' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
28run_command
{
 "command": "sed -n '1,30p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.secu
full
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass APIKeyBase(SecurityBase):\n    @staticmethod\n    def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:\n        if not api_key:\n            if auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            return None\n        return api_key\n\n\nclass APIKeyQuery(APIKeyBase):\n    \"\"\"\n    API key authentication using a query parameter.\n\n    This defines the name of the query parameter that should be provided in the request\n    with the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the query parameter automatically and provides it as the\n", "stderr": "", "exit_code": 0}
29run_command
{
 "command": "sed -i '18s/status_code=HTTP_403_FORBIDDEN/status_code=HTTP_401_UNAUTHORIZED/' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
30run_command
{
 "command": "sed -n '1,20p' fastapi/security/api_key.py"
}
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.secu
full
{"status": "ok", "stdout": "from typing import Optional\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN\nfrom typing_extensions import Annotated\n\n\nclass APIKeyBase(SecurityBase):\n    @staticmethod\n    def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:\n        if not api_key:\n            if auto_error:\n                raise HTTPException(\n                    status_code=HTTP_401_UNAUTHORIZED, detail=\"Not authenticated\"\n                )\n            return None\n", "stderr": "", "exit_code": 0}
31run_command
{
 "command": "sed -n '80,100p' fastapi/security/http.py"
}
{"status": "ok", "stdout": " self.scheme_name = scheme_name or self.__class__.__name__\n self.auto_error = auto_error\n\n async def __call__(\n self, request: R
full
{"status": "ok", "stdout": "        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(\n        self, request: Request\n    ) -> Optional[HTTPAuthorizationCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            else:\n                return None\n        return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)\n\n\nclass HTTPBasic(HTTPBase):\n    \"\"\"\n    HTTP Basic authentication.\n", "stderr": "", "exit_code": 0}
32run_command
{
 "command": "sed -n '300,320p' fastapi/security/http.py"
}
{"status": "ok", "stdout": " self.auto_error = auto_error\n\n async def __call__(\n self, request: Request\n ) -> Optional[HTTPAuthorizationCredentials]:\n auth
full
{"status": "ok", "stdout": "        self.auto_error = auto_error\n\n    async def __call__(\n        self, request: Request\n    ) -> Optional[HTTPAuthorizationCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            else:\n                return None\n        if scheme.lower() != \"bearer\":\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN,\n                    detail=\"Invalid authentication credentials\",\n                )\n            else:\n", "stderr": "", "exit_code": 0}
33run_command
{
 "command": "sed -n '400,420p' fastapi/security/http.py"
}
{"status": "ok", "stdout": " self.model = HTTPBaseModel(scheme=\"digest\", description=description)\n self.scheme_name = scheme_name or self.__class__.__name__\
full
{"status": "ok", "stdout": "        self.model = HTTPBaseModel(scheme=\"digest\", description=description)\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(\n        self, request: Request\n    ) -> Optional[HTTPAuthorizationCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n                )\n            else:\n                return None\n        if scheme.lower() != \"digest\":\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN,\n                    detail=\"Invalid authentication credentials\",\n", "stderr": "", "exit_code": 0}
34run_command
{
 "command": "sed -i '91s/status_code=HTTP_403_FORBIDDEN/status_code=HTTP_401_UNAUTHORIZED/' fastapi/security/http.py"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
35run_command
{
 "command": "sed -i '310s/status_code=HTTP_403_FORBIDDEN/status_code=HTTP_401_UNAUTHORIZED/' fastapi/security/http.py"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
36run_command
{
 "command": "sed -i '412s/status_code=HTTP_403_FORBIDDEN/status_code=HTTP_401_UNAUTHORIZED/' fastapi/security/http.py"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
37run_command
{
 "command": "sed -n '80,100p' fastapi/security/http.py"
}
{"status": "ok", "stdout": " self.scheme_name = scheme_name or self.__class__.__name__\n self.auto_error = auto_error\n\n async def __call__(\n self, request: R
full
{"status": "ok", "stdout": "        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(\n        self, request: Request\n    ) -> Optional[HTTPAuthorizationCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_401_UNAUTHORIZED, detail=\"Not authenticated\"\n                )\n            else:\n                return None\n        return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)\n\n\nclass HTTPBasic(HTTPBase):\n    \"\"\"\n    HTTP Basic authentication.\n", "stderr": "", "exit_code": 0}
38run_command
{
 "command": "sed -n '300,320p' fastapi/security/http.py"
}
{"status": "ok", "stdout": " self.auto_error = auto_error\n\n async def __call__(\n self, request: Request\n ) -> Optional[HTTPAuthorizationCredentials]:\n auth
full
{"status": "ok", "stdout": "        self.auto_error = auto_error\n\n    async def __call__(\n        self, request: Request\n    ) -> Optional[HTTPAuthorizationCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_401_UNAUTHORIZED, detail=\"Not authenticated\"\n                )\n            else:\n                return None\n        if scheme.lower() != \"bearer\":\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN,\n                    detail=\"Invalid authentication credentials\",\n                )\n            else:\n", "stderr": "", "exit_code": 0}
39run_command
{
 "command": "sed -n '400,420p' fastapi/security/http.py"
}
{"status": "ok", "stdout": " self.model = HTTPBaseModel(scheme=\"digest\", description=description)\n self.scheme_name = scheme_name or self.__class__.__name__\
full
{"status": "ok", "stdout": "        self.model = HTTPBaseModel(scheme=\"digest\", description=description)\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(\n        self, request: Request\n    ) -> Optional[HTTPAuthorizationCredentials]:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_401_UNAUTHORIZED, detail=\"Not authenticated\"\n                )\n            else:\n                return None\n        if scheme.lower() != \"digest\":\n            if self.auto_error:\n                raise HTTPException(\n                    status_code=HTTP_403_FORBIDDEN,\n                    detail=\"Invalid authentication credentials\",\n", "stderr": "", "exit_code": 0}
40run_command
{
 "command": "git diff"
}
{"status": "ok", "stdout": "diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py\nindex 496c815a..195d5fb4 100644\n--- a/fastapi/security/api_
full
{"status": "ok", "stdout": "diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py\nindex 496c815a..195d5fb4 100644\n--- a/fastapi/security/api_key.py\n+++ b/fastapi/security/api_key.py\n@@ -5,7 +5,7 @@ from fastapi.openapi.models import APIKey, APIKeyIn\n from fastapi.security.base import SecurityBase\n from starlette.exceptions import HTTPException\n from starlette.requests import Request\n-from starlette.status import HTTP_403_FORBIDDEN\n+from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN\n from typing_extensions import Annotated\n \n \n@@ -15,7 +15,7 @@ class APIKeyBase(SecurityBase):\n         if not api_key:\n             if auto_error:\n                 raise HTTPException(\n-                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n+                    status_code=HTTP_401_UNAUTHORIZED, detail=\"Not authenticated\"\n                 )\n             return None\n         return api_key\ndiff --git a/fastapi/security/http.py b/fastapi/security/http.py\nindex 3a598565..4ceda95d 100644\n--- a/fastapi/security/http.py\n+++ b/fastapi/security/http.py\n@@ -88,7 +88,7 @@ class HTTPBase(SecurityBase):\n         if not (authorization and scheme and credentials):\n             if self.auto_error:\n                 raise HTTPException(\n-                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n+                    status_code=HTTP_401_UNAUTHORIZED, detail=\"Not authenticated\"\n                 )\n             else:\n                 return None\n@@ -307,7 +307,7 @@ class HTTPBearer(HTTPBase):\n         if not (authorization and scheme and credentials):\n             if self.auto_error:\n                 raise HTTPException(\n-                    status_code=HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n+                    status_code=HTTP_401_UNAUTHORIZED, detail=\"Not authenticated\"\n                 )\n             else:\n                 return None\n@@ -409,7 +409,7 @@ class 
41submit_patch
{}
{"status": "ok", "patch_size": 2299, "files_changed": 2}
full
{"status": "ok", "patch_size": 2299, "files_changed": 2}

Patch

diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py
index 496c815a..195d5fb4 100644
--- a/fastapi/security/api_key.py
+++ b/fastapi/security/api_key.py
@@ -5,7 +5,7 @@ from fastapi.openapi.models import APIKey, APIKeyIn
 from fastapi.security.base import SecurityBase
 from starlette.exceptions import HTTPException
 from starlette.requests import Request
-from starlette.status import HTTP_403_FORBIDDEN
+from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
 from typing_extensions import Annotated
 
 
@@ -15,7 +15,7 @@ class APIKeyBase(SecurityBase):
         if not api_key:
             if auto_error:
                 raise HTTPException(
-                    status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+                    status_code=HTTP_401_UNAUTHORIZED, detail="Not authenticated"
                 )
             return None
         return api_key
diff --git a/fastapi/security/http.py b/fastapi/security/http.py
index 3a598565..4ceda95d 100644
--- a/fastapi/security/http.py
+++ b/fastapi/security/http.py
@@ -88,7 +88,7 @@ class HTTPBase(SecurityBase):
         if not (authorization and scheme and credentials):
             if self.auto_error:
                 raise HTTPException(
-                    status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+                    status_code=HTTP_401_UNAUTHORIZED, detail="Not authenticated"
                 )
             else:
                 return None
@@ -307,7 +307,7 @@ class HTTPBearer(HTTPBase):
         if not (authorization and scheme and credentials):
             if self.auto_error:
                 raise HTTPException(
-                    status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+                    status_code=HTTP_401_UNAUTHORIZED, detail="Not authenticated"
                 )
             else:
                 return None
@@ -409,7 +409,7 @@ class HTTPDigest(HTTPBase):
         if not (authorization and scheme and credentials):
             if self.auto_error:
                 raise HTTPException(
-                    status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+                    status_code=HTTP_401_UNAUTHORIZED, detail="Not authenticated"
                 )
             else:
                 return None

Test output

show
.F
=================================== FAILURES ===================================
_________________________ test_security_api_key_no_key _________________________

    def test_security_api_key_no_key():
        client = TestClient(app)
        response = client.get("/users/me")
        assert response.status_code == 401, response.text
        assert response.json() == {"detail": "Not authenticated"}
>       assert response.headers["WWW-Authenticate"] == "APIKey"
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_security_api_key_cookie.py:37: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Headers({'content-length': '30', 'content-type': 'application/json'})
key = 'WWW-Authenticate'

    def __getitem__(self, key: str) -> str:
        """
        Return a single header value.
    
        If there are multiple headers with the same key, then we concatenate
        them with commas. See: https://tools.ietf.org/html/rfc7230#section-3.2.2
        """
        normalized_key = key.lower().encode(self.encoding)
    
        items = [
            header_value.decode(self.encoding)
            for _, header_key, header_value in self._list
            if header_key == normalized_key
        ]
    
        if items:
            return ", ".join(items)
    
>       raise KeyError(key)
E       KeyError: 'WWW-Authenticate'

/kaggle/tmp/envs/fastapi/lib/python3.13/site-packages/httpx/_models.py:302: KeyError
=============================== warnings summary ===============================
../../../../../../kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45
  /kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.
    _PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 1 passed, 1 warning in 1.06s