JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

Although JWTs can be encrypted to also provide secrecy between parties, we will focus on signed tokens. Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens are signed using public/private key pairs, the signature also certifies that only the party holding the private key is the one that signed it.

In its compact form, JSON Web Tokens consist of three parts separated by dots (.), which are:

  • Header : The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.
  • Payload : The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional data. You can learn more about claims and its types here
  • Signature : To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that. Read more about JWT signing algorithms.

Therefore, a JWT typically looks like the following.

xxxxx.yyyyy.zzzzz

1 Building a token

Tokens can be generated using a the builder pattern as follows:

Copy
new Ax.crypt.jwt.Builder()
	.addUser('user_xxxx')
	.setExpiration(new Date())
	.signWith(Ax.crypt.jwt.Builder.Algorithm.HS256, "MYSECRET-KEY")
	.build()
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c3IiOiJ1c2VyX3h4eHgiLCJleHAiOjE2MjM3NjI3NTh9.xNv0+mp8d6FrAcjClmhnuKwlw6f2CQY/jRIY7OFFc70=

Allowed signing are algorithm are defined in Ax.crypt.jwt.Builder.Algorithm :

  • HS256
  • HS384
  • HS512
  • RS256
  • RS384
  • RS512
  • NONE

Algorithms prefixed with "HS" use a symetric key, whereas "RS256" uses a private key to sign and a public key for verification

Signing with an algorithm RS* requires the use of a private key:

Copy
var kp = new Ax.crypt.KeyPair("RSA", 2048);
// sign with keys
new Ax.crypt.jwt.Builder()
	.addUser('user_xxxx')
	.setExpiration(new Date(new Date().getTime() + 3600*1000 ))
	.signWith(Ax.crypt.jwt.Builder.Algorithm.RS256, kp.getRawPrivateKey())
	.build()
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c3IiOiJ1c2VyX3h4eHgiLCJleHAiOjE2MjM3NjU4ODl9.sQhxhd3kVjzJhm/wD54C8IO1Az6mp5zFsbn6jZO4zYuIY57PACOCRBgxGB6Wuy3ZuzSjGnvb0uYbVGBHDKXtB48SD67si1B8+K89vhDipmHYcavvyDSfW+ogtnqjLJ2b0HSs5K6YGcgLU/Pg25Lv9Eng/ubLTSguIJbc/mqSQLqL9BeVb2zLiO3jLCicPVl5+trh538Qan/tA2PwiQmcIZNY/1deO7yHcX0NbyZwJSgBJK6+aTAHFizRiGXa60dN7GmAaiJscIZQvdSx7S6kAq8EyDBsF0ENE72Y1nn7ZaPAyQwRkdbtBNGyO1AiUnqxbTM4sPSGEou0TyI4Dk+dqw==

2 Parsing a token

To parse a token we need to specify the secret key:

Copy
new Ax.crypt.jwt.Parser()
    .setSigningKey('MYSECRET-KEY')
    .parse('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c3IiOiJ1c2VyX3h4eHgiLCJleHAiOjE2MjM3NjI3NTh9.xNv0+mp8d6FrAcjClmhnuKwlw6f2CQY/jRIY7OFFc70=')
{
  "usr": "user_xxxx",
  "exp": 1.623766597E9
}

parse() function returns a map with the claims of the token