โ† pod_r3_v1e

fastapi_14786

resolved RESOLVED PASS ยท 4 tool calls ยท 29 s ยท fastapi/fastapi

Task input

๐Ÿ› Strip whitespaces from `Authorization` header credentials

## Description

Fixes whitespace handling in authorization header parameter extraction to comply with [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750#section-2.1).

## Problem

The current implementation preserves leading/trailing whitespace in the extracted credential parameter. While RFC 6750 allows one or more spaces (`1*SP`) between "Bearer" and the token, the token definition (`b64token`) doesn't include whitespace characters, meaning spaces should be treated as separators only.

This causes the extracted credentials to include extraneous whitespace, which can lead to authentication failures.

## Solution

Added `.strip()` to the parameter extraction to remove leading and trailing whitespace:
```python
return scheme, param.strip()
```

## Reproduction

### Before the fix:
```python
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

app = FastAPI()
security = HTTPBearer()

@app.get("/users/me")
def read_current_user(
    credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]
):
    return {"scheme": credentials.scheme, "credentials": credentials.credentials}
```

**Test case 1: Single space (correct)**
```bash
curl -X 'GET' \
  'http://127.0.0.1:8000/users/me' \
  -H 'Authorization: Bearer xxx'
```
Response: `{"scheme":"Bearer","credentials":"xxx"}` โœ“

**Test case 2: Multiple spaces**
```bash
curl -X 'GET' \
  'http://127.0.0.1:8000/users/me' \
  -H 'Authorization: Bearer   xxx'
```
Response: `{"scheme":"Bearer","credentials":"  xxx"}` โœ—

**Test case 3: Trailing whitespace**
```bash
curl -X 'GET' \
  'http://127.0.0.1:8000/users/me' \
  -H 'Authorization: Bearer xxx '
```
Response: `{"scheme":"Bearer","credentials":"xxx "}` โœ—

### After the fix:

All three test cases now return: `{"scheme":"Bearer","credentials":"xxx"}` โœ“

## Changes

- Modified `get_authorization_scheme_param()` in `fastapi/security/utils.py` to strip whitespace from the parameter
- Added test cases to verify the fix handles multiple spaces and trailing whitespace correctly

## Checklist

- [x] Tests added to cover the bug fix
- [x] Existing tests pass

Tool calls (5)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"get_authorization_scheme_param\" fastapi/security/utils.py"
}
{"status": "ok", "stdout": "fastapi/security/utils.py:4:def get_authorization_scheme_param(\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "fastapi/security/utils.py:4:def get_authorization_scheme_param(\n", "stderr": "", "exit_code": 0}
2run_command
{
 "command": "sed -n '1,30p' fastapi/security/utils.py"
}
{"status": "ok", "stdout": "from typing import Optional\n\n\ndef get_authorization_scheme_param(\n authorization_header_value: Optional[str],\n) -> tuple[str, s
full
{"status": "ok", "stdout": "from typing import Optional\n\n\ndef get_authorization_scheme_param(\n    authorization_header_value: Optional[str],\n) -> tuple[str, str]:\n    if not authorization_header_value:\n        return \"\", \"\"\n    scheme, _, param = authorization_header_value.partition(\" \")\n    return scheme, param\n", "stderr": "", "exit_code": 0}
3run_command
{
 "command": "cd /workspace && python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"fastapi/security/utils.py\"); s = p.read_text()\nold = \"\"\"    scheme, _, param = authorization_header_value.partition(\" \")\n    return scheme, param\"\"\"\nnew = \"\"\"    scheme, _, param = authorization_header_value.partition(\" \")\n    return scheme, param.strip()\"\"\"\nassert s.count(old) == 1, (\"old text found this many times:\", s.count(old))\nt = s.replace(old, new); compile(t, str(p), \"exec\"); p.write_text(t)\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
4run_command
{
 "command": "cd /workspace && python3 - <<'PY'\nfrom fastapi.security.utils import get_authorization_scheme_param\n\ntest_cases = [\n    (\"Bearer xxx\", (\"Bearer\", \"xxx\")),\n    (\"Bearer   xxx\", (\"Bearer\", \"xxx\")),\n    (\"Bearer xxx \", (\"Bearer\", \"xxx\")),\n    (\"Bearer  xxx  \", (\"Bearer\", \"xxx\")),\n    (\"Basic yyy\", (\"Basic\", \"yyy\")),\n    (\"Basic   yyy  \", (\"Basic\", \"yyy\")),\n    (\"\", (\"\", \"\")),\n    (None, (\"\", \"\")),\n]\n\nfor input_val, expected in test_cases:\n    result = get_authorization_scheme_param(input_val)\n    assert result == expected, f\"Failed for {input_val}: expected {expected}, got {result}\"\n\nprint(\"All tests passed!\")\nPY\n"
}
{"status": "ok", "stdout": "All tests passed!\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "All tests passed!\n", "stderr": "", "exit_code": 0}
5submit_patch
{}
{"status": "ok", "patch_size": 404, "files_changed": 1}
full
{"status": "ok", "patch_size": 404, "files_changed": 1}

Patch

diff --git a/fastapi/security/utils.py b/fastapi/security/utils.py
index 002e68b4..fd349aec 100644
--- a/fastapi/security/utils.py
+++ b/fastapi/security/utils.py
@@ -7,4 +7,4 @@ def get_authorization_scheme_param(
     if not authorization_header_value:
         return "", ""
     scheme, _, param = authorization_header_value.partition(" ")
-    return scheme, param
+    return scheme, param.strip()

Test output

show
.........                                                                [100%]
=============================== warnings summary ===============================
../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45
  /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.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
9 passed, 1 warning in 0.40s