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:
- 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.
- 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
| Credential | Purpose | Where to Use | Public? |
|---|---|---|---|
App Key | Identifies your app on WebSocket connections | Client-side (browser, mobile app) | Yes |
App Secret | Signs API requests and channel auth responses | Server-side only | No |
App ID | Identifies your app in REST API URLs | Server-side only | No |
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:
- Dashboard Go to Dashboard and select your app.
- Navigate to the tab. Settings
- Your App ID, App Key, and App Secret are displayed in the Credentials section.
- 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:
SOKETIFY_APP_ID=your-app-id
SOKETIFY_APP_KEY=your-app-key
SOKETIFY_APP_SECRET=your-app-secretSecret Rotation Strategy
Rotating your App Secret is a best practice for maintaining security. Soketify supports seamless secret rotation:
- Generate a new secret — In the Dashboard, click Rotate Secret on your app settings page. The new secret is generated but not yet active.
- Update your server — Deploy the new secret to your server environment variables. During the grace period, both the old and new secrets are accepted.
- 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:
Auth Endpoint Implementation (Node.js / Express)
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:
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
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
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
{
"auth": "APP_KEY:HMAC_SHA256_SIGNATURE"
}
// The signature is computed as:
// HMAC_SHA256(app_secret, socket_id + ":" + channel_name)Presence Channel Response
{
"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
- Learn about all channel types and when to use each one
- Explore the REST API for triggering events from your server
- Migrate from Pusher if you are switching from an existing Pusher setup