Fastify with JWT Integration
Preparation
Ensure Fastify and the fastify-jwt plugin are installed:
npm install fastify @fastify/jwtConfiguring the JWT Plugin
Register the fastify-jwt plugin with a secret key for signing and verifying JWTs:
const fastify = require('fastify')({ logger: true });
fastify.register(require('@fastify/jwt'), {
secret: 'your-secret-key'
});Creating User and Login Endpoint
Create a simple user model and login endpoint, assuming a user database exists:
const users = [
{ username: 'john', password: 'password123' },
{ username: 'jane', password: 'secret456' }
];
fastify.post('/login', async (request, reply) => {
const { username, password } = request.body;
const user = users.find(u => u.username === username && u.password === password);
if (!user) {
throw new Error('Invalid credentials');
}
const token = await reply.jwtSign({ sub: user.username });
return { token };
});Protecting Routes
Use the authenticate method to protect routes:
fastify.get('/protected', { preValidation: [fastify.authenticate] }, async (request, reply) => {
return { user: request.user.sub };
});Parsing JWT
The fastify-jwt plugin parses JWTs and attaches the result to request.user:
fastify.get('/profile', { preValidation: [fastify.authenticate] }, async (request, reply) => {
return { username: request.user.sub, email: request.user.email };
});Error Handling
Handle invalid or expired JWTs with a global error handler:
fastify.setErrorHandler((error, request, reply) => {
if (error.statusCode === 401) {
reply.code(401).send({ error: 'Unauthorized' });
} else {
reply.code(500).send({ error: 'Internal server error' });
}
});Complete Example
A full example of JWT integration:
const fastify = require('fastify')({ logger: true });
fastify.register(require('@fastify/jwt'), {
secret: 'your-secret-key'
});
const users = [
{ username: 'john', password: 'password123', email: 'john@example.com' },
{ username: 'jane', password: 'secret456', email: 'jane@example.com' }
];
fastify.post('/login', async (request, reply) => {
const { username, password } = request.body;
const user = users.find(u => u.username === username && u.password === password);
if (!user) {
throw new Error('Invalid credentials');
}
const token = await reply.jwtSign({ sub: user.username, email: user.email });
return { token };
});
fastify.get('/protected', { preValidation: [fastify.authenticate] }, async (request, reply) => {
return { user: request.user.sub };
});
fastify.setErrorHandler((error, request, reply) => {
if (error.statusCode === 401) {
reply.code(401).send({ error: 'Unauthorized' });
} else {
reply.code(500).send({ error: 'Internal server error' });
}
});
const start = async () => {
try {
await fastify.listen({ port: 3000 });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();Fastify with OAuth2 Integration
Installing Required Packages
Install packages for OAuth2, such as fastify-oauth2 or node-oauth2-server. Here, we use node-oauth2-server to build an OAuth2 server:
npm install node-oauth2-server fastify @fastify/pluginConfiguring OAuth2 Server
Set up an OAuth2 server with models for User, Client, AccessToken, and RefreshToken:
const Fastify = require('fastify');
const OAuth2Server = require('node-oauth2-server');
const fastifyPlugin = require('@fastify/plugin');
const User = require('./models/user');
const Client = require('./models/client');
const AccessToken = require('./models/access_token');
const RefreshToken = require('./models/refresh_token');
const fastify = Fastify();
const oauth = new OAuth2Server({
model: {
getClient: Client.getClient,
saveAuthorizationCode: Client.saveAuthorizationCode,
getAuthorizationCode: Client.getAuthorizationCode,
getAccessToken: AccessToken.getAccessToken,
saveToken: AccessToken.saveToken,
getUser: User.getUser,
getRefreshToken: RefreshToken.getRefreshToken,
saveRefreshToken: RefreshToken.saveRefreshToken
},
grants: ['authorization_code', 'refresh_token'],
debug: true
});
fastify.register(fastifyPlugin(async (instance) => {
instance.decorate('oauth', oauth);
}));
fastify.get('/oauth/authorize', async (request, reply) => {
return oauth.authorize(request, reply);
});
fastify.post('/oauth/token', async (request, reply) => {
return oauth.token(request, reply);
});
const start = async () => {
try {
await fastify.listen({ port: 3000 });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();Implementing Authorization Logic
Implement user authorization, typically involving a UI for consent:
fastify.get('/oauth/authorize', async (request, reply) => {
const { client_id, redirect_uri } = request.query;
// Render UI for user consent (hypothetical)
if (userConsents) {
const code = await oauth.authorize({
client: { id: client_id },
redirectUri: redirect_uri,
user: request.user,
responseType: 'code'
});
reply.redirect(`${redirect_uri}?code=${code}`);
} else {
reply.code(403).send({ error: 'Consent denied' });
}
});Using OAuth2 Client
Use Fastify as an OAuth2 client to obtain access tokens:
const fastify = require('fastify')();
const { OAuth2Client } = require('simple-oauth2');
const client = new OAuth2Client({
client: {
id: 'your-client-id',
secret: 'your-client-secret'
},
auth: {
tokenHost: 'https://provider.example.com',
authorizePath: '/oauth/authorize',
tokenPath: '/oauth/token'
}
});
fastify.get('/login', async (request, reply) => {
const authorizationUri = client.authorizationCode.authorizeURL({
redirect_uri: 'http://localhost:3000/callback',
scope: 'read write'
});
reply.redirect(authorizationUri);
});
fastify.get('/callback', async (request, reply) => {
const { code } = request.query;
try {
const token = await client.authorizationCode.getToken({
code,
redirect_uri: 'http://localhost:3000/callback'
});
return { token };
} catch (err) {
reply.code(500).send({ error: 'Failed to obtain token' });
}
});Protecting Resources
Verify access tokens to protect resources:
fastify.get('/protected-resource', async (request, reply) => {
const accessToken = request.headers.authorization?.split(' ')[1];
const token = await AccessToken.findOne({ token: accessToken });
if (!token) {
reply.code(401).send({ error: 'Unauthorized' });
} else {
reply.send({ resource: 'Protected resource' });
}
});



