Vaulthalla Logo

Why Vaulthalla Requires a WebSocket Session Before HTTP

Published

In Vaulthalla, you can’t access the HTTP layer unless you already have an active WebSocket session.

Not “authenticated recently.”

Not “holding a valid token.”

Actually connected.

That’s backwards compared to most systems—and it’s entirely intentional.


The Dilemma with Vaulthalla-Web

Vaulthalla is a filesystem-first platform. Performance, consistency, and control over state aren’t optional—they’re foundational.

At the protocol layer, this led to two core requirements:

  • WebSockets act as the primary protocol (low overhead, persistent, stateful)
  • HTTP exists as a secondary interface for:
    • File previews (thumbnails, streaming)
    • Middleware validation (Next.js, edge logic)

Simple enough on paper.

Until you try to make both layers obey the same security model.


The Problem: WebSockets Authenticate Before Users Do

WebSockets authenticate once—during the handshake.

But users don’t log in until after the connection is established.

That creates a gap:

You need a valid session before you have a user.

Most systems avoid this problem by making HTTP the source of truth and treating WebSockets as an extension.

Vaulthalla does the opposite.


The Rule

HTTP requests are only valid if their refresh token maps to an active WebSocket session.

Not just a valid token.

Not just a database record.

A live connection.


How Vaulthalla Handles the Gap

Vaulthalla uses a refresh + access token model, but with one key difference:

A refresh token may be issued before authentication, during the WebSocket handshake.

If no token is provided—or it fails validation—a new refresh token is issued immediately and bound to the session.

Yes, this means:

  • You can have a valid refresh token
  • Without an associated user
  • Before authentication completes

That sounds uncomfortable at first.

It’s also what makes the model work.


Why This Exists

HTTP-based auth works in 99% of applications.

Vaulthalla is not one of them.

The HTTP layer in Vaulthalla is responsible for:

  • Serving decrypted previews
  • Passing through middleware validation
  • Exposing filesystem-adjacent operations

If a refresh token alone were sufficient, then:

A stolen token becomes a skeleton key.

So Vaulthalla removes that possibility entirely.


What This Changes

Instead of validating tokens in isolation:

Vaulthalla validates tokens against live session state.

This has immediate implications:

  • A stolen refresh token is useless without the originating session
  • Sessions can be invalidated instantly (drop connection → revoke access)
  • Replay attacks fail without presence
  • HTTP becomes a projection of a real session, not an entry point

You’re either connected—or you’re not getting in.


What It Looks Like in Practice

At runtime, Vaulthalla-core operates as a single daemon coordinating multiple internal services with a shared hot cache. Authentication state lives in memory, not just in the database.

1. WebSocket Initialization

On connection:

  • Attempt token rehydration
  • If invalid or missing → issue new refresh token
  • Cache session immediately
1void Manager::tryRehydrate(const std::shared_ptr<Session>& session) {2    try {3        if (!session) return;45        Validator::validateRefreshToken(session);6        Issuer::accessToken(session);7        cache(session);89        if (!session->user) {10            Issuer::refreshToken(session);11            cache(session);12        }13    } catch (const std::exception& ex) {14        Issuer::refreshToken(session);15        cache(session);16    }17}18

2. WebSocket Routing (Implicit Deny)

Unauthenticated sessions may only access auth routes. Everything else is blocked.

1if (!command.starts_with("auth") && !sessionManager->validate(session, accessToken)) {2    return Response::UNAUTHORIZED(...);3}4

3. Session Promotion (Post-Login)

Once authenticated:

  • Session is bound to a user
  • Refresh token is upgraded with user context
  • Session becomes authoritative

4. HTTP Validation (The Critical Step)

HTTP requests:

  • Extract refresh token from cookie
  • Attempt to resolve active session
  • Validate against in-memory session state
1const auto session = sessionManager->validateRawRefreshToken(refresh);2

No session?

No access.


Tradeoffs (Because Nothing Is Free)

This model is not “plug and play.”

It comes with real costs:

  • Requires persistent connections
  • Introduces session lifecycle complexity
  • Harder to reason about than stateless HTTP
  • Took months to refine into something stable

This is not how you build a CRUD app.


Why Vaulthalla Does It Anyway

Vaulthalla isn’t optimizing for simplicity.

It’s optimizing for:

  • Control over session state
  • Real-time security guarantees
  • Eliminating token-only attack surfaces
  • Aligning protocol behavior with system reality

A filesystem is not stateless.

Your auth layer shouldn’t pretend it is.


Takeaway

Most systems treat WebSockets as optional and HTTP as the source of truth.

Vaulthalla flips that.

The WebSocket session is the source of truth.

HTTP exists to serve it.


Vaulthalla isn’t a REST API.

It’s a system that knows when you’re actually there.

And if you’re not?

You don’t get access—no matter what tokens you’re holding.