@painda/auth
v0.1.8
Published
PaindaProtocol authentication middleware and JWT validators
Maintainers
Readme
🐼 @painda/auth
Secure, token-based authentication middleware for PaindaProtocol.
@painda/auth provides a robust, customizable authentication layer for your real-time applications. It supports JWT, API keys, and custom validation logic with built-in protection against slow-loris auth attacks and unauthorized connections.
⚡ Highlights
- Pluggable Validators: Use any async function to verify tokens (JWT, DB lookup, etc.).
- Automatic Enforcement: Protects your server by enforcing auth before any message handling.
- Timeout Protection: Automatically disconnects clients that fail to authenticate within a window.
- Guest Support: Configurable "allow-guest" mode for public rooms.
Installation
npm install @painda/auth @painda/coreAuthentication Flows
PaindaProtocol supports two authentication flows. Choose the one that fits your security requirements.
Flow 1: Query-Parameter Auth (Recommended for most use cases)
The client sends the token automatically as a ?token= query parameter on every (re)connection. This is handled by PPClient's getToken callback — no extra code needed on the client.
Client:
import { PPClient } from "@painda/client";
const client = new PPClient({
url: "ws://localhost:3000",
getToken: async () => {
// Called on EVERY connect & reconnect — always a fresh token
return await refreshJwtToken();
},
});
// Token is automatically appended as ?token=<value> on the WS URLServer (using server.use() middleware):
import { PPServer } from "@painda/core";
const server = new PPServer({ port: 3000 });
server.use(async (socket, next) => {
// Token arrives as ?token= query parameter
const url = new URL(`ws://x${socket.request.url}`);
const token = url.searchParams.get("token");
if (!token) return next(new Error("No token provided"));
try {
const user = await verifyJwt(token);
socket.data.user = user; // Attach user to socket
next();
} catch {
next(new Error("Invalid token"));
}
});
server.on("connection", (client) => {
console.log("Authenticated user:", client.data.user);
});Note: With PaindaProtocol's core client (
@painda/core/common/client), tokens are sent as the first binary frame after connect instead of URL query params. This avoids token leakage in proxy/server logs. The@painda/clientbrowser package uses URL query params for compatibility.
Flow 2: Post-Connect Authentication (via @painda/auth)
For scenarios where the token should not appear in the URL (e.g., strict security policies, proxy logging concerns). The client sends an authenticate message after connecting.
Server:
import { PPServer } from "@painda/core";
import { PPAuthMiddleware } from "@painda/auth";
const server = new PPServer({ port: 3000 });
const auth = new PPAuthMiddleware(server, {
validator: async (token) => {
const user = await verifyJwt(token);
if (!user) throw new Error("Invalid token");
return user; // Attached to socket as `userContext`
},
authTimeout: 5000, // Client has 5s to authenticate
allowGuest: false,
});
server.on("connection", (client) => {
if (auth.isAuthenticated(client)) {
const user = (client as any).userContext;
console.log("Authenticated:", user.name);
}
});Client:
import { PPClient } from "@painda/client";
const client = new PPClient({ url: "ws://localhost:3000" });
// After connecting, send the authenticate message manually:
client.on("open", async () => {
const token = await getStoredToken();
client.emit("authenticate", { token });
});
// Listen for auth result:
client.on("auth-success", () => console.log("✅ Authenticated!"));
client.on("auth-error", (err) => console.error("❌ Auth failed:", err));When to use which flow?
| Criterion | Flow 1: Query-Parameter | Flow 2: Post-Connect (@painda/auth) |
|-----------|------------------------|--------------------------------------|
| Simplicity | ✅ Automatic via getToken | 🔶 Manual authenticate message |
| JWT Refresh | ✅ Auto-refreshed on every reconnect | 🔶 Must re-send manually |
| Token Visibility | ⚠️ In URL (potential log/proxy exposure) | ✅ In message body only |
| Recommended for | Standard apps, games, SPAs | High-security, banking, enterprise |
Options
| Option | Default | Description |
|--------|---------|-------------|
| validator | required | (token) => user \| boolean — validate token and return user object |
| authTimeout | 5000 | Milliseconds before auto-disconnect for unauthenticated clients |
| allowGuest | false | Allow connections without a token (sets userContext.guest = true) |
Post-Connect Auth Flow
- Client connects → auth timer starts (
authTimeoutms) - Client sends
{ type: "authenticate", payload: { token } } - Validator runs → success:
auth-successresponse / fail: disconnect with code4002 - Timeout reached without auth → disconnect with code
4001
License
MIT License — free for private projects, open-source, and community use.
- Enterprise (Paid): Commercial projects above a certain company size or revenue threshold require a commercial license. Inquiries via pp.painda.tools/enterprise.
- Pro Plugins: Premium modules (Dashboard, Redis Adapter, Enterprise Support) available at pp.painda.tools/plugins.
