jwt in CHICKEN added by klm` on Sun Jan 31 10:56:28 2016

;;$ csi -s jwt.scm 
;;trusted payload: {"sub":"1234567890","name":"John Doe","admin":true}
;;jwt-hs256 token for {"user":"you"}: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoieW91In0.NiDeIMyWH8vn0m--sN6tGB0qoeBtyVlh5KkiqpjyDOw
;;trusted ed25519 payload: {"name":"John Doe"}

(use matchable hmac sha2 base64 tweetnacl)

(define (base64url-decode m) (base64-decode (string-translate m "-_" "+/")))
(define (base64url-encode m)
  (string-trim-right ;; remove = padding (not used/needed in jwt)
   (string-translate (base64-encode m) "+/" "-_") #\=))

(define (hs256 secret) (hmac secret (sha256-primitive)))

;; b64header ignored! (read https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/)
(define (jwt-hs256-verify jwt secret)
  (match (string-split jwt  ".")
    ((b64header b64payload b64signature)
     (and (string=
           (base64url-decode b64signature) ;; not zero-padded
           ((hs256 secret) (string-append b64header "." b64payload)))
          (base64url-decode b64payload)))))

(define (jwt-hs256-sign payload-string secret)
  (let* ((b64header  (base64url-encode "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"))
         (b64payload (base64url-encode payload-string))
         (signed (string-append b64header "." b64payload))
         (b64signature (base64url-encode ((hs256 secret) signed))))
    (string-append signed "." b64signature)))


;; from https://jwt.io/#debugger
(define jwt "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ")
(print "trusted payload: " (jwt-hs256-verify jwt "secret"))

(let ((payload "{\"user\":\"you\"}"))
  (print "jwt-hs256 token for " payload ": " (jwt-hs256-sign payload "secret")))

;; alg:ed25519 works too!
(use tweetnacl)
(define (jwt-ed25519-verify jwt pk)
  (match (string-split jwt  ".")
    ((b64header b64payload b64signature)
     ;; todo: use 'kid' from header and match pk
     (and ((asymmetric-verify (string->blob pk))
           (string-append (base64url-decode b64signature)
                          b64header "." b64payload))
          (base64url-decode b64payload)))))

;; from https://github.com/bryanjos/joken/blob/master/test/support/keys_fixture.exs
(define pk (base64url-decode "l11mBSuP-XxI0KoSG7YEWRp4GWm7dKMOPkItJy2tlMM"))
(define jwt "eyJhbGciOiJFZDI1NTE5IiwidHlwIjoiSldUIn0.eyJuYW1lIjoiSm9obiBEb2UifQ.9a7z_qCuHwBMVSOG9sDzc2Ccbk49tY2GLddqViz0nuB4zG9pQS-jhhGpkYwQ9LE33742__nujzWLaSJ93tYhAw")
(print "trusted ed25519 payload: " (jwt-ed25519-verify jwt pk))