FastAPI HX-Redirect header not working with HTMX after user authentication

I’m building a web app where users need to be redirected after signing in. I have an HTMX form that sends a POST request to my FastAPI backend but the redirect isn’t working properly.

Here’s my login form:

<form hx-post="/signin" hx-target="#message" class="signin-form">
  <div id="message" class="status"></div>
  <!-- username and password inputs here -->
</form>

My backend endpoint:

@app.post("/signin")
async def signin(req: Request, res: Response, username: str = Form(), pwd: str = Form()):
    # validation code here
    res.headers["HX-Redirect"] = "http://localhost:8000/dashboard"
    context = {"message": "Welcome back!"}
    return templates.TemplateResponse("login_success.html", {"request": req, "context": context})

The template renders fine in the target div but the browser doesn’t redirect to the dashboard page. My CORS config allows all headers and methods. I can’t use RedirectResponse because HTMX will just swap that response into the target element instead of actually redirecting the browser.

interesting issue! check your browser’s dev tools - is the hx-redirect header actually being sent? sometimes it gets stripped out. also, are you running any middleware that might mess with response headers?

Had this exact problem in my FastAPI project last month. You’re sending back a template response AND the HX-Redirect header, which confuses HTMX. When HTMX gets both content and a redirect header, it just swaps the content instead.

Fix is simple - return an empty response with only the redirect header when auth works:

@app.post("/signin")
async def signin(req: Request, res: Response, username: str = Form(), pwd: str = Form()):
    # validation code here
    if authentication_successful:
        res.headers["HX-Redirect"] = "http://localhost:8000/dashboard"
        return Response(status_code=200)
    else:
        # return error template for failed authentication
        context = {"message": "Invalid credentials"}
        return templates.TemplateResponse("login_error.html", {"request": req, "context": context})

Now HTMX will actually follow the redirect instead of trying to dump content into your div.

Check if you’ve got any JavaScript event handlers messing with htmx. Had the same issue - old jQuery code was blocking htmx from handling the redirect header. Try adding hx-headers='{"X-Requested-With": "XMLHttpRequest"}' to your form just in case.