Trabalhando com Cookies

Trabalhando com Cookies 

Durante a sua jornada de desenvolvimento de aplicações usando Javascript Puro, ou por meio de um ambiente de desenvolvimento (como o NodeJS), ou quem sabe usando um framework front-end (como o ReactJS, Angular e afins).

Você pode fazer o uso dos Cookies de modo com que a sua aplicação persista alguns dados dentro do navegador do seu usuário.

Mas antes você precisa entender o que são cookies, e como utiliza-los na sua aplicação, vamos nessa? 🍪

O que são Cookies?

Com a evolução dos sites na internet, houve a necessidade de salvar o comportamento de navegação das páginas dentro do próprio navegador do usuário, isso fez com que alguns sites conseguisse armazenar algumas informações daquele usuário, de modo a melhorar a sua experência de navegação.

Eis então, que surgem os Cookies, que nada mais são do que arquivos de textos que são gerenciados pelos próprios navegadores (Chrome, Mozilla, Opera, Edge...), cujo o objetivo é salvar informações, tais como as preferências do usuário em relação aos sites.

Neste caso, nós como desenvolvedores de sites, poderiamos armazenar dentro de Cookies diversas informações como por exemplo:

  • Dados preenchidos em formulários,
  • Senhas de acessos (é inseguro e você nunca deveria fazer, mas é uma das possibilidades),
  • Tokens de acesso (JWT e afins),
  • Produtos deixados no carrinho de compras,
  • Configurações de acessibilidade,
  • Preferências do usuário.

E qualquer outra informação relevante que nós acharmos importante.

Por exemplo, um token de acesso armazenado dentro de um cookie, poderia fazer com que o usuário estivesse logado mesmo após fechar a tela do navegador. De modo que assim que o usuário voltasse a acessar nosso site, ele não precisasse fazer o login novamente.

Um outro exemplo disso, são os produtos deixados no carrinho mas que foram armazenados dentro de cookies. Fazendo com que esses produtos permaneçam no carrinho mesmo após o usuário sair do site, ou fechar a tela do navegador.

Esses Cookies, são popularmente conhecidos como Cookies de Funcionalidade, e tem por objetivo registrar recursos essênciais para que o usuário tenha a melhor experiência no site em questão.

Os Cookies foram criados no ano de 1994 por Lou Montulli, quando ele ainda trabalhava na Netscape, que foi empresa que construiu um dos primeiros nevegadores de internet.

Naquela época, eles se referiam aos cookies que conhecemos hoje como "magic cookie", fazendo referência aos famosos biscoitos da sorte, ou seja, aqueles biscoitos que continham uma mensagem embutida dentro deles.

Os Cookies são a base do modelo da internet que temos hoje, pois sem eles, a nossa experiência com os sites seriam muito ruins, um exemplo disso, é você precisar fazer login no seu site favorito toda vez que precisar acessar novamente.

Arquitetura dos Cookies

Um Cookie de navegador segue uma estrutura de chave e valor, o que permite que os sites armazenem e recuperem de forma eficiente as informações que foram salvas.

