I’m building a secure messaging app using FastAPI with JWT authentication and websockets.
My issue is that after the client connects with a valid token, the websocket closes right away with code 1006.
Here’s the relevant part of my code:
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket, token: str):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
await websocket.accept()
await websocket.send_text("Connected!")
except Exception as e:
print(e)
await websocket.close()
How can I correctly verify the JWT before accepting the websocket so that the connection stays open?
-
1006 means the socket was closed abnormally, most likely because FastAPI rejected the WebSocket before it was actually accepted. What I believe is you are accepting the WebSocket after reading the token parameter. But WebSockets don’t pass query parameters the same way as HTTP, and FastAPI expects websocket.accept() to happen before most interactions. Also, if token is invalid, the browser closes the socket abruptly (1006), because WebSockets cannot receive normal HTTP 401/403 responses.colonel– colonel2025年10月30日 19:27:38 +00:00Commented Oct 30 at 19:27
2 Answers 2
WebSocket connections need to be kept alive with a message loop.
from fastapi import WebSocket, WebSocketDisconnect, status
import jwt
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket, token: str):
# Verify token BEFORE accepting
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
user_id = payload.get("user_id")
except jwt.InvalidTokenError:
await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason="Invalid token")
return
# Now accept the connection
await websocket.accept()
try:
await websocket.send_json({"type": "connection", "message": "Connected successfully"})
# Message loop - keeps connection alive
while True:
message = await websocket.receive_text()
# Your message handling logic
await websocket.send_json({
"type": "echo",
"data": message,
"user_id": user_id
})
except WebSocketDisconnect:
print(f"User {user_id} disconnected")
except Exception as e:
print(f"Error for user {user_id}: {e}")
await websocket.close(code=1011)
CLIENT-SIDE (in javascript):
const ws = new WebSocket(`ws://localhost:8000/ws?token=${jwtToken}`);
ws.onopen = () => {
console.log('Connected');
};
ws.onmessage = (event) => {
console.log('Message:', event.data);
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
ws.onclose = (event) => {
console.log('Closed:', event.code, event.reason);
};
// Send messages
ws.send('Hello server!');
Comments
I'm going to keep the JWT part of your question out of my answer, because it's unrelated to the issue of the connexion closing.
Once you understand why, you can easily add back your token verification.
Sample code that closes the connexion
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
await websocket.send_text("Connected!")
We accept the connexion, send a message, and... the function ends, so FastAPI closes the connexion.
Sample code that keeps it alive
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
await websocket.send_text("Connected!")
while True:
message = await websocket.receive_text()
print(f"Received message: {message}")
Here, after sending "Connected!", we keep listening on the websocket (forever).
Now, it's up to you to add your logic:
When do you actually close the connexion?
Your token verification
Hope that helps!
Comments
Explore related questions
See similar questions with these tags.