JWT — Jugando con Autenticación con Tokens

Matías Mascazzini
Memorias de un Techie
4 min readNov 3, 2016
JWT.io

Me tocó jugar con el Simple Sing-on de Zendesk, para poder loguear usuarios de una aplicación en el sistema de tickets de soporte de zendesk.

Para implementar el logueo en un simple enlace los de Zendesk implementan algo llamado JWT (JSON Web Token) y otra cosa llamada SAML (Secure Assertion Markup Language) que no viene al caso. Así que iré tomando nota en voz alta por si le sirve a otro artesano.

Existen varias formas de identificar un usuario que están relacionadas con los principios de la seguridad de la información: algo que sé, algo que tengo, algo que soy, algo que haga. El Token es algo que tengo y que sé.

Su razón de ser tienen que ver con la escalabilidad de un servicio web, si me identifico con algo que sé, usuario y clave generalmente, el problema esta en dónde guardo el "estado" de que el usuario esta identificado cuando tengo varios servicios corriendo en servidores distintos. Así que a googlear "Autenticación sin estado con Tokens", sino se me hace muy largo el post.

¿Qué es JWT (JSON Web Token)?

Es un estándar de autenticación basado en JSON, que es agnóstico de lenguaje, y lo podemos utilizar en el sabor que más nos guste Ruby, Elixir, Node.js, Python, PHP, .NET, Java, Clojure, ClojureScript, etc. etc.

JWT es un reciente estándar abierto que está siendo liderado por el organismo internacional de estándares IETF y patrocinado por grandes empresas del sector tecnológico (como Google, Microsoft, Facebook, etc).

La especificación técnica se encuentra disponible en http://tools.ietf.org/html/draft-jones-json-web-token-10 . Y en el RFC7519 https://tools.ietf.org/html/rfc7519#section-4.1.4

Te dejo otro doc. que lo explica técnicamente: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html

Y la entrada en la popular Wikipedia (ENG) https://en.wikipedia.org/wiki/JSON_Web_Token

Básicamente, se agarra una maraña de datos JSON y se los encripta para ser transmitidos como una cadena de caracteres encriptada.

¿Cómo es un token JWT?

El formato de un JWT está compuesto por 3 cadenas de caracteres separadas simplemente por un punto '.', se ven algo así como el siguiente ejemplo:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoiMTMwODE5ODExMjM0NSIsImV4cCI6IjEzMDgxOTgxMTIzNDUiLCJuYW1lIjoiUGVwZSBBcmdlbnRvIiwiYWRtaW4iOnRydWV9.J5YqqXepOKiVrrUAMcy5TEWPRPM12OiXjRZImtJBui8

Cada parte de la cadena tiene un significado particular:

Header

  • La primera parte es la cabecera del token, que a su vez tiene otras dos partes, el tipo, en este caso un JWT y la codificación utilizada. Comúnmente es el algoritmo HMAC SHA256, El contenido sin codificar es el siguiente:
{
“alg”: “HS256”,
“typ”: “JWT”
}

(en este caso el header contiene ALGORITHM & TOKEN TYPE)

Luego de codificar, es la primera parte de la cadena antes del punto:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Payload es otra de sus partes

Está compuesto por los llamados JWT Claims donde irán colocados la atributos que definen nuestro token. Existen varios que puedes consultar aquí, los más comunes a utilizar son:

  • sub: Identifica el sujeto del token, por ejemplo un identificador de usuario.
  • iat: Identifica la fecha de creación del token, válido para si queremos ponerle una fecha de caducidad. En formato de tiempo UNIX
  • exp: Identifica a la fecha de expiración del token. Podemos calcularla a partir del iat. También en formato de tiempo UNIX.
{
"sub": "1234567890",
"iat": "1308198112345",
"exp": "1308198112345",
"name": "Pepe Argento",
"admin": true
}

En la cadena codificada el JWT, queda asi:

eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoiMTMwODE5ODExMjM0NSIsImV4cCI6IjEzMDgxOTgxMTIzNDUiLCJuYW1lIjoiUGVwZSBBcmdlbnRvIiwiYWRtaW4iOnRydWV9

También podemos añadirle más campos, incluso personalizados, como pueden ser el el mail del usuario, su rol, etc.

Signature es la tercer parte

Esta firma está formada por los anteriores componentes (Header y Payload) cifrados en Base64 con una clave secreta (un secreto almacenada en nuestro servidor). Así sirve de Hash para comprobar que todo está bien.

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
86bae26023208e57a5880d5ad644143c567fc57baaf5a942
)

Para este ejemplo use el hash:

 86bae26023208e57a5880d5ad644143c567fc57baaf5a942

Luego de codificar nuestro Token JWT, quedará con esta forma:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoiMTMwODE5ODExMjM0NSIsImV4cCI6IjEzMDgxOTgxMTIzNDUiLCJuYW1lIjoiUGVwZSBBcmdlbnRvIiwiYWRtaW4iOnRydWV9.J5YqqXepOKiVrrUAMcy5TEWPRPM12OiXjRZImtJBui8

Y al decodificarlo deberiamos obtener los datos que hemos usado para codificarlo.

Sino aguantas la ansiedad, podes crear tus token de prueba en este sitio web: https://jwt.io/ que es el que usé para crear los ejemplos.

Examples:

Algunos ejemplos de implementación en los repositorios de JWT.io

En Clojure:

http://funcool.github.io/buddy-core/latest/

lein: [funcool/buddy “0.6.0”]

https://github.com/liquidz/clj-jwtLien: [clj-jwt “0.1.1”]

En ClojureScript:

ClojureScript JWT encode/decode (SHA version only) — gist

https://gist.github.com/aputs/b6e255e79ef99bf90ff80a1177044a01

En Ruby.

gem install jwt

gem install json-jwt

gem install json_web_token

SSO (single sign-on) en Zendesk

lo que me lleva al principio de mi problema, como usar JWT con Zendesk para hacer un inicio de sesión único.

Te dejo la info. oficial de zendesk en español.

Que dice que el payload, tiene que tener: iat (a que hora fue emitido), jti (id única para el token), email (del usuario), name (nombre del usuario)

{
"iat": "1308198112345",
"jti": "1308198112345",
"name": "Pepe Argento",
"email": "pepe@argento.com"
}

Y que luego tienen que usarlo, armando una URL:

https://micompañía.zendesk.com/access/jwt?jwt=payload

El secret, lo obtienes de la configuración de seguridad de la cuenta de zendesk.

Y basándome en los ejemplos oficiales de zendesk:

Hice mi prueba de concepto con Ruby on Rails para Zendesk el SSO.

Ahora a laburar en la prueba de concepto en Clojure…

--

--

Matías Mascazzini
Memorias de un Techie

Workhorse Techie, software developer craftsmanship. I like Ruby http://ruby-lang.org, Ruby On Rails framework & drink mate. He/Him/él.