Instala estas 3 librerías que se encargarán de generar los tokens JWT:
1npm install express-jwt @types/express-jwt jsonwebtoken @types/jsonwebtoken --save
El segundo paso es crear una ruta API que pueda ser llamada por el cliente para generar un token (también conocido como login), esta ruta recibirá el email
y password
del body
y buscará cualquier usuario en la base de datos que coincida con esos dos valores.
Si encuentra el valor, generará un token llamando a la función jwt.sign
.
1//esta línea va en tu public_routes.ts 2router.post('/token', safe(createToken)); 3 4// esta función va en tu actions.ts 5import jwt from 'jsonwebtoken' 6 7export const createToken = async (req: Request, res: Response): Promise<Response> =>{ 8 9 if(!req.body.email) throw new Exception("Please specify an email on your request body", 400) 10 if(!req.body.password) throw new Exception("Please specify a password on your request body", 400) 11 12 const userRepo = await getRepository(Users) 13 14 // Necesitamos validar que existe un usuario con este email y contraseña en la BD 15 const user = await userRepo.findOne({ where: { email: req.body.email, password: req.body.password }}) 16 if(!user) throw new Exception("Invalid email or password", 401) 17 18 // esta es la línea más importante en esta función, se crea un token JWT 19 const token = jwt.sign({ user }, process.env.JWT_KEY as string); 20 21 // devolver al cliente el usuario y el token creado recientemente 22 return res.json({ user, token }); 23}
Ahora tenemos que añadir un middleware que buscará el token en el Encabezado de autorización de la petición. El middleware interceptará cada petición y ejecuta la función next
para avanzar solo si logra validar el token, en caso contrario retornará un error.
Añade estos dos middlewares dentro de ./src/app.js
que se encargarán de hacer cumplir el token.
1// ⬆ todo lo ANTERIOR es público 2import jwt, { Options } from 'express-jwt'; 3 4let opt: Options = { secret: process.env.JWT_KEY as string, algorithms: ["HS256"] } 5app.use(jwt(opt)) 6// ⬇ todo lo que esté POR DEBAJO es público 7app.use(((err: any, req: any, res: any, next: any) => { 8 if (err) console.error(err); 9 if (err.name === 'UnauthorizedError') { 10 return res.status(401).json({ status: err.message }); 11 } 12 next(); 13}))
Cualquier endpoint que se añada DEBAJO de estos middlewares será privado, por ejemplo:
1app.get('/public', (req, res) => { 2 res.json({ message: "Anyone can see me" }); 3}) 4 5// ⬆ anything ABOVE is public 6app.use(jwt(opt)) // ⬅ JWT Middleware 7// ⬇ anything BELOW is public 8 9app.get('/private', (req, res) => { 10 res.json({ message: "If you can se me, you are logged in" }); 11})
Hemos terminado, pero si sólo los usuarios registrados pueden llamar a nuestros endpoints privados, entonces necesitamos una forma de saber quién los está llamando, por ejemplo podemos usar req.user
de ahora en adelante, para identificar al usuario de la petición:
1export const getMe = async (req: Request, res: Response): Promise<Response> =>{ 2 3 const users = await getRepository(Users).find({ where: }); 4 // ⬇ no procedentes de la BD 5 return res.json(req.auth); 6}
O podemos utilizar esa información y obtener más información del solicitante de la base de datos.
1export const getMe = async (req: Request, res: Response): Promise<Response> =>{ 2 3 4 // ⬇ not comming from the BD 5 return res.json(req.auth); 6}