diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,13 @@
+0.7.6
+-----
+
+* Fixed exception when JWT contained invalid Base64 (issue #15).
+* Add generateSymmetricKey utility function to Jwk module.
+
 0.7.5
 -----
 
-* A JWT parser is now used to separate parsing and decoding into separaate stages (internal change).
+* A JWT parser is now used to separate parsing and decoding into separate stages (internal change).
 
 0.7.4
 -----
diff --git a/Jose/Internal/Parser.hs b/Jose/Internal/Parser.hs
--- a/Jose/Internal/Parser.hs
+++ b/Jose/Internal/Parser.hs
@@ -139,4 +139,4 @@
 
 
 b64Decode :: ByteString -> P.Parser ByteString
-b64Decode bs = either (fail "Invalid Base64") return $ convertFromBase Base64URLUnpadded bs
+b64Decode bs = either (const (fail "Invalid Base64")) return $ convertFromBase Base64URLUnpadded bs
diff --git a/Jose/Jwe.hs b/Jose/Jwe.hs
--- a/Jose/Jwe.hs
+++ b/Jose/Jwe.hs
@@ -1,16 +1,37 @@
 {-# LANGUAGE OverloadedStrings #-}
 
--- | JWE RSA encrypted token support.
+-- | JWE encrypted token support.
 --
--- Example usage:
+-- To create a JWE, you need to select two algorithms. One is an AES algorithm
+-- used to encrypt the content of your token (for example, @A128GCM@), for which
+-- a single-use key is generated internally. The second is used to encrypt
+-- this content-encryption key and can be either an RSA or AES-keywrap algorithm.
+-- You need to generate a suitable key to use with this, or load one from storage.
 --
+-- AES is much faster and creates shorter tokens, but both the encoder and decoder
+-- of the token need to have a copy of the key, which they must keep secret. With
+-- RSA anyone can send you a JWE if they have a copy of your public key.
+--
+-- In the example below, we show encoding and decoding using a 512 byte RSA key pair
+-- (in practice you would use a larger key-size, for example 2048 bytes):
+--
 -- >>> import Jose.Jwe
 -- >>> import Jose.Jwa
--- >>> import Crypto.PubKey.RSA
--- >>> (kPub, kPr) <- generate 512 65537
--- >>> Right (Jwt jwt) <- rsaEncode RSA_OAEP A128GCM kPub "secret claims"
--- >>> rsaDecode kPr jwt
--- Right (JweHeader {jweAlg = RSA_OAEP, jweEnc = A128GCM, jweTyp = Nothing, jweCty = Nothing, jweZip = Nothing, jweKid = Nothing},"secret claims")
+-- >>> import Jose.Jwk (generateRsaKeyPair, generateSymmetricKey, KeyUse(Enc), KeyId)
+-- >>> (kPub, kPr) <- generateRsaKeyPair 512 (KeyId "My RSA Key") Enc Nothing
+-- >>> Right (Jwt jwt) <- jwkEncode RSA_OAEP A128GCM kPub (Claims "secret claims")
+-- >>> Right (Jwe (hdr, claims)) <- jwkDecode kPr jwt
+-- >>> claims
+-- "secret claims"
+--
+-- Using 128-bit AES keywrap is very similar, the main difference is that
+-- we generate a 128-bit symmetric key:
+--
+-- >>> aesKey <- generateSymmetricKey 16 (KeyId "My Keywrap Key") Enc Nothing
+-- >>> Right (Jwt jwt) <- jwkEncode A128KW A128GCM aesKey (Claims "more secret claims")
+-- >>> Right (Jwe (hdr, claims)) <- jwkDecode aesKey jwt
+-- >>> claims
+-- "more secret claims"
 
 module Jose.Jwe
     ( jwkEncode
diff --git a/Jose/Jwk.hs b/Jose/Jwk.hs
--- a/Jose/Jwk.hs
+++ b/Jose/Jwk.hs
@@ -15,12 +15,13 @@
     , canEncodeJws
     , canEncodeJwe
     , generateRsaKeyPair
+    , generateSymmetricKey
     )
 where
 
 import           Control.Applicative (pure)
 import           Control.Monad (unless)
-import           Crypto.Random (MonadRandom)
+import           Crypto.Random (MonadRandom, getRandomBytes)
 import qualified Crypto.PubKey.RSA as RSA
 import qualified Crypto.PubKey.ECC.ECDSA as ECDSA
 import qualified Crypto.PubKey.ECC.Types as ECC
@@ -72,6 +73,16 @@
 generateRsaKeyPair nBytes id' kuse kalg = do
     (kPub, kPr) <- RSA.generate nBytes 65537
     return (RsaPublicJwk kPub (Just id') (Just kuse) kalg, RsaPrivateJwk kPr (Just id') (Just kuse) kalg)
+
+generateSymmetricKey :: (MonadRandom m)
+    => Int
+    -> KeyId
+    -> KeyUse
+    -> Maybe Alg
+    -> m Jwk
+generateSymmetricKey size id' kuse kalg = do
+    k <- getRandomBytes size
+    return $ SymmetricJwk k (Just id') (Just kuse) kalg
 
 isPublic :: Jwk -> Bool
 isPublic RsaPublicJwk {} = True
diff --git a/Jose/Jwt.hs b/Jose/Jwt.hs
--- a/Jose/Jwt.hs
+++ b/Jose/Jwt.hs
@@ -3,7 +3,9 @@
 
 -- | High-level JWT encoding and decoding.
 --
--- Example usage:
+-- See the Jose.Jws and Jose.Jwe modules for specific JWS and JWE examples.
+--
+-- Example usage with a key stored as a JWK:
 --
 -- >>> import Jose.Jwe
 -- >>> import Jose.Jwa
diff --git a/jose-jwt.cabal b/jose-jwt.cabal
--- a/jose-jwt.cabal
+++ b/jose-jwt.cabal
@@ -1,5 +1,5 @@
 Name:               jose-jwt
-Version:            0.7.5
+Version:            0.7.6
 Synopsis:           JSON Object Signing and Encryption Library
 Homepage:           http://github.com/tekul/jose-jwt
 Bug-Reports:        http://github.com/tekul/jose-jwt/issues
diff --git a/tests/Tests/JweSpec.hs b/tests/Tests/JweSpec.hs
--- a/tests/Tests/JweSpec.hs
+++ b/tests/Tests/JweSpec.hs
@@ -150,6 +150,8 @@
         unpad "111\t\t\t\t\t\t\t" @?= Nothing
       it "Padding byte which matches padding length is OK" $
         unpad "1111111\t\t\t\t\t\t\t\t\t" @?= Just "1111111"
+      it "Rejects invalid Base64 JWT" $
+        withBlinder (Jwe.rsaDecode a2PrivKey "=.") @?= Left BadCrypto
 
 -- verboseQuickCheckWith quickCheckWith stdArgs {maxSuccess=10000}  jweRoundTrip
 jweRoundTrip :: RNG -> JWEAlgs -> [Word8] -> Bool
