Authentication

Learn how Soketify authentication works, how to manage your API credentials, and how to implement authentication endpoints for private and presence channels.

How Authentication Works

Soketify uses the same authentication model as Pusher. There are two distinct contexts where authentication applies:

  1. Server-to-Soketify API Your backend server authenticates with Soketify using your App ID, App Key, and App Secret to trigger events and query channel state via the REST API. This uses HMAC-SHA256 signature authentication on each request.
  2. Client-to-Your-Server (Channel Auth) When a client subscribes to a private or presence channel, the Pusher client library makes an HTTP request to your auth endpoint to verify that the user is allowed to join. Your server generates a signature using the App Secret and returns it to the client.

Public channels (those without a private- or presence- prefix) do not require any authentication. Any client with your App Key can subscribe to them.

App Key vs App Secret

CredentialPurposeWhere to UsePublic?
App KeyIdentifies your app on WebSocket connectionsClient-side (browser, mobile app)Yes
App SecretSigns API requests and channel auth responsesServer-side onlyNo
App IDIdentifies your app in REST API URLsServer-side onlyNo

Never Expose Your App Secret

The App Secret must never appear in client-side code, browser JavaScript bundles, public repositories, or anywhere accessible to end users. If your secret is compromised, rotate it immediately in the Dashboard.

Managing Secrets in the Dashboard

You can view and manage your app credentials from the Soketify Dashboard:

  1. Dashboard Go to Dashboard and select your app.
  2. Navigate to the tab. Settings
  3. Your App ID, App Key, and App Secret are displayed in the Credentials section.
  4. Use the copy button to copy any credential to your clipboard.

Store your credentials as environment variables on your server. A common pattern is to use a .env file:

.env
bash
SOKETIFY_APP_ID=your-app-id
SOKETIFY_APP_KEY=your-app-key
SOKETIFY_APP_SECRET=your-app-secret

Secret Rotation Strategy

Rotating your App Secret is a best practice for maintaining security. Soketify supports seamless secret rotation:

  1. Generate a new secret In the Dashboard, click Rotate Secret on your app settings page. The new secret is generated but not yet active.
  2. Update your server Deploy the new secret to your server environment variables. During the grace period, both the old and new secrets are accepted.
  3. Activate the new secret Once your servers are updated, confirm the rotation in the Dashboard. The old secret is then revoked.

Rotation Best Practices

Rotate your secrets on a regular schedule (e.g., every 90 days) and immediately if you suspect a compromise. Store secrets in a secrets manager rather than directly in code or configuration files.

Private Channel Authentication

When a client subscribes to a channel with the private- prefix, the Pusher client library automatically sends an HTTP POST request to your auth endpoint. Here is the flow:

Browser
pusher-js
Your Server
/pusher/auth
Soketify
ws.soketify.com
POST /pusher/auth
socket_id + channel_name
verify user session
sign: HMAC_SHA256(secret, socket_id:channel)
{ auth: "key:sig" }
subscribe + auth token
subscription_succeeded

Auth Endpoint Implementation (Node.js / Express)

server.js
javascript
1const express = require("express");
2const Pusher = require("pusher");
3
4const app = express();
5app.use(express.urlencoded({ extended: false }));
6
7const pusher = new Pusher({
8  appId: process.env.SOKETIFY_APP_ID,
9  key: process.env.SOKETIFY_APP_KEY,
10  secret: process.env.SOKETIFY_APP_SECRET,
11  host: "api.soketify.com",
12  port: "443",
13  useTLS: true,
14  cluster: "default",
15});
16
17app.post("/pusher/auth", (req, res) => {
18  // Verify user is logged in (use your own auth middleware)
19  const user = req.session?.user;
20  if (!user) {
21    return res.status(403).json({ error: "Not authenticated" });
22  }
23
24  const { socket_id, channel_name } = req.body;
25
26  // Optional: check the user has access to this specific channel
27  // e.g., "private-user-123" should only be accessible by user 123
28  const userId = channel_name.replace("private-user-", "");
29  if (userId !== user.id) {
30    return res.status(403).json({ error: "Not authorized for this channel" });
31  }
32
33  // Generate the auth signature
34  const authResponse = pusher.authorizeChannel(socket_id, channel_name);
35  res.json(authResponse);
36});
37
38app.listen(3000);

