{"id":16596,"library":"ag-auth","title":"ag-auth (SocketCluster Auth Module)","description":"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.","status":"active","version":"2.1.1","language":"javascript","source_language":"en","source_url":null,"tags":["javascript","auth","jwt","socketcluster"],"install":[{"cmd":"npm install ag-auth","lang":"bash","label":"npm"},{"cmd":"yarn add ag-auth","lang":"bash","label":"yarn"},{"cmd":"pnpm add ag-auth","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core dependency for creating, signing, and verifying JWTs.","package":"jsonwebtoken","optional":false},{"reason":"Provides standardized error classes for SocketCluster, used for authentication-related errors.","package":"sc-errors","optional":false}],"imports":[{"note":"While `AuthEngine` can be imported for custom setups or direct usage, most users interact with `ag-auth` indirectly via the `agServer.auth` object within a SocketCluster worker.","wrong":"const AuthEngine = require('ag-auth');","symbol":"AuthEngine","correct":"import { AuthEngine } from 'ag-auth';"},{"note":"Type import for configuring JWT signing, primarily used with TypeScript for better type safety.","wrong":null,"symbol":"SignTokenOptions","correct":"import { SignTokenOptions } from 'ag-auth';"},{"note":"Type import for configuring JWT verification, primarily used with TypeScript for better type safety.","wrong":null,"symbol":"VerifyTokenOptions","correct":"import { VerifyTokenOptions } from 'ag-auth';"}],"quickstart":{"code":"import { AGServer } from 'socketcluster-server';\nimport { AuthEngine } from 'ag-auth'; // Although usually accessed via agServer.auth\n\nconst SECRET_KEY = process.env.AUTH_SECRET_KEY ?? 'my-secret-key-123';\n\nconst agServer = new AGServer({\n  authKey: SECRET_KEY,\n  // If you were to override the default auth engine, you might do:\n  // authEngine: new AuthEngine(SECRET_KEY)\n});\n\n(async () => {\n  for await (const { socket } of agServer.listen()) {\n    (async () => {\n      // This is how ag-auth functionality is typically accessed\n      // via the agServer instance.\n      const tokenData = { username: 'testuser', roles: ['admin'] };\n\n      try {\n        // Sign a token using the configured authEngine (ag-auth)\n        const token = await agServer.auth.signToken(tokenData, { expiresIn: '1h' });\n        console.log(`Signed JWT: ${token}`);\n\n        // Simulate client sending token and server verifying\n        socket.on('login', async (data) => {\n          try {\n            const decodedToken = await agServer.auth.verifyToken(data.token);\n            console.log(`Socket ${socket.id} authenticated:`, decodedToken);\n            socket.emit('authSuccess', { message: 'Authenticated successfully', user: decodedToken.username });\n          } catch (error) {\n            console.error(`Socket ${socket.id} authentication failed:`, error.message);\n            socket.emit('authFail', { message: 'Authentication failed', error: error.message });\n          }\n        });\n\n        // Example: Client attempts to log in\n        setTimeout(() => {\n          console.log('Simulating client login attempt...');\n          socket.emit('login', { token: token });\n        }, 1000);\n\n      } catch (error) {\n        console.error('Error during auth setup:', error);\n      }\n    })();\n  }\n})();\n\nconsole.log('SocketCluster server is listening for connections...');\n","lang":"typescript","description":"This quickstart demonstrates how `ag-auth` (via `agServer.auth`) is used to sign and verify JWT tokens in a SocketCluster server, handling client authentication."},"warnings":[{"fix":"Update all calls to `agServer.auth.signToken` and `agServer.auth.verifyToken` (and similar) to use `await` or `.then()` for Promise resolution.","message":"SocketCluster v15+ transitioned authentication functions to return Promises instead of accepting callbacks. Code relying on callback-based `agServer.auth` methods will break.","severity":"breaking","affected_versions":">=15.0.0"},{"fix":"Refactor authentication logic to exclusively use JWTs, leveraging `agServer.auth.signToken` and `agServer.auth.verifyToken` for all authentication flows. Migrate any persistent session data to be included within JWT payloads or external stores.","message":"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.","severity":"breaking","affected_versions":">=1.3.0"},{"fix":"Only store non-sensitive user identifiers (e.g., user ID, roles) in JWT payloads. Fetch sensitive user data from a secure database or service after verifying the token.","message":"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.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always use a strong, randomly generated, long secret key for `agServer.authKey`. Store it securely (e.g., in environment variables) and rotate it periodically. Never hardcode it in source code.","message":"Using a weak or compromised `authKey` (secret) makes JWTs vulnerable to forgery. An attacker could sign their own tokens and impersonate users.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure 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.","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.","error":"JsonWebTokenError: invalid signature"},{"fix":"Implement 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.","cause":"The JWT's expiration time (`exp` claim) has passed, making the token invalid.","error":"TokenExpiredError: jwt expired"},{"fix":"Pass a secure secret key to the `authKey` option of the `AGServer` constructor: `new AGServer({ authKey: process.env.AUTH_SECRET_KEY });`","cause":"The `authKey` option was not provided to the `AGServer` constructor, which is required for `ag-auth` to sign and verify tokens.","error":"No authKey was specified when creating the AGServer instance."}],"ecosystem":"npm"}