Skip to content

WebSocket Authorization — Complete Guide to Access Control

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Websocket Authorization. We cover key concepts, practical examples, and best practices to help you master this topic.

WebSocket authorization controls which channels and actions an authenticated user can access, using role-based permissions and channel-level access control for real-time applications.

What You'll Learn

  • Authorization models for WebSocket connections
  • Channel-level permissions and subscription control
  • Implementing role-based access for real-time data

Why It Matters

Authentication identifies the user; authorization controls what they can do. Without authorization, any authenticated user can access any real-time data channel.

Real-World Use

Durga Antivirus Pro WebSocket threat feed has three authorization levels: admins receive all threat types, analysts receive threat alerts, and viewers receive only summary notifications. Authorization is checked per message channel.

flowchart LR
    A["Authenticated"] --> P["Permission Check"]
    P -->|"Admin"| C1["All Channels"]
    P -->|"Analyst"| C2["Threat Alerts"]
    P -->|"Viewer"| C3["Summary Only"]
    P -->|"None"| D["Access Denied"]
    style P fill:#dbeafe,stroke:#2563eb

Code Examples

// WebSocket authorization middleware
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });

const CHANNEL_PERMISSIONS = {
  'threats:all':      ['admin'],
  'threats:critical': ['admin', 'analyst'],
  'threats:summary':  ['admin', 'analyst', 'viewer'],
  'system:admin':     ['admin'],
};

function authorizeChannel(user, channel) {
  const allowedRoles = CHANNEL_PERMISSIONS[channel];
  if (!allowedRoles) return false;
  return allowedRoles.includes(user.role);
}

server.on('connection', (ws, req) => {
  // User identity set during authentication (see auth lesson)
  const user = ws.user;

  ws.on('message', (message) => {
    const { action, channel, data } = JSON.parse(message);

    if (action === 'subscribe') {
      if (!authorizeChannel(user, channel)) {
        ws.send(JSON.stringify({
          type: 'error',
          message: `Not authorized for channel: ${channel}`
        }));
        return;
      }
      ws.subscribedChannels = ws.subscribedChannels || [];
      ws.subscribedChannels.push(channel);
      ws.send(JSON.stringify({ type: 'subscribed', channel }));
    }

    if (action === 'publish') {
      if (!authorizeChannel(user, channel)) {
        ws.send(JSON.stringify({
          type: 'error',
          message: `Not authorized to publish to: ${channel}`
        }));
        return;
      }
      broadcast(channel, data);
    }
  });
});

Expected output: Users can only subscribe to channels their role permits; unauthorized subscriptions receive error.

# Python WebSocket channel authorization
import asyncio
import json
import websockets

CHANNEL_PERMISSIONS = {
    'alerts': {'read': ['admin', 'analyst'], 'write': ['admin']},
    'metrics': {'read': ['admin', 'analyst', 'viewer'], 'write': ['admin']},
    'admin': {'read': ['admin'], 'write': ['admin']},
}

class AuthorizedWebSocket:
    def __init__(self, websocket, user):
        self.ws = websocket
        self.user = user
        self.subscriptions = set()

    async def handle_subscribe(self, channel):
        perms = CHANNEL_PERMISSIONS.get(channel, {})
        if self.user['role'] not in perms.get('read', []):
            await self.ws.send(json.dumps({
                'type': 'error',
                'channel': channel,
                'message': 'Read access denied'
            }))
            return False
        self.subscriptions.add(channel)
        await self.ws.send(json.dumps({'type': 'subscribed', 'channel': channel}))
        return True

    async def handle_publish(self, channel, data):
        perms = CHANNEL_PERMISSIONS.get(channel, {})
        if self.user['role'] not in perms.get('write', []):
            await self.ws.send(json.dumps({
                'type': 'error',
                'channel': channel,
                'message': 'Write access denied'
            }))
            return False
        await broadcast(channel, data)
        return True

Expected output: Channel-based authorization controls read and write access per role.

// Permission-based action authorization
class WebSocketAuthorizer {
  constructor() {
    this.permissions = {
      'send_message':     ['user', 'moderator', 'admin'],
      'delete_message':   ['moderator', 'admin'],
      'ban_user':         ['admin'],
      'view_analytics':   ['admin'],
    };
  }

  canPerform(user, action) {
    const allowedRoles = this.permissions[action];
    if (!allowedRoles) return false;
    return allowedRoles.includes(user.role);
  }

  authorizeAction(user, action, callback) {
    if (!this.canPerform(user, action)) {
      callback({ error: 'Insufficient permissions', action });
      return false;
    }
    return true;
  }
}

const authorizer = new WebSocketAuthorizer();

ws.on('message', (msg) => {
  const { action, payload } = JSON.parse(msg);
  authorizer.authorizeAction(ws.user, action, (error) => {
    ws.send(JSON.stringify(error));
  }) && handleAction(action, payload);
});

Expected output: Each action has role-based permissions; unauthorized actions are rejected with error.

Common Mistakes

1. Checking Authorization Only at Connection Time

User roles can change mid-session. Re-check authorization periodically or on sensitive operations.

2. No Channel-Level Granularity

All-or-nothing authorization forces users to choose between too much access or no access at all.

3. Exposing Channel Names Without Authorization

Listing all channels to an unauthenticated user reveals the system topology.

4. Caching Permissions Too Long

If roles change, cached permissions allow unauthorized access. Cache with short TTLs or invalidate on change.

5. Authorization Errors in Production Logs

Logging authorization decisions for debugging is fine but do not expose permission structure in error messages sent to users.

Practice Questions

  1. What is the difference between WebSocket authentication and authorization?
  2. Why should authorization be checked per-channel rather than once per connection?
  3. How do you handle role changes during an active WebSocket session?
  4. Why should channel names not be exposed to unauthorized users?
  5. What is the problem with caching permissions too long?

Answers:

  1. Authentication verifies identity; authorization controls what the identified user can access.
  2. Users may have different permissions for different channels; per-channel check enables fine-grained control.
  3. Listen for role change events from the auth service and update permissions mid-session.
  4. Channel names reveal system capabilities and topology, aiding attack reconnaissance.
  5. Outdated cached permissions allow unauthorized access after role changes.

Challenge: Implement channel-level authorization for a real-time collaboration app. Three roles (admin, editor, viewer) with read/write permissions per document channel. Handle role changes mid-session.

FAQ

How do you handle authorization for dynamically created channels?

: Use a pattern matcher (channel:document:{id}) and check permissions against document ownership or team membership.

Should authorization be at the message level or connection level?

: Connection level for coarse access, message level for fine-grained control.

Can WebSocket authorization use OAuth 2.0 scopes?

: Yes, map OAuth scopes to WebSocket channels and actions.

How do you test WebSocket authorization?

: Write automated tests with different user tokens/roles, verifying allowed and denied channel access.

What is the performance impact of per-message authorization?

: Minimal for simple role checks; noticeable for database-backed permissions. Cache when possible.

Mini Project

Build a WebSocket authorization system for a real-time dashboard with channels: metrics (all roles), alerts (admin, analyst), admin (admin only). Implement per-action permissions (subscribe, publish) and role change handling mid-session.

What's Next

Learn about WebSocket authentication for verifying identity, or explore WebSocket rate limiting for controlling connection behavior.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro