--- /dev/null
+! Copyright (C) 2021 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: checksums.sha crypto.jwt tools.test ;
+IN: crypto.jwt.tests
+
+{ t } [
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.he0ErCNloe4J7Id0Ry2SEDg09lKkZkfsRiGsdX_vgEg"
+ "" check-signature
+] unit-test
+
+{ t } [
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.QjxgSJl1C760VSNK4e5EZaYo6qemRqYL_Ol8ZgeQreg"
+ "covid" check-signature
+] unit-test
+
+{ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.he0ErCNloe4J7Id0Ry2SEDg09lKkZkfsRiGsdX_vgEg" } [
+ H{ { "alg" "HS256" } { "typ" "JWT" } }
+ H{
+ { "sub" "1234567890" }
+ { "name" "John Doe" }
+ { "iat" 1516239022 }
+ }
+ "" sha-256 sign-jwt
+] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2021 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs base64 checksums.hmac checksums.sha json.reader
+json.writer kernel sequences splitting strings ;
+IN: crypto.jwt
+
+: jwt> ( jwt -- header payload signature )
+ "." split first3
+ [ urlsafe-base64> >string json> ]
+ [ urlsafe-base64> >string json> ]
+ [ ] tri* ;
+
+: hmac-signature ( encoded secret/f method/f -- signature )
+ [ "" or ] [ sha-256 or ] bi*
+ hmac-bytes >urlsafe-base64-jwt >string ;
+
+: jwt-encode-header-payload ( header payload -- encoded )
+ [ >json >urlsafe-base64-jwt ] bi@ "." glue ;
+
+: sign-jwt ( header payload secret/f method/f -- jwt )
+ [ jwt-encode-header-payload dup ] 2dip
+ hmac-signature "." "" glue-as ;
+
+ERROR: unsupported-jwt header ;
+
+: ensure-sha256 ( header -- header )
+ dup "typ" of "JWT" = [ unsupported-jwt ] unless
+ dup "alg" of "HS256" = [ unsupported-jwt ] unless ;
+
+: check-signature ( jwt secret/f -- ? )
+ [
+ "." split first3 [
+ dup
+ urlsafe-base64> >string json> ensure-sha256 drop
+ ] [ "." glue ]
+ [ ] tri*
+ ] dip
+ '[ _ f hmac-signature ] dip = ;