Middlewares
A middleware function is a function that gets executed for every incoming connection.
Middleware functions can be useful for:
- logging
- authentication / authorization
- rate limiting
Note: this function will be executed only once per connection (even if the connection consists in multiple HTTP requests).
Registering a middleware
A middleware function has access to the Socket instance and to the next registered middleware function.
io.use((socket, next) => { if (isValid(socket.request)) { next(); } else { next(new Error("invalid")); } }); |
You can register several middleware functions, and they will be executed sequentially:
io.use((socket, next) => { next(); }); io.use((socket, next) => { next(new Error("thou shall not pass")); }); io.use((socket, next) => { // not executed, since the previous middleware has returned an error next(); }); |
Please make sure to call next()
in any case. Otherwise, the connection will be left hanging until it is closed after a given timeout.
Sending credentials
The client can send credentials with the auth
option:
// plain object const socket = io({ auth: { token: "abc" } }); // or with a function const socket = io({ auth: (cb) => { cb({ token: "abc" }); } }); |
Those credentials can be accessed in the handshake object on the server-side:
io.use((socket, next) => { const token = socket.handshake.auth.token; // ... }); |
Handling middleware error
If the next
method is called with an Error object, the connection will be refused and the client will receive an connect_error
event.
// client-side socket.on("connect_error", (err) => { console.log(err.message); // prints the message associated with the error }); |
You can attach additional details to the Error object:
// server-side io.use((socket, next) => { const err = new Error("not authorized"); err.data = { content: "Please retry later" }; // additional details next(err); }); // client-side socket.on("connect_error", (err) => { console.log(err instanceof Error); // true console.log(err.message); // not authorized console.log(err.data); // { content: "Please retry later" } }); |
Compatibility with Express middleware
Most existing Express middleware modules should be compatible with Socket.IO, you just need a little wrapper function to make the method signatures match:
const wrap = middleware => (socket, next) => middleware(socket.request, {}, next); |
The middleware functions that end the request-response cycle and do not call next()
will not work though.
Example with express-session:
const session = require("express-session"); io.use(wrap(session({ secret: "cats" }))); io.on("connection", (socket) => { const session = socket.request.session; }); |
Example with Passport:
const session = require("express-session"); const passport = require("passport"); io.use(wrap(session({ secret: "cats" }))); io.use(wrap(passport.initialize())); io.use(wrap(passport.session())); io.use((socket, next) => { if (socket.request.user) { next(); } else { next(new Error("unauthorized")) } }); |
A complete example with Passport can be found here.
© 2014–2021 Automattic
Licensed under the MIT License.
https://socket.io/docs/v3/middlewares