Client Configuration

Configure the Pusher client to use your auth endpoint:

client.js
javascript
1const pusher = new Pusher("YOUR_APP_KEY", {
2  wsHost: "ws.soketify.com",
3  wsPort: 443,
4  wssPort: 443,
5  forceTLS: true,
6  disableStats: true,
7  enabledTransports: ["ws", "wss"],
8  cluster: "default",
9  // Point to your auth endpoint
10  channelAuthorization: {
11    endpoint: "/pusher/auth",
12    transport: "ajax",
13  },
14});
15
16const privateChannel = pusher.subscribe("private-user-123");
17privateChannel.bind("pusher:subscription_succeeded", () => {
18  console.log("Successfully subscribed to private channel");
19});
20privateChannel.bind("pusher:subscription_error", (error) => {
21  console.error("Auth failed:", error);
22});

Presence Channel Authentication

Presence channels work similarly to private channels but require additional user information. When the client subscribes to a presence- channel, your auth endpoint must return user data along with the signature.

Auth Endpoint for Presence Channels

server.js
javascript
1app.post("/pusher/auth", (req, res) => {
2  const user = req.session?.user;
3  if (!user) {
4    return res.status(403).json({ error: "Not authenticated" });
5  }
6
7  const { socket_id, channel_name } = req.body;
8
9  // For presence channels, provide user data
10  if (channel_name.startsWith("presence-")) {
11    const presenceData = {
12      user_id: user.id,
13      user_info: {
14        name: user.name,
15        email: user.email,
16        avatar: user.avatar,
17      },
18    };
19
20    const authResponse = pusher.authorizeChannel(
21      socket_id,
22      channel_name,
23      presenceData
24    );
25    return res.json(authResponse);
26  }
27
28  // For private channels
29  if (channel_name.startsWith("private-")) {
30    const authResponse = pusher.authorizeChannel(socket_id, channel_name);
31    return res.json(authResponse);
32  }
33
34  res.status(400).json({ error: "Invalid channel" });
35});

Using Presence Data on the Client

presence-client.js
javascript
1const presence = pusher.subscribe("presence-chat-room");
2
3// Fired when subscription succeeds - contains all current members
4presence.bind("pusher:subscription_succeeded", (members) => {
5  console.log("Total members:", members.count);
6
7  // Iterate over all members
8  members.each((member) => {
9    console.log(member.id, member.info.name);
10  });
11});
12
13// Fired when a new member joins
14presence.bind("pusher:member_added", (member) => {
15  console.log(`${member.info.name} joined`);
16});
17
18// Fired when a member leaves
19presence.bind("pusher:member_removed", (member) => {
20  console.log(`${member.info.name} left`);
21});

Auth Response Format Reference

For reference, here are the exact response formats your auth endpoint should return. The Pusher server libraries handle this for you, but it is useful to understand the format for debugging.

Private Channel Response

Response
json
{
  "auth": "APP_KEY:HMAC_SHA256_SIGNATURE"
}

// The signature is computed as:
// HMAC_SHA256(app_secret, socket_id + ":" + channel_name)

Presence Channel Response

Response
json
{
  "auth": "APP_KEY:HMAC_SHA256_SIGNATURE",
  "channel_data": "{"user_id":"123","user_info":{"name":"Alice"}}"
}

// The signature is computed as:
// HMAC_SHA256(app_secret, socket_id + ":" + channel_name + ":" + channel_data)

Info

Note that channel_data is a JSON string, not a nested object. The Pusher server libraries handle this serialization automatically.

Next Steps