JWT y Golang
Tags: go, webdev, security, api
Published: 2022-10-01 17:37:34

Bien sabemos lo complicado que es cubrir el 100% de los casos de uso cuando hablamos de registro de usuario, autorización y autenticación. Eternas discusiones que nos consumen mucho tiempo y recursos para siempre dejar espacios en blanco que con el tiempo serán subsanados con nuevas versiones de nuestros servicios encargados de estas acciones. Siempre recomiendo, para cada desarrollo donde servidor y cliente están separados, tener un mecanismo basado en Tokens (puede ser JWT, puede ser cualquier otro) para garantizar la autenticidad de las peticiones.

## JWT y REST

Siempre leímos que en **REST** cada petición tiene que ser independiente a su predecesora y sucesora, lo cual es _falso_ para sistemas que requieran autenticación, que a su vez, corresponden a la gran mayoría de los que usamos en nuestras PCs y teléfonos; es muy difícil imaginar poder hacer una transferencia bancaria sin autenticarse primero o querer publicar una entrada en un blog sin antes dejar mis credenciales.

Entonces, tenemos una primera petición bien conocida, que es proveer nuestra identidad, sin importar de qué manera, SSO con Google, GitHub, email y password o biometría, le tenemos que dar _algo_ para que el sistema confíe en que somos nosotros. En un futuro, voy a intentar redactar modelos de autenticación más sofisticados para servidores web.

Una vez validadas las credenciales, el servidor nos otorga una llave para nuestras sucesivas peticiones dentro del mismo dominio, que suele ser un **token** (un string o cadena de caracteres), con un formato específico que ambos entienden, firmado con un algoritmo (que ambos entienden) e información adicional que puede ser cualquier cosa, aunque se recomienda altamente no dejar nada sensible o que pueda llevarnos a conocer más acerca de quién era -el dueño- del Token.

## Morfología del JWT

Sabemos por sus siglas en inglés, qué es JSON, es Web y es un Token, a su vez, cuenta con una estructura bien determinada en la cual se basa el mecanismo. Consta de 3 partes separadas por un punto y cada una de ellas contiene datos específicos, las librerías de los lenguajes nos ayudan a formar JWTs correctos y seguros. También, estas tienen una estructura JSON y están _encodeadas_ en **Base64**.

Éstas partes son:
1. **Headers** -> dónde se encuentran el algoritmo de encriptación usado y el tipo de  token.

2. **Payload** -> acá, se encuentran los datos que queremos transportar del usuario, el campo "sub" (de subject) es donde comúnmente se encuentra un identificador único. Podemos agregar los campos que necesitemos pero es muy importante no agregar nada sensible por un simple hecho; en caso de que el token quede comprometido, la información es totalmente accesible, ya que solo está en formato de Base64 (al igual que las demás partes).

3. **Signature** -> Este segmento valida la firma a la hora de verificar el token y si estaba sellado con una contraseña, debemos utilizar la misma, caso contrario el token va a ser detectado como inválido y por consiguiente, el cliente no podrá consumir el recurso seguro.

Esta imagen es de la web [jwt.io](https://jwt.io) donde pueden practicar como crear uno y validarlo.
![sitio web de jwt.io](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vymgg3rxrk0iu049b0zp.png)

Otros _claims_ (campos) importantes en el payload de JWT son los de "iat" y "exp" que además del "sub" deben viajar siempre y corresponden a _issued at_ (cuando se firmó) y _expires at_ (cuando vence). Es muy común en sitios web ver el check de _remember me_, la gran mayoría de las veces esto es para firmar el token con un exp mucho mayor que si no estuviese checkeado.

---

## Cómo lo hago en Golang?

En Go tenemos librerías muy fáciles de usar, mi consejo es usarlo como servicio e inyectar cuando sea necesario, para después usarlo como middleware, así su uso queda muy natural y desacoplado a la lógica de negocios.

Acá vemos para firmar el token, no necesitamos casi nada extra aparte de "[github.com/golang-jwt/jwt](github.com/golang-jwt/jwt)", solo un secreto para firmar el token y los claims, que además de los estándar, podemos agregar los que necesitemos. Es importante tener en cuenta el tag json para que queden con el formato esperado.

La expiración del token queda grabada en esta firma también.

{% embed https://gist.github.com/tomiok/a483a870016c58959a31994f2506063f %}

Ahora vemos como usarlo como un middleware en los web handlers y declarando como servicio

{% embed https://gist.github.com/tomiok/08d59fba5423a88ec89ec5d3ed8c2ba2 %}

y con estos simples pasos ya podemos agregarlo a cualquier ruta como middleware, en caso de que estemos usando la _std lib_ de Golang, en caso de usar algún framework web com o Gin, Fiber o Echo, vamos a tener que modificar un poco la firma, pero de lo contrario, ya está listo para ser implementado.

Si les gustó el contenido, [me pueden sponsorear aca](https://github.com/sponsors/tomiok)!