Skip to main content

Authentication

Efesto does not ship an authentication system. It gives you two hooks and runs them around every request; what happens inside them, JWT, sessions, API keys, OAuth, is your code. This page documents exactly what those hooks are and where they run.

What Efesto actually provides
  • Express: a global authMiddleware you pass to efesto(), plus a per-method override (_<method>OverrideAuth).
  • Bun/Elysia: nothing Efesto-specific. You authenticate natively in setup (e.g. onBeforeHandle), because that hook runs on the root before routes mount.

Anything else (verifying a token, looking up a user, refreshing a session) lives in your middleware, not in the framework.

The global hook

You pass authMiddleware to efesto(). It runs before every resolver. To leave an app open, pass a middleware that just calls next():

import efesto from "efesto";

app.use(
"/api/v1",
efesto({
authMiddleware: (req, res, next) => {
// verify the request here; attach anything you need to `req`
// call next(err) / throw to reject, or next() to allow
next();
},
errorMiddleware: (req, res, next) => next(),
isProduction: false,
options: { absoluteDirRoutes: `${__dirname}/routes` },
})
);

Whatever you attach to req inside this middleware is available in every Efesto method and in the ABAC check (see ABAC Permissions).

A realistic token-verification middleware is ordinary Express, Efesto does not wrap it:

const authMiddleware = (req, res, next) => {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) return res.status(401).json({ error: "Missing token" });
try {
req.user = verifyYourToken(token); // your logic / your library
next();
} catch {
res.status(401).json({ error: "Invalid token" });
}
};

Per-endpoint authentication (Express)

Not every endpoint needs the same rule. On the Express stack you override the global middleware for a single method by declaring _<method>OverrideAuth on the service. It is a plain middleware and replaces the global one for that verb only:

import { BaseApiService } from "efesto";
import type { Request, Response, NextFunction } from "express";

class Users extends BaseApiService {
constructor() {
super(__filename);
}

// public GET: skip the global auth entirely
_getOverrideAuth = (req: Request, res: Response, next: NextFunction) => {
next();
};

_get(req, res) {
return res.json(listUsers());
}

// POST still uses the global authMiddleware (no override declared)
_post(req, res) {
return res.json(createUser(req.body));
}
}
export default Users;
Elysia

There is no _overrideAuth equivalent. Per-route auth on the Elysia stack is done the idiomatic Elysia way (a guard / beforeHandle on the route module, or a scoped plugin), not through an Efesto convention.

Error handling (Express)

errorMiddleware is the second hook you pass to efesto(). It is wired into the Express chain so thrown errors and next(err) calls reach it. A pass-through is valid when you have nothing to handle:

errorMiddleware: (req, res, next) => next();

The ABAC check throws a CASL ForbiddenError when a permission fails, this is the error you most often handle here. See ABAC Permissions.

What Efesto does not do

These are common needs, but they are your application's responsibility, not framework features. Implement them inside your middleware:

  • Token verification / refresh, session stores, API-key lookup, OAuth flows.
  • Rate limiting, secure headers, CORS (use standard Express/Elysia middleware).

Once requests are authenticated, authorize them with ABAC.