Stateless X Stateful - Autenticação JWT no NodeJS

@WellsSA

@WellsSA

Wellington S. Almeida

  • Senior Software Engineer at @Holonic (Sillicon Valey)
  • Community Manager at @EW.it
  • Community Manager at @FlutterNation
  • Ex-CTO & Co-founder at @Envia.io
  • Designer, maybe?
  • Speaker? @icarcal
  • Music? Let's Rock!

@WellsSA

"Autenticação usando Tokens"

Geralmente ouvimos falar de

@WellsSA

Mas, antes de tudo

O que é Autenticação?

@WellsSA

Na definição

Autenticação
(do grego : αυθεντικός = real ou genuíno, de 'authentes' = autor) é o ato de estabelecer ou confirmar algo (ou alguém) como autêntico"

@WellsSA

Autenticação

Isso é muito importante

Segurança e privacidade

  • Para ver as informações, precisa autenticar

Acessos

  • Quais informações pode ver/criar/apagar?
  • Pode ver/criar/apagar informações?

Logging/Auditoria

  • Quem está vendo/criando/apagando informações?

@WellsSA

@WellsSA

Então agora sabemos que: Autenticação é importante

E existem várias formas de autenticação

@WellsSA

Você

servidor

"Tá logado?
tem ID?
Nível de acesso?"

Usando um exemplo simples

@WellsSA

@WellsSA

Precisamos de autenticação

Você

servidor

"Tem login e senha, sei quem é"

(login, senha)

(acesso à página)

@WellsSA

E também salvar a autenticação

Você

servidor

"Tem login e senha, sei quem é"

(login, senha)

(acesso à página)

Você

servidor

"Quem é você?"

(qualquer outra requisição)

@WellsSA

Preciso de login e senha toda vez?

Não!

E como fazemos isso?

@WellsSA

Um meio inteligente de autenticar o usuário

O que precisamos é

@WellsSA

Stateless
X
Stateful

E é aí que entra o tema da palestra

Autenticação

@WellsSA

Voltando pro nosso exemplo

Você

servidor

"Tá logado?
tem ID?
Nível de acesso?"

@WellsSA

Podemos usar variáveis de sessão

Você

servidor

(login, senha)

(acesso à página)

Você

servidor

"Esse é o usuário do Session_id: 123"

(qualquer outra requisição)

Session_id: 123

User_ID: 2

Session

@WellsSA

E é isso

Fim da palestra

@WellsSA

Ainda não, caaalma

Pegadinha

@WellsSA

Só teoria

Teoria
+
Prática

Na teoria

Você

servidor

Session_id: 123

User_ID: 2

Session

@WellsSA

Na prática
              ex.:

Você

servidor

Session_id: 123

User_ID: 2

Session

@WellsSA

Temos alguns problemas

Você

load balancer

Session

(session_cookie)

@WellsSA

Isso é

@WellsSA

Autenticação

Stateful

O servidor salva um estado

Você

load balancer

Session

(session_cookie)

@WellsSA

@WellsSA

Mas e como raios é a Stateless?

OK, isso é Stateful

@WellsSA

Imagina só

Você

servidor

(login, senha)

(acesso à página + chave)

Você

servidor

"Esse é o usuário
{ User_ID: 2 }"

(qualquer outra requisição + chave)

{ User_ID: 2 }

Chave criptografada

@WellsSA

Em termos técnicos

"chave criptografada"

"token"

E por que isso é tão útil?

Porque no Stateful

@WellsSA

Você

load balancer

Session

Enquanto no Stateless

Você

load balancer

(token)

(token)

(login)

E isso serve pra muita coisa!

@WellsSA

✅ Autenticação Stateful

✅ Autenticação Stateless

Então já sabemos o que é

Mas....

@WellsSA

O que é JWT?

@WellsSA

@WellsSA

JWT

(JSON Web Token)

  • Web Token que armazena objetos JSON
  • Permite a autenticação de uma requisição

"(...) é um método RCT 7519 padrão da indústria para realizar autenticação entre duas partes por meio de um token assinado que autentica uma requisição web"

(Fonte: DevMedia)

@WellsSA

@WellsSA

Basicamente

"abcd.1234.abcd1234"

@WellsSA

Um meio inteligente de autenticar o usuário

Esse é

@WellsSA

✅ Autenticação Stateful

✅ Autenticação Stateless

Agoooora sim já sabemos 

✅ e JWT

@WellsSA

Por que JSON Web Token?

Tópico extra, pra quem tiver curiosidade

@WellsSA

JSON é um formato de texto que facilita a troca de dados estruturados!

Porque

@WellsSA

O que é JSON?

[
    {
        nome: "Wellington",
        idade: 20,
        amigos: ["Kaleo", "Lucas"],
    },
    {
        nome: "Kaleo",
        idade: 21,
        amigos: ["Lucas", "Wellington"],
    },
]
"[{"nome":"Wellington","idade":20,"amigos":["Kaleo","Lucas"]},{"nome":"Kaleo","idade":21,"amigos":["Lucas","Wellington"]}]"

Objeto

X

Texto

(JavaScript Object Notation)

Objeto

Texto

Objeto

@WellsSA

Com o JSON

Informação útil

Token criptografado

@WellsSA

E usando o JSON Web Token

servidor

Texto

Informação útil

Token criptografado

Texto

Ou seja

Você

load balancer

(login)

(token)

@WellsSA

Ou seja

Você

load balancer

(token)

@WellsSA

@WellsSA

✅ Autenticação Stateful

✅ Autenticação Stateless

Agoooora sim já sabemos 

JSON e JWT

@WellsSA

Dicas extras especiais

  • Atenção ao tamanho do "secret" escolhido, ele vai ser usado para criptografar/descriptografar informações em quase toda request
  • Defina sempre um tempo de expiração pros seus JWTs, assim se eles forem "roubados", o atacante tem um tempo limitado para agir 

Bora codar!

@WellsSA

Criando um server com Express

@WellsSA

Definindo as Configurações

@WellsSA

Rota de Login

@WellsSA

Rota de Login

Exemplo de resposta

@WellsSA

Middleware de Autenticação

@WellsSA

A ordem das rotas importa!

@WellsSA

Código completo

const express = require('express');

const cors = require('cors');
const jwt = require('jsonwebtoken');

const app = express();

app.use(cors({ origin: '*' }));
app.use(express.json());

const config = {
  secret: 'palestraJWTSKKAsdo@22s',
  expiresIn: '1h',
};

app.post('/login', (req, res) => {
  // email/password verification to find user

  const user = { id: 10 };

  return res.json({
    user,
    token: jwt.sign({ id: user.id }, config.secret, {
      expiresIn: config.expiresIn,
    }),
  });
});

const authMiddleware = (req, res, next) => {
  const { authorization } = req.headers;

  // 1. Verify if the authorization header was provided
  if (!authorization) {
    return res.status(401).json({ error: 'Missing authorization' });
  }

  // 'Bearer token123'
  const [_, token] = authorization.split(' ');

  try {
    // 2. Verify if there is a valid token
    const decoded = jwt.verify(token, config.secret);

    req.userID = decoded.id;
    // 3. If everything is okay, continue to the next middleware
    next();
  } catch (error) {
    console.log(error);
    if (error.name === 'JsonWebTokenError')
      return res.status(401).json({ error: 'Invalid token provided' });
    return res.status(500);
  }
};

app.get('/non-protected', (req, res) => res.json({ ok: true }));

app.use(authMiddleware);

app.get('/protected', (req, res) => res.json({ ok: true }));

const port = 3002;

app.listen(port, () => console.info(`🚀 Server running on port ${port}...`));

@WellsSA

Wellington S. Almeida

@WellsSA

Made with Slides.com