Security

Notiway secures the notification pipeline at multiple layers: authentication at the connection boundary, tenant validation at the subscription boundary, and built-in protections like rate limiting, CORS, and HSTS at the transport layer.


Security Layers

  flowchart TD
    C["Client"]

    subgraph Transport["Transport Security"]
        HSTS["HSTS"]
        CORS["CORS"]
        RL["Rate Limiting"]
    end

    subgraph Connection["Connection Security"]
        AUTH["Authentication Plugin"]
    end

    subgraph Subscription["Subscription Security"]
        TV["Tenant Validation Plugin"]
    end

    C --> Transport --> Connection --> Subscription

Every request passes through all layers in order. A failure at any layer terminates the request — the client never reaches the next layer.


Authentication

Every incoming connection is authenticated before the WebSocket upgrade. The configured Auth plugin inspects the initial HTTP request and either allows or rejects the connection.

On success, the plugin produces an identity containing at least a user ID. This identity determines automatic audience membership (Global, User, and Connection audiences) and is carried for the entire connection lifetime.

If authentication fails, the gateway rejects the connection and the WebSocket upgrade never happens.

Only one Auth plugin is active at a time. See Auth Plugins for available options, client-side setup, and configuration.


Tenant Validation

In multi-tenant deployments, tenant validation controls which tenants a client is allowed to join. When a client calls Subscribe to join a Tenant audience, the Tenant Validation plugin verifies that the authenticated user actually belongs to that tenant.

Without tenant validation, any authenticated client could subscribe to any tenant audience and receive its notifications.

Tenant validation also applies to tenant-scoped groups. A client must first pass validation for a tenant before it can join any group scoped to that tenant.

  flowchart TD
    C["Client calls Subscribe<br/>(audienceType: 2, audienceValue: 'acme-corp')"]
    C --> V{"Tenant Validation Plugin"}
    V -->|"Client belongs to tenant"| J["Client joins tenant:acme-corp<br/>Persisted notifications replayed"]
    V -->|"Client does NOT belong"| R["Subscribe rejected<br/>Client does not join"]

Only one Tenant Validation plugin is active at a time. See Tenant Validation Plugins for available options and configuration.


Transport Security

HSTS

Notiway enforces HTTP Strict Transport Security with subdomain inclusion and preload enabled. Browsers that have connected once will refuse plaintext HTTP connections for subsequent visits.

CORS

CORS is configurable per deployment:

  • Restricted mode — only whitelisted origins can establish connections. Credentials are allowed for authenticated SignalR connections. This is the recommended mode for production.
  • Open mode — any origin can connect. Useful for development and testing.

The gateway only accepts GET and POST methods — the minimum required by SignalR’s negotiation and WebSocket upgrade flow.

Rate Limiting

The gateway applies per-IP rate limiting using a fixed window strategy. Each IP address is tracked independently.

Default configuration:

SettingValue
Window size10 seconds
Requests per window100 per IP
Rejection status429 Too Many Requests

When a client exceeds the limit, the gateway rejects further requests with 429 and includes a X-RateLimit-Limit response header. Normal access resumes when the current window expires.

Rate limiting applies to all HTTP requests, including the initial SignalR negotiation and WebSocket upgrade.


Connection Security Flow

The full security flow from initial HTTP request to receiving notifications:

  sequenceDiagram
    participant Client
    participant Gateway as Notiway Gateway
    participant Auth as Auth Plugin
    participant TV as Tenant Validation Plugin

    Client->>Gateway: HTTP request with credentials
    Gateway->>Gateway: HSTS / CORS / Rate Limit checks
    Gateway->>Auth: Validate credentials

    alt Authentication fails
        Auth-->>Gateway: Reject
        Gateway-->>Client: 401 Unauthorized
    else Authentication passes
        Auth-->>Gateway: Identity (userId, claims)
        Gateway-->>Client: WebSocket upgrade
        Note over Gateway,Client: Auto-joins Global, User, Connection audiences
    end

    Client->>Gateway: Subscribe(tenant: "acme-corp")
    Gateway->>TV: Validate membership(tenantId, userId, claims)

    alt Validation fails
        TV-->>Gateway: Unauthorized
        Gateway-->>Client: Subscribe rejected
    else Validation passes
        TV-->>Gateway: Success
        Gateway-->>Client: Joined tenant:acme-corp
        Note over Gateway,Client: Persisted notifications replayed
    end

Security Best Practices

Transport

  • Always use HTTPS/WSS in production. SignalR negotiates the transport protocol over the initial HTTP connection
  • Configure TLS termination at your load balancer or reverse proxy
  • Restrict CORS origins to your application domains. Avoid open mode in production
  • Set the Forwarded / X-Forwarded-Proto headers if Notiway sits behind a proxy

Authentication

  • Never deploy with a development auth plugin (e.g. NoAuth) in production
  • Ensure credentials are refreshed on reconnect to avoid expired sessions
  • Refer to your chosen Auth Plugin documentation for plugin-specific security recommendations

Tenant Isolation

  • Enable tenant validation in any multi-tenant deployment
  • Remember that tenant-scoped groups inherit tenant validation. A client cannot join a group within a tenant it hasn’t been validated for

Infrastructure

  • Run Notiway in a private network. Only expose the WebSocket endpoint through a load balancer or reverse proxy
  • Use the broker’s native access controls (IAM policies for SNS/SQS, ACLs for Redis/RabbitMQ) to restrict who can publish notifications
  • Pass secrets through environment variables or a secret manager. Never hardcode credentials in configuration files