Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cookies not setting on starlette TestClient, with requests sent via Python Requests

The login/logout feature on FastAPI works in the browser, but I am trying to write unit tests for it. When my app sets the cookie, I can see the response DOES have the cookie sent. When I receive it with Python Request, the cookie has been stripped from the response hence the login doesn't work.

@pytest.fixture(scope='module')
def test_client():
    app = create_app(testing=True)
    client = TestClient(app)
    client.base_url = 'https://localhost'
    from app.models import Base, User
    Base.metadata.create_all(bind=engine)
    yield client
    db.flush()
    Base.metadata.drop_all(bind=engine)

# Simple login functions.
def test_login(test_client):
    response = test_client.post(url='/login', data=dict(
        username=username,
        password=password
    ), allow_redirects=True, proxies=proxies)
    breakpointB()
    assert response.headers

Then the server side which works in the browser:

    @core.post("/login", response_model=schemas.Token)
    async def login_for_access_token(*, request: Request, form_data: OAuth2PasswordRequestForm = Depends(),
                                     db: Session = Depends(get_db)):
        token = jsonable_encoder(access_token)
        response = RedirectResponse(url=request.url_for('index'), status_code=303)
        response.set_cookie(
            "Authorization",
            value=f"Bearer {token}",
            domain=os.environ.get('DOMAIN'),
            httponly=False,
            max_age=1800,
            expires=1800,
        )
        breakpointA()
        return response

So at BreakpointA(), just before the response is sent, this is what response.headers looks like:

MutableHeaders({'location': 'https://localhost/', 'set-cookie': 'Authorization="Bearer e
yJ0eXAiO5JKV1iLCJ4bGciOiJ2UzI1NiJ9.eyJzdWIiOi2b2Vqb2UiL253JleH1iOjE1DM0ODEzNTR7.zwbT9yV
OnV2V14Yrtuc1PP8wv82alz2354sgm0Rc7PgZIvc"; Domain=https://localhost; expires=Fri, 06 Mar 202
0 07:55:54 GMT; Max-Age=1800; Path=/'})

At BreakpointB(), on my test client side AFTER the response has been recieved, this is what response.headers and response.cookies looks like:

(Pdb) response.headers
{'content-length': '24956', 'content-type': 'text/html; charset=utf-8'}

(Pdb) response.cookies
<RequestsCookieJar[]>
(Pdb) response.cookies.get_dict()
{}

I have a strong suspicion this is because of the domain issue - but how do I correct for this? In my TestClient (Starlette TestClient), I have set client.base_url = 'https://localhost', and in my endpoint when making the cookie I've set DOMAIN=https://localhost. Anyone have any experience fixing this?

like image 821
phil0s0pher Avatar asked Sep 14 '25 19:09

phil0s0pher


2 Answers

I experienced the same issue. While not a perfect solution, I ended up doing this in my test:

assert "Authorization" in response.headers['set-cookie']

...you could check for more things in the string as needed.

like image 62
shawnwall Avatar answered Sep 17 '25 09:09

shawnwall


Just ran into this issue, in my case, it is indeed because of the cookie domain used in TestClient.

You can supply your cookie_domain as the base_url to your TestClient:

client = TestClient(app, base_url="http://example.com") 

set-cookie should work as long as the base_url is consistent with the cookie domain.

Edit: make sure your cookie domain is an FQDN without http:// or https:// prefixes

like image 37
melvin Avatar answered Sep 17 '25 11:09

melvin