ag-auth (SocketCluster Auth Module)
ag-auth is the official authentication module for SocketCluster (now Asyngular), providing a robust mechanism for securing real-time applications using JSON Web Tokens (JWT). It handles the signing, verification, and management of authentication tokens. Currently at version 2.1.1, the package is actively maintained, with the latest significant update published in November 2025. It serves as the underlying engine for SocketCluster's `agServer.auth` object, abstracting the complexities of JWT handling. While alternative methods for JWT exist (e.g., direct `jsonwebtoken` usage), ag-auth integrates seamlessly into the SocketCluster ecosystem, offering a standardized and convenient approach to user authentication across HTTP and WebSocket flows. Its primary differentiator is this tight integration, ensuring compatibility and streamlined development within SocketCluster projects.
Common errors
-
JsonWebTokenError: invalid signature
cause The JWT provided by the client was signed with a different secret key than the one the server is using for verification, or the token has been tampered with.fixEnsure the `authKey` used when initializing `AGServer` is identical to the key used to sign the token. Check for accidental whitespace or character discrepancies. If tokens are issued by an external service, verify key synchronization. -
TokenExpiredError: jwt expired
cause The JWT's expiration time (`exp` claim) has passed, making the token invalid.fixImplement token refresh mechanisms on the client-side, where a valid refresh token is used to obtain a new access token before the current one expires. Configure appropriate `expiresIn` values during token signing. -
No authKey was specified when creating the AGServer instance.
cause The `authKey` option was not provided to the `AGServer` constructor, which is required for `ag-auth` to sign and verify tokens.fixPass a secure secret key to the `authKey` option of the `AGServer` constructor: `new AGServer({ authKey: process.env.AUTH_SECRET_KEY });`
Warnings
- breaking SocketCluster v15+ transitioned authentication functions to return Promises instead of accepting callbacks. Code relying on callback-based `agServer.auth` methods will break.
- breaking Prior to SocketCluster v1.3.0, authentication was session-based. Since v1.3.0, it shifted entirely to JSON Web Tokens (JWT). Direct session manipulation methods are deprecated.
- gotcha JWTs are signed, not encrypted. Do not store sensitive or secret data directly in the token's payload, as it can be easily read by anyone with access to the token.
- gotcha Using a weak or compromised `authKey` (secret) makes JWTs vulnerable to forgery. An attacker could sign their own tokens and impersonate users.
Install
-
npm install ag-auth -
yarn add ag-auth -
pnpm add ag-auth
Imports
- AuthEngine
const AuthEngine = require('ag-auth');import { AuthEngine } from 'ag-auth'; - SignTokenOptions
import { SignTokenOptions } from 'ag-auth'; - VerifyTokenOptions
import { VerifyTokenOptions } from 'ag-auth';
Quickstart
import { AGServer } from 'socketcluster-server';
import { AuthEngine } from 'ag-auth'; // Although usually accessed via agServer.auth
const SECRET_KEY = process.env.AUTH_SECRET_KEY ?? 'my-secret-key-123';
const agServer = new AGServer({
authKey: SECRET_KEY,
// If you were to override the default auth engine, you might do:
// authEngine: new AuthEngine(SECRET_KEY)
});
(async () => {
for await (const { socket } of agServer.listen()) {
(async () => {
// This is how ag-auth functionality is typically accessed
// via the agServer instance.
const tokenData = { username: 'testuser', roles: ['admin'] };
try {
// Sign a token using the configured authEngine (ag-auth)
const token = await agServer.auth.signToken(tokenData, { expiresIn: '1h' });
console.log(`Signed JWT: ${token}`);
// Simulate client sending token and server verifying
socket.on('login', async (data) => {
try {
const decodedToken = await agServer.auth.verifyToken(data.token);
console.log(`Socket ${socket.id} authenticated:`, decodedToken);
socket.emit('authSuccess', { message: 'Authenticated successfully', user: decodedToken.username });
} catch (error) {
console.error(`Socket ${socket.id} authentication failed:`, error.message);
socket.emit('authFail', { message: 'Authentication failed', error: error.message });
}
});
// Example: Client attempts to log in
setTimeout(() => {
console.log('Simulating client login attempt...');
socket.emit('login', { token: token });
}, 1000);
} catch (error) {
console.error('Error during auth setup:', error);
}
})();
}
})();
console.log('SocketCluster server is listening for connections...');