Skip to content

joshbax189/jwt-el

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JWT.el

Decode and verify JSON Web Tokens in Emacs.

Verification is supported for RSA and HMAC signatures, with SHA256, SHA384 and SHA512 hashes.

Signing is supported for HMAC only.

Install

No user-specific configuration. Simply install from this repo.

E.g. using straight

(use-package jwt
  :straight (jwt :fetcher git :url "https://github.com/joshbax189/jwt-el"))

Features

  • decode JWT strings and view contents in a buffer
  • display docs for defined claims using eldoc
  • access claims within JWTs from elisp code
  • check token expiry time
  • verify HMAC signatures
  • verify RSA signatures
  • create HMAC signed JWTs

Planned Features

  • verify tokens signed with ECC

Usage

Run M-x jwt-decode then paste the token string into the minibuffer prompt.

This will output the decoded token contents to a buffer.

Alternatively, M-x jwt-decode-at-point will do the same but working on a token in a buffer.

./images/jwt-buffer.png Displaying JWT contents in a buffer

When viewing a decoded JWT, you can verify it using C-c C-c (or M-x jwt-verify-current-token), then paste the key into the minibuffer.

Note that because it is hard to copy raw bytes, the key is assumed to be either an RSA key or a base-64 encoded byte string.

Specific Examples

Here are some examples of using jwt.el in your own code.

Extracting Claims

For example, to get the “sub” claim:

(let* ((token-string     "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")
      (decoded-token (jwt-to-token-json token-string)))
  (map-elt (jwt-token-json-payload-parsed decoded-token) "sub"))

Note that the output of jwt-token-json has JSON strings in its slots. You need to use either jwt-token-json-payload-parsed or jwt-token-json-header-parsed to get the JSON as a Lisp object.

The map library is very helpful for dealing with parsed JSON.

Verify HMAC Signatures

To verify HMAC signatures you need the private key used to sign the token.

Note that the key is read as a list of bytes. So if your key is base64 encoded, you should first decode it:

(let* ((key-string "IUILGn96IQgxBoPgvH0IJ7J9+KhqCGzvwgBZI88qwsw=")
       (byte-string (base64-decode-string key-string)))
  (print (string-to-list byte-string)))
(let* ((key-string "IUILGn96IQgxBoPgvH0IJ7J9+KhqCGzvwgBZI88qwsw=")
       (key (base64-decode-string key-string) "a.b.c")
       (token "eyJhbGciOiJoczI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Adw8gL7v0IwVQsq3B8n6v_0AxdUBJoLmPTiFaP9LYCA"))
  (jwt-verify-signature token key))

Verify RSA Signatures

RSA signatures only need the public key of the signer for verification.

You can use either of these key formats,

e.g. “RSA PUBLIC KEY”

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
luowcXwDwoyinmeOY9eKyh6aY72xJh7noLBBq1N0bWi1e2i+83txOCg4yV2oVXhB
o8pYEJ8LT3el6Smxol3C1oFMVdwPgc0vTl25XucMcG/ALE/KNY6pqC2AQ6R2ERlV
gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
-----END RSA PUBLIC KEY-----

or “PUBLIC KEY”

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u
+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh
kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ
0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg
cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc
mwIDAQAB
-----END PUBLIC KEY-----

Within elisp, verification is like so:

(let ((test-key "-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u
+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh
kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ
0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg
cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc
mwIDAQAB
-----END PUBLIC KEY-----")
      (encoded-jwt "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc4TSMb4bXP3l3YlNWACwyXPGffz5aXHc6lty1Y2t4SWRqGteragsVdZufDn5BlnJl9pdR_kdVFUsra2rWKEofkZeIC4yWytE58sMIihvo9H1ScmmVwBcQP6XETqYd0aSHp1gOa9RdUPDvoXQ5oqygTqVtxaDr6wUFKrKItgBMzWIdNZ6y7O9E0DhEPTbE9rfBo6KTFsHAZnMg4k68CDp2woYIaXbmYTWcvbzIuHO7_37GT79XdIwkm95QJ7hYC9RiwrV7mesbY4PAahERJawntho0my942XheVLmGwLMBkQ"))
 (jwt-verify-signature
  encoded-jwt
  test-key))

Create HMAC Signatures

Here we sign with just a randomly generated key:

(let* ((key (jwt--random-bytes 64))
       (payload '((sub . "1234567890")
                  (name . "John Doe")
                  (iat . 1516239022))))
  (jwt-create payload "hs256" key))

You can set the “iat” claim to reflect current time, like so:

(let* ((key (jwt--random-bytes 64))
       (payload '((sub . "1234567890")
                  (name . "John Doe")))
       (token (jwt-create payload "hs256" key nil 't)))
  (map-elt (jwt-token-json-payload-parsed (jwt-to-token-json token)) "iat"))

Changelog

0.2.0

  • add jwt-decode-region
  • add IANA defined claims to eldoc

0.1.1

  • fix token string predicate

0.1.0

  • decode tokens
  • verify with HMAC and RSA signatures
  • print help for defined claims

About

Interact with JSON Web Tokens from Emacs

Resources

License

Stars

Watchers

Forks

Packages

No packages published