JSON Object Signing and Encryption Library

Version on this page:0.9.6
LTS Haskell 22.29:0.9.6
Stackage Nightly 2024-07-19:0.10.0
Latest on Hackage:0.10.0

See all snapshots jose-jwt appears in

BSD-3-Clause licensed and maintained by Luke Taylor
This version can be pinned in stack with:jose-jwt-0.9.6@sha256:cc234805da58fc75bc4c11af3db2dabf920f2c7d5d8b9a2b73bdb7c024b8d087,3557

Module documentation for 0.9.6


A Haskell implementation of the JSON Object Signing and Encryption (JOSE) specifications and the related JWT specification, as used, for example, in OpenID Connect.


The JWT specification was split into JWS and JWE during its development so does not contain much. A JWT is either a JWS or a JWE depending on whether it is signed or encrypted. It is encoded as a sequence of base64 strings separated by ‘.’ characters [1].

Technically, the content of a JWT should be JSON (unless it’s a nested JWT), but this library doesn’t care - it only requires a bytestring. The application should verify that the content is valid. Exactly what that means will depend on what you are using JWTs for.


You can either use the high-level encode and decode functions in the Jwt module or specific functions in the Jws and Jwe modules.

The following examples can be entered directly into ghci. Use

> :set -XOverloadedStrings

to begin with.

JWS signing example with a symmetric HMAC algorithm

HMAC is a good choice when both signer and verifier have a copy of the key.

> import Jose.Jws (hmacEncode, hmacDecode)
> import Jose.Jwa (JwsAlg(HS256))
> hmacEncode HS256 "aRANDOMlygeneratedkey" "my JSON message"
Right (Jwt {unJwt = "eyJhbGciOiJIUzI1NiJ9.bXkgSlNPTiBtZXNzYWdl.lTJx7ECLwYF3P7WbrrUpcp_2SdLiFXaDwK-PXcipt5Q"})
> hmacDecode "aRANDOMlygeneratedkey" "eyJhbGciOiJIUzI1NiJ9.bXkgSlNPTiBtZXNzYWdl.lTJx7ECLwYF3P7WbrrUpcp_2SdLiFXaDwK-PXcipt5Q"
Right (JwsHeader {jwsAlg = HS256, jwsTyp = Nothing, jwsCty = Nothing, jwsKid = Nothing},"my JSON message")

Trying to decode with a different key would return a Left BadSignature [2].

JWS signing using Ed25519 private key

Some situations require the use of public key cryptography for signing. For example, only a trusted party is allowed to create a signed token, but it must be verified by others.

Elliptic-curve EdDSA signing and verification are supported as defined in RFC 8037, as well as the older RSA JWS algorithms.

> import Jose.Jwt
> import Jose.Jwk
> import Jose.Jwa (JwsAlg(EdDSA))
> import Data.ByteString (ByteString)
> import Data.Aeson (decodeStrict)
> jsonJwk = "{\"kty\":\"OKP\", \"crv\":\"Ed25519\", \"d\":\"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A\", \"x\":\"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo\"}" :: ByteString
> Just jwk = decodeStrict jsonJwk :: Maybe Jwk
> Jose.Jwt.encode [jwk] (JwsEncoding EdDSA) (Claims "public claims")
Right (Jwt {unJwt = "eyJhbGciOiJFZERTQSJ9.cHVibGljIGNsYWltcw.xYekeeGSQVpnQbl16lOCqFcmYsUj3goSTrZ4UBQqogjHLrvFUaVJ_StBqly-Tb-0xvayjUMM4INYBTwFMt_xAQ"})

To verify the JWT you would use the Jose.Jwt.decode function with the corresponding public key.

More examples can be found in the package documentation.

Build Status

Build Status

[1] This is now referred to as “compact serialization”. The additional “JSON serialization” is not supported in this library.

[2] Note that a real key for HMAC256 should be a much longer, random string of bytes. See, for example, this stackexchange answer.



  • Updated aeson package bound to include 2.2


  • Support for mtl 2.3


  • Support for aeson 2


  • Add upper bound < 1.6 for aeson dependency
  • Add Num Instance for IntDate


  • Add UnsupportedJwt constructor to Jwk type which wraps the JSON value. This prevents failure loading keys which have alg or kty values which we don’t support (see #31).



  • Support for EdDSA signing algorithms as defined in RFC 8037.


  • The result of the Jose.Jwt.decodeClaims function is now polymorphic so it can be used with any FromJSON type.
  • Only ghc 8 upwards are now supported.
  • the RSA-OAEP-256 algorithm is now supported.


  • Switch from EitherT to ExceptT to allow compiling with latest version of ‘either’ package.


  • User ByteArray and ScrubbedBytes from memory package in preference to ByteString in internal crypto code.


  • Fixed exception when JWT contained invalid Base64 (issue #15).
  • Add generateSymmetricKey utility function to Jwk module.


  • A JWT parser is now used to separate parsing and decoding into separate stages (internal change).


  • Stricter checking of AES key lengths when looking for a valid JWK to encode/decode an AES-KW JWT.


  • Add JSON test data to extra-source-files.


  • Remove test dependency on aeson-qq


  • Update cryptonite version to 0.19 to avoid security issues
  • Fix broken benchmark code
  • Better error message for invalid key length when using AES keywrap


  • Add support for AES key wrap in JWEs.
  • Support A192GCM and A192CBC-HS384 algorithms.
  • Switch to cryptonite library.


  • Remove dependency on errors package.


  • Minor internal changes to fix build on GHC 7.10.


  • Change KeyId type to allow use of a UTCTime string for the identifier.
  • Internal crypto fixes to prevent exceptions from external libraries.


  • Add JwtEncoding type. Changes API of Jwt.encode and Jwt.decode.


  • Fix in the code for finding suitable JWKs for encoding/decoding.

  • Added doctest flag to cabal file to allow doctests to be disabled.


  • Add cprng-aes dependency to doctests to stop test failure on travis and nixos hydra builds.


  • Changed use of Jwt type to represent an encoded JWT.
  • Introduced Payload type to allow setting the cty header value correctly for nested JWTs.
  • Added an explicit Unsecured type for a decoded JWT, to make it obvious when the content is not signed or encrypted.
  • Fixed some bugs in JSON encoding and decoding of EC JWKs.


Changed the signature of Jwt.encode to take a list of Jwk rather than a single key. The key will be selected from the list based on the specified algorithms.


  • New support for JWS validation using elliptic curve algorithms.
  • Added Jwt.encode function which takes a JWK argument, allowing key data (currently the key ID) to be encoded in the token header.