Skip to content

Conversation

@bourgeoa
Copy link
Member

@bourgeoa bourgeoa commented Jan 12, 2026

Implemented authentication and authorization for WebSocket connections in node-solid-server

Summary

Implemented authentication and authorization for WebSocket connections in node-solid-server, enforcing ACL Read permissions before allowing subscriptions. Supports both session cookie and Bearer token authentication methods.

Motivation

WebSocket subscriptions previously lacked authentication and authorization checks, allowing any client to subscribe to resource updates regardless of ACL permissions. This posed a security risk where unauthorized users could monitor changes to private resources.

Changes

1. WebSocket Authorization Infrastructure

Modified node-solid-ws/lib/server.js

  • Added authorize callback option to WebSocket server constructor
  • Integrated authorization check before subscription processing
  • Returns err <uri> forbidden when authorization fails
  • Returns ack <uri> on successful authorization
  • Backward compatible - if no authorize callback provided, subscriptions proceed without checks

Modified lib/create-server.mjs - Authorization callback (lines 210-270)

  • Created authorizeSubscription callback function
  • Checks ACL Read permission using ACLChecker.can(userId, 'Read')
  • Validates URL length (max 2048 chars) to prevent DoS
  • Prevents SSRF via hostname validation
  • Supports both authenticated and anonymous requests

2. Session Cookie Authentication for WebSockets

Modified lib/create-server.mjs - Upgrade handler (lines 107-140)

  • Extract session middleware from Express app
  • Manually parse session cookies during WebSocket upgrade event
  • Extract WebID from request.session.userId
  • Store WebID on request object for authorization callback

3. Bearer Token Authentication for WebSockets

Modified lib/create-server.mjs - Upgrade handler (lines 141-198)

  • Check Authorization: Bearer <token> header if no session found
  • Integrate OIDC Resource Server (oidc.rs.authenticate()) for token validation
  • Extract WebID from token claims via oidc.webIdFromClaims()
  • Support configurable token types (DPoP, Bearer)
  • Graceful degradation on invalid tokens (treated as anonymous)

4. Async Authentication Pattern

Implementation Details:

  • Wrapped authentication logic in authPromise (async IIFE)
  • Made authorization callback async to await authentication completion
  • Ensures Bearer token validation finishes before subscription authorization

Authentication Flow:

1. Client connects with session cookie OR Authorization: Bearer <token>
2. Upgrade event fires → authPromise created
   - Parse session cookies (if present)
   - If no session, check Authorization header
   - Call oidc.rs.authenticate() to validate token
   - Extract WebID from session or token claims
   - Store webId on request object
3. WebSocket connection established
4. Client sends 'sub <uri>' message
5. Authorization callback invoked
   - Waits for authPromise to complete
   - Checks ACL Read permission for the resource
   - Allows or denies subscription

Tests

Added comprehensive test coverage:

node-solid-server Tests (7 tests added)

File: test/integration/authentication-oidc-test.mjs

Session Cookie Authentication (4 tests):

  • should allow authenticated WebSocket subscription to private resource
  • should deny anonymous WebSocket subscription to private resource
  • should allow authenticated subscription to public resource
  • should allow anonymous subscription to public resource

Bearer Token Authentication (3 tests):

  • should allow Bearer token WebSocket subscription to private resource
  • should allow Bearer token WebSocket subscription to public resource
  • should degrade gracefully with invalid Bearer token

Test Results: 872 passing (15s)

node-solid-ws Tests (3 tests added)

File: test/websockets.js

Authorization Callback Suite:

  • should receive ack when authorization allows subscription
  • should receive err when authorization denies subscription
  • should receive err when authorization callback returns error

Test Results: 8 passing (82ms)

Test Infrastructure Changes

Modified: test/resources/accounts-scenario/alice/.acl-override

  • Added public Read authorization for root resource
  • Allows anonymous WebSocket subscriptions to public resources
  • Uses foaf:Agent agentClass for public access
  • Only applies to root (./), not default for children

Security

ACL Enforcement:

  • All WebSocket subscriptions require Read permission
  • Authorization checks use existing ACL infrastructure
  • Private resources deny anonymous access
  • Public resources allow anonymous access

Protection Against Attacks:

  • URL length validation prevents DoS attacks
  • Hostname validation prevents SSRF
  • Invalid tokens cannot elevate to authenticated sessions
  • Failed authentication logs errors but doesn't crash server

Compatibility

  • ✅ Backward compatible - no breaking changes
  • ✅ Works with both authentication methods simultaneously
  • ✅ Existing REST API authentication unchanged
  • ✅ Public resources remain accessible anonymously
  • ✅ No configuration changes required

Dependencies

  • Uses existing OIDC infrastructure (@solid/oidc-rs, @solid/oidc-auth-manager)
  • Uses existing ACL checker (@solid/acl-check)
  • Modified node-solid-ws (v0.4.3) to support authorization callbacks
  • For local development: Use npm link solid-ws to test with modified node-solid-ws

Files Modified

node-solid-server:

  • lib/create-server.mjs - WebSocket authentication and authorization
  • test/integration/authentication-oidc-test.mjs - WebSocket auth test suite
  • test/resources/accounts-scenario/alice/.acl-override - Public read for root

node-solid-ws:

  • lib/server.js - Authorization callback support
  • test/websockets.js - Authorization callback test suite

Configuration

  • Authorization is automatically enabled when live: true is set
  • Bearer token support automatically enabled when OIDC is configured
  • Token types configurable via ldp.tokenTypesSupported (defaults to ['DPoP', 'Bearer'])

@bourgeoa bourgeoa requested a review from CxRes January 12, 2026 11:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants