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) }),
}));