// src/middlewares/auth.ts

// ...

export function ensureAuthViaQuery(req: AuthenticatedRequest, res: Response, next: NextFunction) {
  const { token } = req.query

  if (!token) {
    return res.status(401).json({ message: 'Não autorizado: nenhum token encontrado' })
  }

  if (typeof token !== 'string') {
    return res.status(400).json({ message: 'O parâmetro token deve ser do tipo string' })
  }

  jwtService.verifyToken(token, (err, decoded) => {
    if (err || typeof decoded === 'undefined') {
      return res.status(401).json({ message: 'Não autorizado: token inválido' })
    }

    userService.findByEmail((decoded as JwtPayload).email).then(user => {
      req.user = user
      next()
    })
  })
}
// src/routes.ts

// ...

router.get('/episodes/stream', ensureAuthViaQuery, episodesController.stream)

export { router }
// public/video.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Testando Streaming</title>
</head>
<body>

  <h2>Testando Streaming</h2>

  <video id="videoplayer" controls>
    <source src="/episodes/stream?videoUrl=videos/course-1/configuracao-obs-canvas.mp4&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiZmlyc3RfbmFtZSI6IklzYWFjIiwiZW1haWwiOiJpc2FhY0BlbWFpbC5jb20iLCJpYXQiOjE2NDUxNDg2NzksImV4cCI6MTY0NTc1MzQ3OX0.W-VKdPX3daCIicpsXgC_pWgIcerXpgwFcegxjNwA2Ms" type="video/mp4">
  </video>

  <script>
    var myvideo = document.getElementById('videoplayer')
    myvideo.currentTime = 70;
    myvideo.play();
  </script>
</body>
</html>