Json Web Tokens - Como funcionam, como criar e validar.
Bom dia pessoal, hoje irei demonstrar como o processo de criação e validação de um Json Web Token funciona, e nós não vamos usar módulos como o jwt
ou o jose
pra isso. Vamos começar do zero!
O tutorial a seguir é pra node.js
Além disso para ficar mais organizado eu dividi esse post em 3 categorias:
- O que é?
- Como criar
- Como validar
O que é um Json Web Token (Clique para expandir)
O que é um Json Web Token?
Um json web token, em palavras simples é um token de autenticação, que é divido em 3 partes:
Parte 1 | O header do token, ele contém o algoritmo usado pelo hash, e o tipo de token |
Parte 2 | O payload do token, ele contém informações personalizadas que você pode decidir! |
Parte 3 | O hash do token, ele é criptografado com uma chave privada |
Para não ter que ficar repetindo Json Web Token
toda hora, vamos chamar ele de JWT
por enquanto
Como o processo da criação do token funciona (Clique para expandir)
Como o processo da criação do token funciona
Antes de escrever o código que vai gerar o token, precisamos antes entender como o processo que gera ele funciona.
O que temos que gerar?
Temos que gerar um header, um payload, E um hash que garante a integridade dos header e do payload.
O header, assim como o payload será um Json
encriptado em Base64
E o hash, será um Hash-sha256 que terá como valor o header e o payload, e o hash será assinado com uma chave privada para garantir que quem emitiu o token foi nós, e não outra pessoa.
Como gerar?
Primeiramente precisamos ter um meio de codificar um json
em base64
e vice-versa.
Para isso utilizaremos o Buffer
do node.js, que irá fazer o trabalho de codificar o base64
para nós
let JSONbase64 = {
encode: (json) => Buffer.from(JSON.stringify(json)).toString("base64url"),
decode: (base64) => JSON.parse(Buffer.from(base64, "base64url").toString("ascii"))
}
Com isso feito nós podemos passar pra nossa próxima tarefa: Gerar o hash do token
Para isso nós usaremos o módulo crypto
que já vem instalado com o node.js
A linha de código que vai gerar o hash é está:
crypto.createHmac("sha256", secret_key).update(`${header}.${payload}`).digest("base64url") //secret_key = a chave privada que eu falei antes!
Se você quiser saber mais do crypto a docs dele está aqui
Maravilha! agora que fizemos tudo nós vamos criar a função que vai gerar o token:
Primeiramente, tenha em mente que essa função vai gerar uma Promise, pois demora alguns milissegundos pra gerar um hash.(Pode parecer pouco millisegundos, mas computadores são muitos mais rapidos que isso. então somente pra nós, Humanos que esse tempo é curto)
Essa função vai gerar um header, um payload com a data de quando o token foi emitido e o nome do usuário(que vai ser passado por um pârametro), e o hash que corresponde a isso. E depois vai juntar tudo com o separador .
const crypto = require("crypto")
function createToken(nome){
return new Promise((resolve, reject) => {
let header = JSONbase64.encode({typ: "JWT", "alg": "HS256"})
let payload = JSONbase64.encode({nome: nome, createdAt: Date.now()})
let hash = crypto.createHmac("sha256", secret_key).update(`${header}.${payload}`).digest("base64url")
let result_token = `${header}.${payload}.${hash}`
resolve(result_token)
})
}
E pronto! Você aprendeu como gerar um token!
Como o processo da validação do token funciona (Clique para expandir)
Como o processo da validação do token funciona
Ok, você aprendeu a como gerar um token JWT, mas como validar ele?
Alguns processos que você pode pensar são:
- Gerar o token novamente e verificar se os tokens são iguais: Não funciona! lembra do atributo
createdAt
do payload? o tempo que você vai validar é diferente do tempo que o token foi criado, então os tokens vão ser diferentes! - Gerar o hash novamente e verificar se os hash são iguais: Funciona!
Então vamos lá:
function validateToken(token){
return new Promise((resolve, reject) => {
let [header_in_base64, payload_in_base64, hash] = token.split(".")
let valid_hash = crypto.createHmac("sha256", secret_key).update(`${header_in_base64}.${payload_in_base64}`).digest("base64url")
resolve(hash == valid_hash)
})
}
E pronto! agora você sabe como validar e criar tokens JWT
Repositorio no github para quem quiser ver o código completo: https://github.com/33gustavo33/jwt-exemplo