É importante ressaltar que os cookies podem ser criados por meio de linguagens de programação back-end (PHP, C#, Java...), quanto também por linguagens que atuam no front-end, como é o caso do Javascript.

Além disso, durante a criação de um cookie, o site pode adicionar uma série de restrições de acesso, como por exemplo:

  • Definir se o cookie será acessado somente pelo site que o criou, ou não,
  • Definir uma data de expiração para o cookie,
  • Além de outras definições de segurança.

Quantos bytes um cookie pode armazenar?

De acordo com os limites impostos pela RFC, um navegador deve ser capaz de aceitar pelo menos uns 300 cookies com tamanho máximo de 4.096 bytes.

Criando Cookies usando Javascript

Como vimos anteriormente em outras lições, o Javascript conta com um objeto global chamado document, que é uma interface que serve como ponto de partida para acessar o conteúdo da página (DOM), logo após o carregamento da página.

Será com o document que podemos acessar a propriedade cookie, permitindo que você realize a leitura, gravação e exclusão dos cookies do site.

Antes de começarmos a colocar a mão na massa, vamos iniciar criando um arquivo HTML simples dentro da pasta do seu projeto. No meu caso eu nomeei ele como index-cookies.html:

<!DOCTYPE html>
<html>
 <head>
 <title>Testes com Cookies</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 </head>
 <body>
 <h1>Testes com Cookies</h1>
 <p>Os testes estão sendo feitos no Javascript, consulte o console do navegador para acompanhar o desenvolvimento.</p>	
 </body>
 <script>
 //Comece aqui...
 </script>
</html>

Será dentro das tags <script> que iremos escrever toda a lógica que veremos a seguir 😉

Criando um Cookie

O processo de criação de um cookie usando Javascript é bem simples, observe:

document.cookie = "nomeDoCookie=valorDoCookie;";

Como um Cookie nada mais é do que um arquivo de texto, nós precisamos armazenar nossos dados em formato de string.

Observe também que criamos um novo cookie com uma chave chamada 'nomeDoCookie' que armazena a informação 'valorDoCookie', e fizemos isso usando o operador de atribuição (=) junto com o ponto e vírgula no final (;).

Veja agora outros exemplos de utilização de cookies:

document.cookie = "nome=micilini;";

document.cookie = "rank=109;";

document.cookie = "url=https://micilini.com/;";

No exemplo acima, foram criados três cookies com as chaves: 'nome', 'rank' e 'url', cada qual armazenando um valor diferente.

Caso preferir, você também pode criar diversos cookies dentro de uma única chamada ao document.cookie, observe:

document.cookie = "cookie1=valor1; cookie2=valor2; cookie3=valor3;";

Boas Práticas ao criar Cookies

Até o momento, você aprendeu criar cookies sem fazer o uso de espaços ou algum outro tipo de caractere especial, o problema é que se você criar um cookie dessa forma:

document.cookie = "cookie1=Olá Mundo!;"

document.cookie = "cookie1=Meu Nome é Micilini @%$*&;";

document.cookie = "cookie1=2 + 2 = 4";

O navegador pode ter dificuldades para armazenar essas informações, e é por esse motivo que você precisa estar a par das boas práticas na hora da criação deles.

Com relação aos nomes dos cookies (chave), eles são sensíveis a maiúsculas e minúsculas, fazendo com que o cookie "NomeDoCookie", e o cookie "nomedocookie" sejam tratados como cookies diferentes.

Além disso, você deve criar cookies usando nomes descritivos e significativos para a sua aplicação.

Já com relação aos valores dos cookies (value), é importante que você codifique essas informações usando o encodeURIComponent, o que garante que os caracteres especiais sejam tratados corretamente, observe:

document.cookie = "minhaChave=" + encodeURIComponent("Eu sei que esse valor = não vai ter nenhum @ problema! ¨%&*%¨&*$%#!`^{?`^:") + ";";

Além disso, é importante ressaltar que você não deve armazenar informações sensíveis nos cookies, como senhas ou outras informações pessoais.

Quantos cookies podemos criar de forma simultânea no navegador?

Atualmente não há um limite absoluto relacionado ao número de cookies que podemos criar, entretanto cada navegador possui suas próprias regras da quantidade de limites de cookies que podemos armazenar por domínio de acordo com as regras do RFC.

Lendo um Cookie

Para ler todos os cookies armazenados no navegador, você pode fazer isso usando o document.cookie da seguinte forma:

const meusCookies = document.cookie;//Todos os Cookies serão retornados aqui

No exemplo acima, como não estamos usando o operador de atribuição (=) ao document.cookie, o sistema vai retornar a lista de cookies armazenadas dentro do navegador.

É importante ressaltar que o retorno será uma string com todos os cookies em pares de chave-valor, sendo assim, caso você queria separa-los dentro de um array, você pode criar uma função para isso:

function getAllCookies() {
 const cookieString = document.cookie;//Pega a lista de todos os cookies juntos em formato de string
 const cookiesArray = cookieString.split("; ");//Separa em um array todos os cookies a partir do caractere ';'
 const cookies = {};//Cria uma lista vazia de objetos, que será usada para armazenar os cookies em formato de pares de chave-valor

 cookiesArray.forEach(cookie => {//Faz um loop dentro de cookiesArray de modo a retornar todos os cookies separados anteriormente
 const [name, value] = cookie.split("=");//Como os pares estão armazenados juntos em uma string, aqui realizamos mais uma separação usando o caractere '=', onde tudo o que vier antes do = será armazenado na variável 'name', e tudo o que vier depois será armazenado na variável 'value'
 cookies[name] = decodeURIComponent(value);//Por fim estamos armazenando dentro da variável 'cookies', os pares que separamos no código acima
 });

 return cookies;//Estamos retornando os pares de chave-valor dos cookies, em um formato que conseguimos trabalhar posteriormente
}

// Exemplo de uso
const cookies = getAllCookies();
console.log(cookies);

No código acima, criamos a função getAllCookies que é responsável por retornar os cookies e lista-los dentro de um objeto, para que posteriormente nós possamos fazer o uso de cada informação ali armazenada de uma maneira mais fácil.

Observação: Talvez você tenha notado que outros cookies (além daqueles que você criou) tenham sido retornados durante o processo. Isso aconteceu pois outros sites podem criar cookies públicos, isto é, cookies de terceiros que também podem ser lidos pelo seu ou qualquer outro site.

Mais tarde ainda nesta lição, veremos como criar cookies de forma segura, fazendo com que eles possam ser lidos somente pelo site que os criou 🙂

Atualizando o valor de um Cookie

Supondo que você tenha criado um novo cookie chamado de 'frase' que armazena o valor 'Hoje o dia está lindo!':

document.cookie = "frase=" + encodeURIComponent("Hoje o dia está lindo!") + ";";

Será que é possível atualizar esse valor?

Sim é possível, mas atualmemte não existe nenhum método para tal, sendo assim a única forma de atualizar o valor de um cookie é sobrescrevendo ele:

document.cookie = "frase=" + encodeURIComponent("Está é a nova FRASE!") + ";";

Caso desejar, você pode criar uma função específica pra isso:

function updateCookie(name, value) {
 document.cookie = name + "=" + encodeURIComponent(value) + ";";
}

// Exemplo de uso
updateCookie("frase", "Nova frase aqui");

Removendo o valor de um Cookie

Para remover um cookie, basta sobrescreve-lo passando um valor vazio junto com uma data de expiração, observe:

document.cookie = 'frase=; expires=Thu, 01 Jan 1970 00:00:00 UTC;';

No caso do exemplo acima, criamos um cookie com uma data de expiração para o ano de 1970, ou seja, o navegador vai remover esse cookie imediatamente assim que criar 🤣

Informando parâmetros durante a criação dos Cookies

Também é possível informar certos parâmetros na hora em que criamos nossos cookies, parâmetros esses que restringem ou adicionam certo nível de segurança aos nossos cookies, vejamos cada um deles abaixo.

expires: usado para definir uma data de expiração do cookie, caso não for especificado, o cookie que você criou será excluído do navegador, logo após o usuário fechar o navegador.

// Define a data de expiração para daqui a 7 dias
var date = new Date();
date.setTime(date.getTime() + (7 * 24 * 60 * 60 * 1000)); // 7 dias em milissegundos
var expires = "expires=" + date.toUTCString();

// Define o cookie com o nome "meuCookie" e o valor "valorDoCookie" que expira em 7 dias
document.cookie = "meuCookie=valorDoCookie; " + expires + ";";

Observação: Nesse caso, sempre crie cookies usando o parâmetro expires.

path: usado para especificar o caminho no servidor para qual o cookie está disponível. Por padrão usamos o caminho '/', o que engloba toda a estrutura de pastas e urls do domínio.

// Define o cookie com o nome "nome" e o valor "micilini" disponível para qualquer parte/pasta do site
document.cookie = "nome=micilini; path=/";

// Define o cookie com o nome "meuCookie" e o valor "valorDoCookie" disponível apenas no caminho "/minha-pasta"
document.cookie = "meuCookie=valorDoCookie; path=/minha-pasta";

domain: usado para especificar o domínio para qual o cookie esta disponível, por padrão é o dominio do servidor que define o cookie, mas podemos criar cookies que estejam disponíveis para outros domínios.

// Define o cookie com o nome "meuCookie" e o valor "valorDoCookie" disponível apenas para o domínio "micilini.com"
document.cookie = "meuCookie=valorDoCookie; domain=micilini.com";

//No exemplo acima, somente o dominio 'micilini.com' terá acesso ao cookie criado.

secure: quando informado, indica que o cookie deve estar disponível apenas por conexões que fazem o uso do HTTPS.

// Define o cookie com o nome "meuCookie" e o valor "valorDoCookie" como seguro (secure)
document.cookie = "meuCookie=valorDoCookie; secure";

SameSite: usado para controlar se o cookie será enviado em solicitações cross-site. Atualmente temos 3 tipos diferentes, que são: 'strict', 'lax' ou 'none'.

strict: o cookie só será enviado em solicitações do mesmo site:

// Define o cookie com o nome "meuCookie" e o valor "valorDoCookie" com SameSite=Strict
document.cookie = "meuCookie=valorDoCookie; SameSite=Strict";

lax: o cookie será enviado em solicitações do mesmo site e em solicitações GET de navegação de alto nível do site de origem cruzada:

// Define o cookie com o nome "meuCookie" e o valor "valorDoCookie" com SameSite=Lax
document.cookie = "meuCookie=valorDoCookie; SameSite=Lax";

none: o cookie será enviado em solicitações cross-site:

// Define o cookie com o nome "meuCookie" e o valor "valorDoCookie" com SameSite=None; Secure
document.cookie = "meuCookie=valorDoCookie; SameSite=None;";

HttpOnly: quando informado, diz ao navegador que o cookie deve ser acessível apenas pelo servidor e não por scripts no navegador, o que ajuda a prevenir ataques de XSS (Cross-Site Scripting).

// Define o cookie com o nome "meuCookie" e o valor "valorDoCookie" como HttpOnly
document.cookie = "meuCookie=valorDoCookie; HttpOnly";

max-age: usado para definir a vida útil do cookie em segundos a partir do momento em que é definido. Este parâmetro substitui o expires (caso ele estiver sido definido).

// Define o cookie com o nome "meuCookie" e o valor "valorDoCookie" com uma vida útil de 1 hora (3600 segundos)
document.cookie = "meuCookie=valorDoCookie; max-age=3600";

Observação: Se o expires não estiver definido, certifique-se de que você esta usando max-age, pois sem eles o seu cookie vai ser destruido logo após o usuário fechar o navegador.  

É importante ressaltar que nem todos os navegadores possuem suporte aos parâmetros informados acima, além do comportamento poder variar de navegador para navegador.

Aqui esta um exemplo de um cookie que foi criado em conjunto com outros parâmetros:

document.cookie = "nomeDoCookie=valorDoCookie; expires=dataDeExpiracao; path=/; domain=seuDominio.com; secure; SameSite=None; HttpOnly";
var date = new Date();
date.setTime(date.getTime() + (7 * 24 * 60 * 60 * 1000)); // 7 dias de expiração
var expires = "; expires=" + date.toUTCString();
var domain = "; domain=example.com";
var path = "; path=/";
var secure = "; Secure";
document.cookie = "username=John" + expires + domain + path + secure;

E sim, você PODE e DEVE criar cookies utilizando mais de um parâmetro! Não se esqueça de usar o encodeURIComponent() para tratar o valor.

var value = encodeURIComponent("John Doe");
document.cookie = "username=" + value;

Para saber mais sobre o funcionamento dos cookies e seus respectivos parâmetros, não deixe de consultar a documentação.

Cookies VS LocalStorage?

Na Jornada anterior, você aprendeu a fazer o uso do LocalStorage para armazenar informações dentro do navegador do usuário.

Mas talvez você esteja se perguntando: Qual é a forma mais segura de persistir informações no navegador do usuário?

Para responder essa pergunta, eu criei um artigo que fala sobre Cookies VS LocalStorage: Dicas de como armazenar dados e tokens (JWT) com segurança, vale a pena conferir 🤓

Conclusão

Nesta lição você aprendeu a fazer o uso dos cookies de navegador, e como configurá-los por meio de parâmetros.

Até a próxima lição 😊