Authentication
info
Use AdditionalRequest to share data between hooks and controller.
Examples
- @fastify/jwt
- @fastify/auth
- express-jwt
- express-passport
- npm
- yarn
cd server
npm install @fastify/jwt
cd server
yarn add @fastify/jwt
Register the plugin
$/service/app.ts
import Fastify, { FastifyServerFactory } from 'fastify';
import fastifyJwt from '@fastify/jwt';
import { API_JWT_SECRET, API_BASE_PATH } from '$/service/envValues';
import server from './$server';
export const init = (serverFactory?: FastifyServerFactory) => {
const app = Fastify({ serverFactory });
app.register(fastifyJwt, { secret: API_JWT_SECRET });
server(app, { basePath: API_BASE_PATH });
return app;
};
Issue tokens
$/api/token/controller.ts
import { defineController } from './$relay';
import { validateUser } from '$/service/user';
export default defineController((fastify) => ({
post: ({ body }) =>
validateUser(body.id, body.pass)
? { status: 201, body: { token: fastify.jwt.sign({ id: body.id }) } }
: { status: 401 },
}));
Verify tokens
Although @fastify/jwt extends FastifyRequest, it is not reflected to the controller, so you need to prepare it yourself in order to reference it in the controller.
Relaying of type extended by plugins
$/api/user/hooks.ts
import { defineHooks } from './$relay';
export type AdditionalRequest = {
user: {
id: string;
};
};
export default defineHooks(() => ({
onRequest: (request, reply) => request.jwtVerify().catch((err) => reply.send(err)),
}));
$/api/user/controller.ts
import { defineController } from './$relay';
import { getUserNameById } from '$/service/user';
export default defineController(() => ({
get: async ({ user }) => ({ status: 200, body: await getUserNameById(user.id) }),
// ^^^^ extended by AdditionalRequest
}));
- npm
- yarn
cd server
npm install @fastify/auth
cd server
yarn add @fastify/auth
Register the plugin
$/service/app.ts
import Fastify, { FastifyServerFactory } from 'fastify';
import fastifyAuth from '@fastify/auth';
import { API_JWT_SECRET, API_BASE_PATH } from '$/service/envValues';
import server from './$server';
export const init = (serverFactory?: FastifyServerFactory) => {
const app = Fastify({ serverFactory });
app.register(fastifyAuth);
server(app, { basePath: API_BASE_PATH });
return app;
};
Verify tokens
$/api/user/hooks.ts
import { defineHooks } from './$relay';
import { getUserIdByToken } from '$/service/user';
export type AdditionalRequest = {
user: {
id: string;
};
};
export default defineHooks((fastify) => ({
preHandler: fastify.auth([
(req, _, done) => {
const user = typeof req.headers.token === 'string' && getUserIdByToken(req.headers.token);
if (user) {
// eslint-disable-next-line
// @ts-expect-error
req.user = user;
done();
} else {
done(new Error('Unauthorized'));
}
},
]),
}));
$/api/user/controller.ts
import { defineController } from './$relay';
import { getUserNameById } from '$/service/user';
export default defineController(() => ({
// user was added by AdditionalRequest of ./hooks.ts
get: async ({ user }) => ({ status: 200, body: await getUserNameById(user.id) }),
}));
- npm
- yarn
cd server
npm install express-jwt
npm install -D @types/express-jwt @types/jsonwebtoken
cd server
yarn add express-jwt
yarn add -D @types/express-jwt @types/jsonwebtoken
Issue tokens
$/api/token/controller.ts
import jwt from 'jsonwebtoken';
import { defineController } from './$relay';
import { validateUser } from '$/service/user';
export default defineController(() => ({
post: ({ body }) =>
validateUser(body.id, body.pass)
? { status: 201, body: { token: jwt.sign({ id: body.id }, process.env.JWT_SECRET) } }
: { status: 401 },
}));
Verify tokens
$/api/user/hooks.ts
import jwt from 'express-jwt';
import { defineHooks } from './$relay';
export type AdditionalRequest = {
user: {
id: string;
};
};
export default defineHooks(() => ({
onRequest: jwt({ secret: process.env.JWT_SECRET, algorithms: ['HS256'] }),
}));
$/api/user/controller.ts
import { defineController } from './$relay';
import { getUserNameById } from '$/service/user';
export default defineController(() => ({
// user was added by AdditionalRequest of ./hooks.ts
get: async ({ user }) => ({ status: 200, body: await getUserNameById(user.id) }),
}));
- npm
- yarn
cd server
npm install passport passport-trusted-header
npm install -D @types/passport
cd server
yarn add passport passport-trusted-header
yarn add -D @types/passport
Verify tokens
$/api/user/hooks.ts
import passport from 'passport';
import { defineHooks } from './$relay';
import { getUserIdByToken } from '$/service/user';
export type AdditionalRequest = {
user: {
id: string;
};
};
passport.use(
// eslint-disable-next-line
new (require('passport-trusted-header').Strategy)(
{ headers: ['token'] },
// eslint-disable-next-line
(headers: { token: string }, done: Function) => {
done(null, getUserIdByToken(headers.token));
},
),
);
export default defineHooks(() => ({
onRequest: [passport.initialize(), passport.authenticate('trusted-header', { session: false })],
}));
$/api/user/controller.ts
import { defineController } from './$relay';
import { getUserNameById } from '$/service/user';
export default defineController(() => ({
// user was added by AdditionalRequest of ./hooks.ts
get: async ({ user }) => ({ status: 200, body: await getUserNameById(user.id) }),
}));