An open API service indexing awesome lists of open source software.

https://github.com/igorfonseca05/api-auth

Este projeto apresenta uma API de autenticação projetada para gerenciar o controle de acesso a dados restritos em websites. A aplicação utiliza pacotes como Express, cookie-parser, jsonwebtoken , entre outros, para fornecer uma solução segura e eficiente.
https://github.com/igorfonseca05/api-auth

api authentication igorfonseca05 node-js webdeveloper

Last synced: 3 months ago
JSON representation

Este projeto apresenta uma API de autenticação projetada para gerenciar o controle de acesso a dados restritos em websites. A aplicação utiliza pacotes como Express, cookie-parser, jsonwebtoken , entre outros, para fornecer uma solução segura e eficiente.

Awesome Lists containing this project

README

        

![Group 18](https://github.com/user-attachments/assets/9b79622d-c9d4-4029-a999-d9c6603b0a25)

# Índice

- [Introdução](#introdução)
- [Configurações iniciais](#configurações-iniciais)
- [Servidor 🖥️](#1---servidor)
- [server.js](#serverjs)
- [Rotas 🗺️](#2---router)
- [routes.js 🗺️](#21---routerjs)
- [auth.js 🔐](#22---authjs)
- [users.js 👥](#23---usersjs)
- [Controllers 🕹️](#3---controllers)
- [authController.js 🔒](#31---authcontrollerjs)
- [usersController 👥](#32---userscontrollerjs)
- [Base de dados 🗄️](#4---base-de-dados)
- [Model](#41---model)
- [userModel.js 📦](#411---usermodeljs)
- [Conectando a base de dados 💾](#42---conectando-a-base-de-dados)
- [db.js 🗄️](#421---dbjs)
- [1° atualização do servidor 🔄](#422---atualização-do-arquivo-serverjss)
- [2° atualização do servidor 🔄](#423---atualização-do-arquivo-serverjs)
- [Middlewares](#middlewares)
- [Middleware Validator](#middleware-validator)
- [userValidator.js](#uservalidatorjs)
- [Rotas 📍](#3--rotas)
- [signup](#signup)
- [Hash da senha](#hash)
- [Login](#login)

# Introdução

[Voltar ao topo 🔝](#índice)

API-authentication é um projeto desenvolvido em função da necessidade de se aplicar conhecimentos adquiridos em estudos
da linguagem **javascript** no lado do servidor em projetos reais. Criado com diversos pacotes publicos disponiveis no NPM, esse projeto dispoe de diversas funcionalidades como **sign-up**, **login** e entre outras. Essa documentação foi criada no intuito de servir como uma anotação para consultas futuras, de modo que todo o conteúdo apresentado aqui será o mais completo e detalhado possível.

# Configurações iniciais

[Voltar ao topo 🔝](#índice)

Neste projeto usaremos o modelo MVC(Model, viewers, controllers), onde a requisição chega ao servidor, é direcionada
ao routes que analisa qual endpoint buscar (auth/users), direcionando a solicitação ao Middleware que vai fazer algum
tipo de tratamento nos dados e chegar ao controller que é onde será respondida a solicitação. Esse fluxo pode ser visto
no diagrama abaixo

Client Request ---> Server ---> Routes.js ---> Middleware ---> Controller ---> Response

pois podemos trabalhar com separação de responsabilidades:

- **Routes:** Determinam "para onde" a requisição vai com base no endpoint.
- **Middleware:** Adiciona camadas para pré-processamento (como autenticação ou validação).
- **Controller:** Contém a lógica de processamento de requisições.
- **Response:** Contém a resposta da requisições.

Vamos iniciar a configuração do nosso projeto com base no fluxo mostrado acima, ou seja, vamos criar os arquivos server
Router e os demais de modo que as requisições fluem até o controller e então criaremos toda a lógica da resposta.

## 1 - Servidor

[Voltar ao topo 🔝](#índice)

Para iniciar o projeto, no terminal do VS Code dentro do diretório da pasta onde vai criar os arquivo do projeto digite

npm init

Usamos esse commando para criar um **package.json** na nossa aplicação, que será o responsável por armazenar as dependencias da aplicação. Com o arquivo criado precisamos instalar os pacotes iniciais que vamos utilizar para criar nossa API. No terminal digite

npm i express mongoose nodemon --save-dev dotenv

Eles serão adicionados ao package.json como dependencias. Na raiz do projeto deve-se criar o arquivo **server.js** que é onde será adicionada toda a lógica por trás do servidor.

### server.js

[Voltar ao topo 🔝](#índice)

```javascript
require(".dotenv").config(); // Carrega as variáveis de ambiente do arquivo .env para process.env

const express = require("express"); // Importa o framework Express para criar o servidor

const app = express(); // Cria uma instância do servidor com Express

// server config
const port = process.env.port || 5000; // Define a porta do servidor (process.env.port ou 5000)

app.get("/", (req, res) => {
res.send("Bem vindo a API"); // Configura a rota principal (/) para responder com "Bem vindo a API"
});

app.listen(port, () => {
console.log("Servidor on"); // Exibe mensagem indicando que o servidor está ativo
console.log(`Acesse em http://localhost:${port}`); // Informa a URL para acessar o servidor
});
```

## 2 - Router

[Voltar ao topo 🔝](#índice)

Aqui vamos configurar para onde nosso servidor vai redirecionar as requisições e quais rotas o usuário vai poder acessar. Para isso crie um pasta nomeada de **src** (source) na raiz do projeto, dentro dela a pasta **Routes**, que terá os arquivos **routes.js**, **users.js** e **auth.js** como mostrado abaixo:

API-Authentication
|
|- node_modules 🗃️
|
|--src 🗃️
| |-routes 📁
| |- users.js 📄
| |- auth.js 📄
| |- routes.js 📄
|
|- package.json 📄
|- server.js 📄

no arquivo **routes.js** faremos:

### 2.1 - router.js

[Voltar ao topo 🔝](#índice)

```javascript
const express = require("express"); // Importa o módulo 'express' para criar o roteador

const router = express.Router(); // Cria um novo roteador usando o express.Router()

// Controllers das rotas
const users = require("./users"); // Importa o arquivo 'users.js' para lidar com as rotas de usuários
const auth = require("./auth"); // Importa o arquivo 'task.js' para lidar com as rotas de tarefas

// Rotas para endpoint Users
router.use("/users", users); // Define que as rotas com '/users' serão tratadas pelo controlador 'users'
router.use("/auth", auth); // Define que as rotas com '/tasks' serão tratadas pelo controlador 'tasks'

module.exports = router; // Exporta o roteador para que ele possa ser usado em outros arquivos
```

nos arquivos **users** e **auth** que são importados acima, adicionaremos as rotas publicas e privadas do nosso sistema de autenticação, pode ser visto abaixo:

### 2.2 - auth.js

[Voltar ao topo 🔝](#índice)

```javascript const express = require('express')
const route = express.Router();

// Controllers
const authController = require("../controllers/authController");

// Routes
route.post("/signup", authController.signUp); // Rota para criar uma nova conta (signup)
route.post("/login", authController.signIn); // Rota para fazer login
route.post("/logout", authController.logout); // Rota para fazer logout (remover o token)
route.post("/logoutAll", authController.logoutAll); // Rota para fazer logout de todos os dispositivos

module.exports = route;
```

### 2.3 - users.js

[Voltar ao topo 🔝](#índice)

```javascript const express = require('express') // Importa o módulo 'express' para criar o roteador
const route = express.Router(); // Cria um novo roteador usando o express.Router()

// Controllers
const userController = require("../controllers/usersControllers"); // Importa o controlador de usuários, onde as funções de lógica estão.

// Routes
route.get("/profile", userController.getusers); // Rota para obter o perfil de usuário.
route.patch("/profile", userController.patchUser); // Rota para atualizar os dados do usuário.
route.delete("/profile", userController.deleteUser); // Rota para excluir a conta do usuário.

module.exports = route; // Exporta o roteador para que ele possa ser utilizado em outros arquivos
```

A função de processamento de cada uma dessas rotas foram colocadas dentro de seu respectivo **controller**, como podemos ver nas importações

```javascript
const authController = require("../controllers/authController");
const userController = require("../controllers/usersControllers");
```

é dentro desses controllers que iremos condensar todas as rotas que manipularão os dados e responderão os usuário.

# 3 - Controllers

[Voltar ao topo 🔝](#índice)

Com todas as rotas criadas e configuradas, vamos agora na pasta **controlers** e criar os arquivos **authController.js** e **usersControllers.js**, de modo que a estrutura do nosso projeto até o momento seja:

API-Authentication
|
|- node_modules 🗃️
|
|--src 🗃️
| |-Controller 📁
| |- authController.js 📄
| |- usersController.js 📄
| |-routes 📁
| |- users.js 📄
| |- auth.js 📄
| |- index.js 📄
|
|- package.json 📄
|- server.js 📄

Dentro desses arquivos faremos:

### 3.1 - authController.js

[Voltar ao topo 🔝](#índice)

```javascript
exports.signUp = async (req, res) => {}; // Controlador responsável por criar um novo usuário

exports.signIn = async (req, res) => {}; // Controlador responsável pelo login do usuário

exports.logout = async (req, res) => {}; // Controlador responsável por realizar o logout do usuário

exports.logoutAll = async (req, res) => {}; // Controlador responsável por realizar o logout de todos os dispositivos
```

### 3.2 - usersController.js

[Voltar ao topo 🔝](#índice)

```javascript
exports.getusers = async (req, res) => {}; // Rota para obter o perfil do usuário autenticado

exports.deleteUser = async (req, res) => {}; // Rota para excluir a conta do usuário

exports.patchUser = async (req, res) => {}; // Rota para atualizar as informações do usuário

exports.uploads = async (req, res) => {}; // Rota para realizar upload de foto de perfil

exports.deleteAvatar = async (req, res) => {}; // Rota para excluir a foto de perfil do usuário

exports.getAvatar = async (req, res) => {}; // Rota para obter a foto de perfil do usuário
```

Vamos adicionar a lógica necessaria em cada uma das rotas acima de modo decrescente.

# 4 - Base de dados

[Voltar ao topo 🔝](#índice)

Como vamos iniciar nossa API pela rota de signup, precisamos estabelecer a conexão com a base de dados, uma vez que
na rota em questão precisamos salvar as credenciais do usuário e isso só é possivel se tivermos onde salvar os dados.

## 4.1 - Model

[Voltar ao topo 🔝](#índice)

Um **model** em uma aplicação representa a estrutura e as regras de um dado armazenado no banco de dados. Ele define os campos, tipos de dados e validações necessários para criar e manipular esses dados. Além disso, o model permite interagir com o banco de dados, como realizar consultas, atualizações, exclusões e adições. É usado para centralizar a lógica de negócios relacionada às informações. Em geral, o model é uma peça do padrão **MVC** (Model-View-Controller).

Dentro da pasta **src** criamos uma terceira pasta chamada **model** e dentro dela um arquivo que nomearemos como _userModel.js_.

API-Authentication
|
|--node_modules 📁
|
|--src 🗃️
| |--Controller 📁
| |--routes 🛤️
| | |-- index.js 📄
| | |-- users.js 📄
| | |-- auth.js 📄
| |
| |--model 📂
| | |-- userModel.js 📄
|
|--package.json 📄
|--server.js 📄

Dentro de **userModel.js** faremos

### 4.1.1 - userModel.js

[Voltar ao topo 🔝](#índice)

```javascript
// Todo pacote importado em atualizações no Model devem ser adicionados abaixo do mongoose
const mongoose = require("mongoose");

const userSchema = new mongoose.Schema({
userName: {
type: String,
required: true, // O nome de usuário é obrigatório
trim: true, // Sanitiza o input
},
email: {
type: String,
required: true, // O e-mail é obrigatório
unique: true, // O e-mail deve ser único no banco de dados
trim: true, // Sanitiza o input
},
password: {
type: String,
required: true, // A senha é obrigatória
trim: true, // Sanitiza o input
},
});

// _______________________________

// Toda a lógica das atualização devem ser feitas entre as linhas na ordem mostrada abaixo
// .
// .
// 3° atualização
// 2° atualização
// 1° atualização

// _______________________________

// Definindo o modelo de dados "Users" baseado no esquema "userSchema"
const userData = mongoose.model("Users", userSchema);

module.exports = userData;
```

No model acima adicionamos algumas configurações que são importantes no inicio, e algumas outras serão adicionadas a medida que vamos desenvolvendo a aplicação. No model acima um usuário cadastrado na base de dados terá seus dados armazenados como:

```json
{
"_id": "new ObjectId('213asf5554s5533525')",
"name": "Caio",
"email": "[email protected]",
"password": "123456"
}
```

Antes de falarmos da senha e caracteristicas dos dados quando os salvamos na base de dados, precisamos primeiro ter onde salvar os dados, e sem a conexão com a base isso é impossivel.

## 4.2 - Conectando a base de dados

[Voltar ao topo 🔝](#índice)

Na pasta **src** vamos adicinar a pasta _DB_ onde criamos o arquivo _db.js_, que será o responsavel por toda a logica da conexão com a base de dados

API-Authentication

├── src 🗃️
│ ├── Controller 📁
│ ├── Model 📂
│ │ └── userModel.js
│ ├── Routes 📁
│ │ ├── auth.js
│ │ ├── users.js
│ │ └── index.js
│ ├── db 🗄️
│ └── db.js
├── package.json 📄
├── server.js 📄

### 4.2.1 - db.js

[Voltar ao topo 🔝](#índice)

```javascript
const mongoose = require("mongoose");
const Events = require("events");

const dbEvents = new Events();

mongoose
.connect(process.env.DB_URL)
.then(() => {
dbEvents.emit("connected");
})
.catch((error) => {
console.log(error);
});
module.exports = { dbEvents };
```

para poder acessar o _process.env.DB_URL_, precisamos na raiz no projeto criar um arquivo .env e um .gitignore. O .env é onde adicionamos as variaveis de ambiente, e o .gitignore e onde colocamos a extensão dos arquivos que não queremos que sejam enviados para o github.

API-Authentication

├── src 🗃️
│ ├── Controller 📁
│ ├── Model 📂
│ │ └── userModel.js
│ ├── Routes 📁
│ │ ├── auth.js
│ │ ├── users.js
│ │ └── index.js
│ ├── db 🗄️
│ │ └── db.js
├── .env 📄
├── .gitignore 📄
├── package.json 📄
├── server.js 📄

no arquivo .env e .gitignore adicionamos

#### .env

DB_URL: mongodb://127.0.0.1/27017/auth

que é a string de conexão que o mongoose vai utilizar para conectar com a base de dados. Já no no .gitignore fazemos

#### .gitignore

node_modules
.env

Agora esses arquivos não serão mais mapeados para o github e não corremos o risco de expor dados sensiveis da nossa aplicação. Para finalizar a conexão com a base de dados, precisamos importar esse arquivo no arquivo server para que quando o servidor seja iniciado, a conexão seja estabelecida e o evento ` dbEvents.emit("connected")` seja disparado e então o servidor liberado.

### 4.2.2 - Atualização do arquivo server.js

[Voltar ao topo 🔝](#índice)

:warning: A parte de texto comentada é que a que foi adicionada ao código.

**server.js (Conexão com a base)**

```javascript
require(".dotenv").config();

const express = require("express");

const app = express();

const port = process.env.port || 5000;

// Conexão com a base de dados (1° atualizações)
const { dbEvents } = require("/src/db/dbConnection");

app.get("/", (req, res) => {
res.send("Bem vindo a API");
});

dbEvents.on("connected", () => {
app.listen(port, () => {
console.log("Servidor on");
console.log(`Acesse em http://localhost:${port}`);
});
});
```

no código

```javascript
// Ouvindo o evento 'connected' do dbEvents, que é disparado quando a conexão com o banco de dados é bem-sucedida
dbEvents.on("connected", () => {
// Inicia o servidor na porta especificada, e exibe mensagens de sucesso
app.listen(port, () => {
console.log("Servidor on"); // Exibe mensagem indicando que o servidor está ativo
console.log(`Acesse em http://localhost:${port}`); // Informa a URL para acessar o servidor
});
});
```

indica que o servidor só será liberado após o sinal "connected" ser emitido. Feito a atualização acima, vc deve ser capaz de acessar o servidor já com a base conectada.

### 4.2.3 - Atualização do arquivo server.js

[Voltar ao topo 🔝](#índice)

Com a base de dados configurada, já quase podemos iniciar as configurações das nossas rotas, porém nosso servidor ainda não é capaz de interpretar e responder requisições no formato `JSON` e nem de receber objetos complexos no corpo da requisição. Para resolver isso teremos de atualizar nosso arquivo **server.js**.

#### server.js (Conexão com a base | JSON e extended)

```javascript
require(".dotenv").config();
const express = require("express");

const app = express();

const port = process.env.port || 5000;

const { dbEvents } = require("/src/db/dbConnection");

// Middlewares (2° atualização)
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.get("/", (req, res) => {
res.send("Bem vindo a API");
});

dbEvents.on("connected", () => {
app.listen(port, () => {
console.log("Servidor on");
console.log(`Acesse em http://localhost:${port}`);
});
});
```

Agora podemos adicionar um primeiro usuário a base de dados e responde-lo usando JSON.

# Middlewares

[Voltar ao topo 🔝](#índice)

Um outro conceito que é muito importante para aprendermos antes de colocarmos a mão na massa, é o de middleware.
Um middleware é uma função que intercepta requisições (request) e respostas (response) no fluxo de uma aplicação, executando lógica antes de alcançar o manipulador final da rota. Ele pode ser usado para tarefas como autenticação, logging, manipulação de dados ou tratamento de erros. Middleware é aplicado globalmente ou em rotas específicas e funciona em uma sequência definida. No Express, usa-se app.use() ou diretamente na rota.

No nosso projeto teremos dois middlewares principais, o que será responsável por validar os dados enviados no corpo da
requisição e um de verificação de token. Na pasta **src** crie:

📁 API-Authentication
├── 📁 node_modules 🗃️

├── 📁 src 🗃️
│ ├── 📁 controllers 📁
│ │ ├── authController.js 📄
│ │ ├── usersController.js 📄
│ │
│ ├── 📁 db 📁
│ │ └── db.js 📄
│ │
│ ├── 📁 middleware 📁
│ │ ├── userValidator.js 📄
│ │ └── verifyToken.js 📄
│ │
│ ├── 📁 model 📁
│ │ └── userModel.js 📄
│ │
│ ├── 📁 routes 📁
│ │ ├── users.js 📄
│ │ ├── auth.js 📄
│ │ └── index.js 📄

├── .env 📄
├── .gitignore 📄
├── package.json 📄
├── server.js 📄

## Middleware Validator

[Voltar ao topo 🔝](#índice)

Esse middleware será responsavel por validar os dados enviados no corpo da requisição. Para podermos escrever a lógica associada, vamos instalar o Validator. No terminal do VSCode digite

npm i validator

uma vez instalado, no arquivo `userValidator.js` faremos

### userValidator.js

[Voltar ao topo 🔝](#índice)

```javascript

const validator = require('validator')

function validate(req, res, next) {

const {name. email, password} = req.body

if(!name || name.length <= 2) {
return res.status(400).json({message: 'O nome deve conter no minimo 3 caracteres'})
}

if(!email || validor.isEmail(email)) {
return res.status(400).json({message: 'Formato de email inválido'})
}

if(!password || validator.isLength(password, {min: 6})) {
return res.status(400).json({message: 'Senha deve conter no minimo 6 caracteres'})
}

next()

}

module.exports = validate
```

O middleware acima será adicionado no meio da rota de [signup](#authjs), como podemos ver abaixo:

**routes.js**:

```javascript
const route = express.Router();

const authController = require("../controllers/authController");

const validator = require("../middlewares/userValidator");

// Middleware Validator
route.post("/signup", validator, authController.signUp);

route.post("/login", authController.signIn);
route.post("/logout", authController.logout);
route.post("/logoutAll", authController.logoutAll);

module.exports = route;
```

com os dados sendo validados. Vamos iniciar a implementação das nossas rotas.

# 3- Rotas

[Voltar ao topo 🔝](#índice)

Com as primeiras configurações feitas, podemos iniciar a lógica dentro dos controllers [Controllers](#controllers). Destaco que o codigo mostrads abaixo são basicos e que a medida em que formos adicionando novas funcionalidades, serão inclusas novas linhas de código.

# signup

Rota de sign-up é a rota que utilizamos para cadastrar um usuário ao nosso projeto, todavia, antes de se implementar essa rota na aplicação é necessário fazermos o hash da senha senha para que ela não fique em texto plano e gerar um token para o usuário nas rotas de signup e login, que é essencialmente uma forma de assinar o usuário digitalmente, ou seja, é uma forma de informar ao servidor que o usuário que está tentando fazer login na aplicação é realmente quem diz ser.

### Hash

[Voltar ao topo 🔝](#índice)

O hash é um processo de transformar uma senha em uma sequência única e fixa de caracteres, usando um algoritmo como bcrypt ou argon2. Ele é irreversível, ou seja, não é possível converter o hash de volta para a senha original. Quando o usuário tenta fazer login, a senha fornecida é novamente transformada em hash e comparada com o hash armazenado. Isso garante que a senha original nunca seja salva no banco de dados, aumentando a segurança. Além disso, técnicas como "salting" (adicionar valores aleatórios) tornam os hashes únicos, mesmo para senhas iguais. Um hash pode ser visto abaixo.

$2b$12$IHoTahYqFX3wPKLtvi.6/uM1xpIdcfZBYVgmvY2sMCepqY61aUkXe

Para proteger a senha dos usuários vamos precisar instalar argon2

npm i argon2

dentro do [userModel.js](#411---usermodeljs) adicione

### 1° atualização -Model

```javascript
// No topo do arquivo adicione
const argon2 = require('argon2')

// Função de hash da senha
userSchema.pre("save", (next) => {
const user = this;

try {

if (!user.isModified(password)) return next();

user.passoword = await argon2.sign(password, {
type: argon2.argon2id,
memoryCost: 2 ** 16,
timeCost: 5,
paralelism: 1,
})

next()

} catch(error) {
next(error)
}
});

// Toda atualização deve ser adicionada acima dessas diretivas
const userData = mongoose.model("Users", userSchema);

module.exports = userData;
```

Agora o que será salvo na base de dados é o hash da senha, e não a senha como texto plano. Limpe a base de dados e cadatre um novo usuário, o resultado deve ser algo como

```json
{
"_id": "new ObjectId('213asf5554s5533525')",
"name": "Caio",
"email": "[email protected]",
"password": "$2b$12$IHoTahYqFX3wPKLtvi.6/uM1xpIdcfZBYVgmvY2sMCepqY61aUkXe"
}
```

Uma vez que temos o usuário cadastrado na base de dados, podemos implementar a lógica que o permite utilizar os dados
cadastrados para fazer login.

### Token

[Voltar ao topo 🔝](#índice)

Um token é uma chave única usada para confirmar a identidade de um usuário ou aplicação. Ele é gerado ao fazer login e permite acessar recursos de forma segura. Tokens têm prazo de validade e podem ser cancelados, sendo muito usados em APIs e sistemas de autenticação.

Como utilizaremos a criação de tokens em mais de uma rota, iremos adiciona-lo ao model e atrela-lo aos documentos que forem criados pelo model, mas antes precisamos alterar o model, uma vez que queremos dar a oportunidade do usuário acessar sua conta em diversos dispositivos. No [usermodel.js](#411---usermodeljs) vamos adicionar um novo campo.

```javascript
const userSchema = new mongoose.Schema({
userName: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
required: true,
unique: true,
trim: true,
},
password: {
type: String,
required: true,
trim: true,
},
tokens: [
{
token: {
type: String,
required: true,
},
},
], // tokens será um array de objetos
});
```

. Para isso faremos:

No terminal instale o pacote:

npm i jsonwebtoken

Dentro do [usermodel.js](#411---usermodeljs) adicionamos:

```javascript
// Inclua no top do model
const jwt = require("jsonwebtoken");

// Método gerar token

userSchema.methods.generateToken = async function () {
const user = this; // 'this' se refere ao usuário atual

// Gerando o token JWT com o ID do usuário, utilizando a chave secreta do ambiente
const userToken = jwt.sign({ _id: user._id }, process.env.JWT_SECRET, {
expiresIn: "7d", // O token vai expirar em 7 dias
});

// Verificando se o usuário já tem 4 tokens. Se sim, remove o mais antigo
if (user.tokens.length >= 4) {
return user.tokens?.shift();
}

// Se não tiver 4 tokens, adiciona o novo token à lista de tokens do usuário
user.tokens?.push({ userToken });

return userToken; // Retorna o token gerado
};
```

No metodo acima, usamos o `process.env.JWT_SECRET`, que é a string que o json web token usa para assinar os tokens e poder decodifica-los posteriormente. Podemos criar essa chave de muitas formas difentes, mas é importante lembrar que ela deve ser uma senha muito forte, visto que é com essa senha que nosso servidor será capaz de garantir ou não acesso ao nosso site, e caso caia em mãos erradas, o atacante terá acesso total ao sistema. Recomendo que execute o resultado abaixo no terminal do VScode e use a saida como senha.

node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

Para usar o valor gerado como senha do servidor, no arquivo .env adicionamos

```javascript
JWT_SECRET = K8wHSvZHndOTPtQJYLYsx2DBOCL1n6DTEXQL8bGhb+U=
```

Agora temos uma senha segura que garante ao nosso servidor seja capaz de impedir tokens falsificados.
Vamos utilizar todos os passos acima para garantir a segurança da nossa aplicação nas rotas que implementaremos.

Na rota signup faremos:

### sign-up code

```javascript
const UserModel = require("../model/userModel"); // Importando model

exports.signUp = async (req, res) => {
const { email, name, password } = req.body; // obtendo dados do formulário

try {
const existUser = await UserModel.findOne({ email });

if (existUser) {
throw new Error("Usuário já cadastrado");
}

const newUser = new UserModel({ name, email, password });
await newUser.generateToken();

try {
await newUser.save();
res.status(201).json({
message: "Usuário criado com sucesso",
newUser,
});
} catch (error) {
throw new Error(error.message);
}
} catch (error) {
res.status(401).json({ message: error.message });
}
};
```

# login

[Voltar ao topo 🔝](#índice)

```javascript
const UserModel = require("../model/userModel");
const argon2 = require("argon2");

exports.login = async (req, res) => {
try {
const user = await UserModel.findByCredentials(req.body); // Vamos criar esse método no userModel

await user.generateToken();

return res.status(200).json({
success: true,
message: "Login realizado com sucesso.",
user,
});
} catch (error) {
return res.status(401).json({
success: false,
message: error.message,
user: null,
});
}
};
```

no [userModel.js](#411---usermodeljs) vamos adicionar o código mostrado abaixo

```javascript
// Acima da função de fazer hash da senha adicione (2° atualização)
userSchema.statics.findByCredentials = async function ({ email, password }) {
const user = this;
const existUser = await User.findOne({ email });

if (!existUser) {
throw new Error("Usuário não cadastrado");
}

const isValidPassword = await argon2.verify(existUser.password, password);

if (!isValidPassword) {
throw new Error("Usuário não cadastrado");
}

return existUser;
};
```

O código acima anexamos um novo método ao model de modo que agora, podemos invocá-lo sempre que precisarmos verificar se o usuário está existe na base de dados.

# logout

A rota logout é a rota responsavel por finalizar a sessão do usuário na aplicação, para fazer precisamos primeiro verificar se o usuário que está tentando fazer o logout é autorizado a fazer isso, ou seja, se ele possui um token de acesso. Para isso antes de implementarmos a lógica de logout, devemos criar um middleware que verifica o token do usuário. Esse middleware será utilizado em todas as rotas privadas.

### verifyToken.js

```javascript
const jwt = require("jsonwebtoken");
const UserModel = require("../model/userModel");

async function verifyToken(req, res, next) {
try {
const token =
req.cookies.userToken ||
req.headers.authorization?.replace("Bearer ", "");

const decoded = jwt.verify(token, process.env.JWT_SECRET);

const user = await UserModel.findById(decoded._id);

if (!user) {
throw new Error("Usuário não cadastrado");
}

req.user = user;
req.token = token;

next();
} catch (error) {
res.status(401).json({ message: error.message });
}
}
```

```javascript
exposts.logout = async function (req, res) {
try {
const user = await UserModel.findById();
} catch (error) {}
};
```