npm i jsonwebtoken@~8.5.1
// src/models/user.ts

import { database } from '../database'
import { DataTypes, Model, Optional } from 'sequelize'
import bcrypt from 'bcrypt'

type CheckPasswordCallback = (err: Error | undefined, isSame: boolean) => void

export interface UserAttributes {
  id: number

// ...
// src/models/user.ts

// ...

type CheckPasswordCallback = (err: Error | undefined, isSame: boolean) => void

// ...

export interface UserInstance extends Model<UserAttributes, UserCreationAttributes>, UserAttributes {
  checkPassword: (password: string, callbackfn: CheckPasswordCallback) => void
}

// ...
// src/models/user.ts

// ...

}, {
  hooks: {
    beforeSave: async (user) => {
      if (user.isNewRecord || user.changed('password')) {
        user.password = await bcrypt.hash(user.password.toString(), 10);
      }
    }
  }
})

User.prototype.checkPassword = function (password: string, callbackfn: (err: Error | undefined, isSame: boolean) => void) {
  bcrypt.compare(password, this.password, (err, isSame) => {
    if (err) {
      callbackfn(err, false)
    } else {
      callbackfn(err, isSame)
    }
  })
}
// src/services/jwtService.ts

import jwt from 'jsonwebtoken'

const secret = 'chave-jwt'

export const jwtService = {
  signToken: (payload: string | object | Buffer, expiration: string) => {
    return jwt.sign(payload, secret, { expiresIn: expiration })
  }
}
// src/controllers/authController.ts

import { Request, Response } from 'express'
import { jwtService } from '../services/jwtService'

// ...

	},

  // POST /auth/login
  login: async (req: Request, res: Response) => {
    const { email, password } = req.body

    try {
      const user = await userService.findByEmail(email)

      if (!user) {
        return res.status(401).json({ message: 'E-mail não registrado' })
      }

      user.checkPassword(password, (err, isSame) => {
        if (err) {
          return res.status(400).json({ message: err.message })
        }

        if (!isSame) {
          return res.status(401).json({ message: 'Senha incorreta' })
        }

				const payload = {
          id: user.id,
          firstName: user.firstName,
          email: user.email
        }

        const token = jwtService.signPayload(payload, '7d')

        return res.json({ authenticated: true, user, token })
      })
    } catch (err) {
      if (err instanceof Error) {
        return res.status(400).json({ message: err.message })
      }
    }
  }
}
// src/routes.ts

// ...

router.post('/auth/register', authController.register)
router.post('/auth/login', authController.login)

// ...