C.W.K.
Stream
Lesson 08 of 08 · published

Authentication

~13 min · fastapi, auth, jwt, depends

Level 0Poller
0 XP0/60 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

Auth must complete before accept()

The handshake is the only place to reject without leaving the client in an awkward "open then immediately closed" state. So all auth — token validation, permission checks, rate-limit-by-user — must happen before you call websocket.accept(). The cost of being strict here is zero; the cost of being lax is leaked auth state and confusing client UX.

FastAPI Depends works on WebSocket

The Depends(...) system is fully supported on WebSocket endpoints. You can write a dependency that extracts and validates the token, raising WebSocketException on failure, and the framework handles the close for you.

Cookies vs. tokens

If your users authenticate via session cookies in the browser, those cookies are sent automatically on the WebSocket upgrade GET. Read them via websocket.cookies. For non-browser clients (mobile, server-to-server), pass tokens in the query string. cwkPippa uses cookies for the WebUI and tokens for tooling — same auth code path, different transport.

Code

Depends-style auth on WebSocket·python
from fastapi import WebSocket, WebSocketException, status, Depends

async def get_current_user(websocket: WebSocket) -> dict:
    token = websocket.query_params.get('token')
    if not token:
        raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
    user = decode_jwt(token)
    if not user:
        raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
    return user

@app.websocket('/ws')
async def protected(
    websocket: WebSocket,
    user: dict = Depends(get_current_user),
):
    await websocket.accept()
    await websocket.send_json({'type': 'welcome', 'data': {'user': user['name']}})
    # ... handler
Cookie-based auth (browser sessions)·python
@app.websocket('/ws')
async def cookie_auth(websocket: WebSocket):
    session_id = websocket.cookies.get('session_id')
    user = await load_session(session_id) if session_id else None
    if user is None:
        await websocket.close(code=4001, reason='unauthorized')
        return
    await websocket.accept()
    # ... user is the same shape as your REST auth produces

External links

Exercise

Use the Depends pattern to build a /ws/{room} endpoint where (a) the token must decode to a valid user, (b) the user must have read access to the room, (c) writing requires write access. Test with three users: full access, read-only, no access — each must hit a different code path.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.