Fastify JWT Auth Guard Decorator
Protect Fastify routes with the JWT plugin via preHandler guards, verifying tokens once and exposing typed claims to handlers.
Code
import Fastify from 'fastify';
import jwt from '@fastify/jwt';
interface TokenClaims {
sub: string;
role: 'admin' | 'editor' | 'viewer';
}
declare module 'fastify' {
interface FastifyRequest {
user: TokenClaims;
}
}
const app = Fastify({ logger: true });
await app.register(jwt, {
secret: process.env.JWT_SECRET ?? 'dev-secret-change-me',
sign: { expiresIn: '15m' },
});
function requireRole(...roles: TokenClaims['role'][]) {
return async (req: Fastify.FastifyRequest, reply: Fastify.FastifyReply) => {
try {
await req.jwtVerify<TokenClaims>();
} catch {
return reply.code(401).send({ error: 'invalid or expired token' });
}
if (!roles.includes(req.user.role)) {
return reply.code(403).send({ error: 'insufficient role' });
}
};
}
app.get('/me', { preHandler: requireRole('viewer', 'editor', 'admin') },
async (req) => ({ userId: req.user.sub, role: req.user.role }),
);
app.post('/admin/purge', { preHandler: requireRole('admin') },
async (req, reply) => reply.code(202).send({ purged: true, by: req.user.sub }),
);
app.inject({
method: 'GET',
url: '/me',
headers: { authorization: 'Bearer ' + app.jwt.sign({ sub: 'u-1', role: 'viewer' }) },
}).then((res) => console.log('status:', res.statusCode));Report a problem with this exampleOpens a pre-filled issue on GitHub.