diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+0.6
+---
+
+* Change KeyId type to allow use of a UTCTime string for the identifier.
+* Internal crypto fixes to prevent exceptions from external libraries.
+
 0.5
 ---
 
diff --git a/Jose/Internal/Crypto.hs b/Jose/Internal/Crypto.hs
--- a/Jose/Internal/Crypto.hs
+++ b/Jose/Internal/Crypto.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, FlexibleContexts #-}
 {-# OPTIONS_HADDOCK prune #-}
 
 -- | Internal functions for encrypting and signing / decrypting
@@ -22,6 +22,7 @@
 
 import           Control.Applicative
 import           Crypto.Cipher.Types (AuthTag(..))
+import           Control.Monad.Error
 import           Crypto.Number.Serialize (os2ip)
 import qualified Crypto.PubKey.ECC.ECDSA as ECDSA
 import qualified Crypto.PubKey.RSA as RSA
@@ -124,8 +125,8 @@
 generateCmkAndIV :: CPRG g
                  => g   -- ^ The random number generator
                  -> Enc -- ^ The encryption algorithm to be used
-                 -> (B.ByteString, B.ByteString, g) -- ^ The key, IV and generator
-generateCmkAndIV g e = (cmk, iv, g'')
+                 -> ((B.ByteString, B.ByteString), g) -- ^ The key, IV and generator
+generateCmkAndIV g e = ((cmk, iv), g'')
   where
     (cmk, g') = cprgGenerate (keySize e) g
     (iv, g'') = cprgGenerate (ivSize e) g'  -- iv for aes gcm or cbc
@@ -162,7 +163,7 @@
            -> RSA.PrivateKey                -- ^ The decryption key
            -> B.ByteString                  -- ^ The encrypted content
            -> Either JwtError B.ByteString  -- ^ The decrypted key
-rsaDecrypt blinder a rsaKey jweKey = either (const $ Left BadCrypto) Right $ decrypt rsaKey jweKey
+rsaDecrypt blinder a rsaKey jweKey = either (const $ throwError BadCrypto) return $ decrypt rsaKey jweKey
   where
     decrypt = case a of
         RSA1_5   -> PKCS15.decrypt blinder
@@ -171,16 +172,15 @@
 oaepParams :: OAEP.OAEPParams
 oaepParams = OAEP.defaultOAEPParams (hashFunction hashDescrSHA1)
 
--- TODO: Need to check key length and IV are is valid for enc.
-
 -- | Decrypt an AES encrypted message.
-decryptPayload :: Enc        -- ^ Encryption algorithm
+decryptPayload :: MonadError JwtError m
+               => Enc        -- ^ Encryption algorithm
                -> ByteString -- ^ Content management key
                -> ByteString -- ^ IV
                -> ByteString -- ^ Additional authentication data
                -> ByteString -- ^ The integrity protection value to be checked
                -> ByteString -- ^ The encrypted JWT payload
-               -> Either JwtError ByteString
+               -> m ByteString
 decryptPayload e cek iv aad sig ct = do
     (plaintext, tag) <- case e of
         A128GCM        -> decryptedGCM
@@ -189,11 +189,12 @@
         A256CBC_HS512  -> decryptedCBC 32 hashDescrSHA512
     if tag == AuthTag sig
       then return plaintext
-      else Left BadSignature
+      else throwError BadSignature
   where
-    decryptedGCM = Right $ AES.decryptGCM (AES.initAES cek) iv aad ct
+    decryptedGCM = return $ AES.decryptGCM (AES.initAES cek) iv aad ct
 
     decryptedCBC l h = do
+      unless (B.length ct `mod` 16 == 0) $ throwError BadCrypto
       let (macKey, encKey) = B.splitAt (B.length cek `div` 2) cek
       let al = fromIntegral (B.length aad) * 8 :: Word64
       plaintext <- unpad $ AES.decryptCBC (AES.initAES encKey) iv ct
@@ -222,11 +223,11 @@
 authTag :: Int -> HashDescr -> ByteString -> ByteString -> AuthTag
 authTag l h k m = AuthTag $ B.take l $ hmac (hashFunction h) 64 k m
 
-unpad :: ByteString -> Either JwtError ByteString
+unpad :: MonadError JwtError m => ByteString -> m ByteString
 unpad bs
-    | padLen > 16 || padLen /= B.length padding = Left BadCrypto
-    | B.any (/= padByte) padding = Left BadCrypto
-    | otherwise = Right pt
+    | padLen > 16 || padLen /= B.length padding = throwError BadCrypto
+    | B.any (/= padByte) padding = throwError BadCrypto
+    | otherwise = return pt
   where
     len     = B.length bs
     padByte = B.last bs
diff --git a/Jose/Jwe.hs b/Jose/Jwe.hs
--- a/Jose/Jwe.hs
+++ b/Jose/Jwe.hs
@@ -23,7 +23,9 @@
 
 import Control.Arrow (first)
 import Crypto.Cipher.Types (AuthTag(..))
+import Control.Error
 import Crypto.PubKey.RSA (PrivateKey(..), PublicKey(..), generateBlinder, private_pub)
+import Control.Monad.State.Strict
 import Crypto.Random.API (CPRG)
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as B
@@ -75,39 +77,43 @@
     a   = jweAlg h
     e   = jweEnc h
     hdr = encodeHeader h
-    (cmk, iv, rng') = generateCmkAndIV rng e
+    ((cmk, iv), rng') = generateCmkAndIV rng e
     (jweKey, rng'') = rsaEncrypt rng' a pubKey cmk
     aad = B64.encode hdr
     (ct, AuthTag sig) = encryptPayload e cmk iv aad claims
     jwe = B.intercalate "." $ map B64.encode [hdr, jweKey, iv, ct, sig]
 
-
 -- | Decrypts a JWE.
 rsaDecode :: CPRG g
           => g
           -> PrivateKey               -- ^ Decryption key
           -> ByteString               -- ^ The encoded JWE
           -> (Either JwtError Jwe, g) -- ^ The decoded JWT, unless an error occurs
-rsaDecode rng pk jwt = (decode blinder, rng')
-  where
-    (blinder, rng') = generateBlinder rng (public_n $ private_pub pk)
+rsaDecode rng pk jwt = flip runState rng $ runEitherT $ do
+    blinder <- state $ \g -> generateBlinder g (public_n $ private_pub pk)
 
-    decode b = do
-        checkDots
-        let components = BC.split '.' jwt
-        let aad = head components
-        [h, ek, iv, payload, sig] <- mapM B64.decode components
-        hdr <- case parseHeader h of
-            Right (JweH jweHdr) -> return jweHdr
-            Right (JwsH _)      -> Left (BadHeader "Header is for a JWS")
-            Right UnsecuredH    -> Left (BadHeader "Header is for an unsecured JWT")
-            Left e              -> Left e
-        let alg = jweAlg hdr
-        cek    <- rsaDecrypt (Just b) alg pk ek
-        claims <- decryptPayload (jweEnc hdr) cek iv aad sig payload
-        return (hdr, claims)
+    checkDots
+    let components = BC.split '.' jwt
+    let aad = head components
+    [h, ek, providedIv, payload, sig] <- mapM B64.decode components
+    hdr <- case parseHeader h of
+        Right (JweH jweHdr) -> return jweHdr
+        Right (JwsH _)      -> left (BadHeader "Header is for a JWS")
+        Right UnsecuredH    -> left (BadHeader "Header is for an unsecured JWT")
+        Left e              -> left e
+    let alg = jweAlg hdr
+        enc = jweEnc hdr
+    (dummyCek, dummyIv) <- state $ \g -> generateCmkAndIV g enc
+    let decryptedCek = either (const dummyCek) id $ rsaDecrypt (Just blinder) alg pk ek
+        cek = if B.length decryptedCek == B.length dummyCek
+                then decryptedCek
+                else dummyCek
+        iv  = if B.length providedIv == B.length dummyIv
+                 then providedIv
+                 else dummyIv
+    claims <- decryptPayload enc cek iv aad sig payload
+    return (hdr, claims)
 
-    checkDots = case BC.count '.' jwt of
-                    4 -> Right ()
-                    _ -> Left $ BadDots 4
+  where
+    checkDots = unless (BC.count '.' jwt == 4) $ left (BadDots 4)
 
diff --git a/Jose/Jwk.hs b/Jose/Jwk.hs
--- a/Jose/Jwk.hs
+++ b/Jose/Jwk.hs
@@ -7,14 +7,20 @@
     , KeyId
     , Jwk (..)
     , JwkSet (..)
+    , isPublic
+    , isPrivate
+    , jwkId
+    , jwkUse
     , canDecodeJws
     , canDecodeJwe
     , canEncodeJws
     , canEncodeJwe
+    , generateRsaKeyPair
     )
 where
 
 import           Control.Applicative (pure)
+import           Crypto.Random (CPRG)
 import qualified Crypto.PubKey.RSA as RSA
 import qualified Crypto.PubKey.ECC.ECDSA as ECDSA
 import qualified Crypto.Types.PubKey.ECC as ECC
@@ -55,6 +61,27 @@
     { keys :: [Jwk]
     } deriving (Show, Eq, Generic)
 
+generateRsaKeyPair :: (CPRG g)
+    => g
+    -> Int
+    -> KeyId
+    -> KeyUse
+    -> Maybe Alg
+    -> ((Jwk, Jwk), g)
+generateRsaKeyPair rng nBytes id' kuse kalg =
+    let ((kPub, kPr), rng') = RSA.generate rng nBytes 65537
+    in  ((RsaPublicJwk kPub (Just id') (Just kuse) kalg, RsaPrivateJwk kPr (Just id') (Just kuse) kalg), rng')
+
+isPublic :: Jwk -> Bool
+isPublic RsaPublicJwk {} = True
+isPublic EcPublicJwk  {} = True
+isPublic _ = False
+
+isPrivate :: Jwk -> Bool
+isPrivate RsaPrivateJwk {} = True
+isPrivate EcPrivateJwk  {} = True
+isPrivate _ = False
+
 canDecodeJws :: JwsHeader -> Jwk -> Bool
 canDecodeJws hdr jwk = jwkUse jwk /= Just Enc &&
     keyIdCompatible (jwsKid hdr) jwk &&
@@ -292,7 +319,7 @@
     , y   :: Maybe JwkBytes
     , use :: Maybe KeyUse
     , alg :: Maybe Alg
-    , kid :: Maybe Text
+    , kid :: Maybe KeyId
     , x5u :: Maybe Text
     , x5c :: Maybe [Text]
     , x5t :: Maybe Text
diff --git a/Jose/Jwt.hs b/Jose/Jwt.hs
--- a/Jose/Jwt.hs
+++ b/Jose/Jwt.hs
@@ -17,7 +17,7 @@
 -- >>> let (Right (Jwt jwtEncoded), g')  = encode g [jwk] (JwsEncoding RS256) (Claims "public claims")
 -- >>> let (Right jwtDecoded, g'') = Jose.Jwt.decode g' [jwk] (Just (JwsEncoding RS256)) jwtEncoded
 -- >>> jwtDecoded
--- Jws (JwsHeader {jwsAlg = RS256, jwsTyp = Nothing, jwsCty = Nothing, jwsKid = Just "mykey"},"public claims")
+-- Jws (JwsHeader {jwsAlg = RS256, jwsTyp = Nothing, jwsCty = Nothing, jwsKid = Just (KeyId "mykey")},"public claims")
 
 module Jose.Jwt
     ( module Jose.Types
diff --git a/Jose/Types.hs b/Jose/Types.hs
--- a/Jose/Types.hs
+++ b/Jose/Types.hs
@@ -14,7 +14,7 @@
     , JwtError (..)
     , IntDate (..)
     , Payload (..)
-    , KeyId
+    , KeyId (..)
     , parseHeader
     , encodeHeader
     , defJwsHdr
@@ -30,12 +30,15 @@
 import qualified Data.ByteString.Lazy as BL
 import qualified Data.HashMap.Strict as H
 import Data.Int (Int64)
+import Data.Time.Clock (UTCTime)
 import Data.Time.Clock.POSIX
+import Data.Time.Format
 import Data.Text (Text)
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as TE
 import Data.Vector (singleton)
 import GHC.Generics
+import System.Locale (defaultTimeLocale)
 
 import Jose.Jwa (JweAlg(..), JwsAlg (..), Enc(..))
 
@@ -69,8 +72,22 @@
                | UnsecuredH
                  deriving (Show)
 
-type KeyId   = Text
+data KeyId
+    = KeyId    Text
+    | UTCKeyId UTCTime
+      deriving (Eq, Show, Ord)
 
+instance ToJSON KeyId
+  where
+    toJSON (KeyId t)    = toJSON t
+    toJSON (UTCKeyId t) = toJSON t
+
+instance FromJSON KeyId
+  where
+    parseJSON = withText "KeyId" $ \t ->
+        case parseTime defaultTimeLocale "%FT%T%QZ" (T.unpack t) of
+            Just d -> pure (UTCKeyId d)
+            _      -> pure (KeyId t)
 
 -- | Header content for a JWS.
 data JwsHeader = JwsHeader {
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.5
+Version:            0.6
 Synopsis:           JSON Object Signing and Encryption Library
 Homepage:           http://github.com/tekul/jose-jwt
 Bug-Reports:        http://github.com/tekul/jose-jwt/issues
@@ -59,8 +59,9 @@
                     , crypto-random >= 0.0.7
                     , crypto-numbers >= 0.2
                     , cipher-aes >= 0.2.6
-                    , errors >= 1.4
-                    , aeson >= 0.7
+                    , errors >= 1.4 && < 2.0
+                    , aeson >= 0.8.1.0
+                    , old-locale
                     , text  >= 0.11
                     , time  >= 1.4
                     , unordered-containers >= 0.2
diff --git a/tests/Tests/JweSpec.hs b/tests/Tests/JweSpec.hs
--- a/tests/Tests/JweSpec.hs
+++ b/tests/Tests/JweSpec.hs
@@ -9,6 +9,7 @@
 import Data.Either.Combinators
 import Data.Word (Word8)
 import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as BC
 import Test.Hspec
 import Test.HUnit hiding (Test)
 import Test.QuickCheck
@@ -38,7 +39,7 @@
 
       it "generates the expected IV and CMK from the RNG" $ do
         let g = RNG $ B.append a1cek a1iv
-        generateCmkAndIV g A256GCM @?= (a1cek, a1iv, RNG "")
+        generateCmkAndIV g A256GCM @?= ((a1cek, a1iv), RNG "")
 
       it "generates the expected RSA-encrypted content key" $ do
         let g = RNG a1oaepSeed
@@ -66,6 +67,22 @@
             Just  k2 = decodeStrict' a2jwk
         fst (decode blinderRNG [k2, k1] (Just $ JweEncoding RSA_OAEP A256GCM) a1) @?= (Right $ Jwe (a1Header, a1Payload))
 
+      it "a truncated CEK returns BadSignature" $ do
+        let [hdr, _, iv, payload, tag] = BC.split '.' a1
+            (newEk, _) = rsaEncrypt blinderRNG RSA_OAEP a1PubKey (B.tail a1cek)
+        fst (Jwe.rsaDecode blinderRNG a1PrivKey (B.intercalate "." [hdr, B64.encode newEk, iv, payload, tag])) @?= Left BadSignature
+
+      it "a truncated payload returns BadSignature" $ do
+        let [hdr, ek, iv, payload, tag] = BC.split '.' a1
+            Right ct = B64.decode payload
+        fst (Jwe.rsaDecode blinderRNG a1PrivKey (B.intercalate "." [hdr, ek, iv, B64.encode (B.tail ct), tag])) @?= Left BadSignature
+
+      it "a truncated IV returns BadSignature" $ do
+        let (fore, aft) = BC.breakSubstring (B64.encode a1iv) a1
+            newIv = B64.encode (B.tail a1iv)
+        fst (Jwe.rsaDecode blinderRNG a1PrivKey (B.concat [fore, newIv, aft])) @?= Left BadSignature
+
+
     context "when using JWE Appendix 2 data" $ do
       let a2Header = defJweHdr {jweAlg = RSA1_5, jweEnc = A128CBC_HS256}
       let aad = B64.encode . encodeHeader $ a2Header
@@ -86,6 +103,21 @@
 
       it "decodes the JWT to the expected header and payload" $
         fst (Jwe.rsaDecode blinderRNG a2PrivKey a2) @?= Right (a2Header, a2Payload)
+
+      it "a truncated CEK returns BadCrypto" $ do
+        let [hdr, _, iv, payload, tag] = BC.split '.' a2
+            (newEk, _) = rsaEncrypt blinderRNG RSA1_5 a2PubKey (B.tail a2cek)
+        fst (Jwe.rsaDecode blinderRNG a2PrivKey (B.intercalate "." [hdr, B64.encode newEk, iv, payload, tag])) @?= Left BadCrypto
+
+      it "a truncated payload returns BadCrypto" $ do
+        let [hdr, ek, iv, payload, tag] = BC.split '.' a2
+            Right ct = B64.decode payload
+        fst (Jwe.rsaDecode blinderRNG a2PrivKey (B.intercalate "." [hdr, ek, iv, B64.encode (B.tail ct), tag])) @?= Left BadCrypto
+
+      it "a truncated IV returns BadSignature" $ do
+        let (fore, aft) = BC.breakSubstring (B64.encode a2iv) a2
+            newIv = B64.encode (B.tail a2iv)
+        fst (Jwe.rsaDecode blinderRNG a2PrivKey (B.concat [fore, newIv, aft])) @?= Left BadSignature
 
     context "when used with quickcheck" $ do
       it "padded msg is always a multiple of 16" $ property $
diff --git a/tests/Tests/JwkSpec.hs b/tests/Tests/JwkSpec.hs
--- a/tests/Tests/JwkSpec.hs
+++ b/tests/Tests/JwkSpec.hs
@@ -11,7 +11,7 @@
 import Crypto.Types.PubKey.ECDSA
 import Crypto.Types.PubKey.ECC
 
-import Jose.Jwt (defJwsHdr, JwsHeader(..))
+import Jose.Jwt (defJwsHdr, JwsHeader(..), KeyId(..))
 import Jose.Jwk
 import Jose.Jwa
 
@@ -26,9 +26,9 @@
         , {"use": "enc", "crv": "P-256", "kty": "EC", "y": "zcOqE_LYsPTf7a9FOFpJiwK2ZQuUmoNLdsY7BRTICN0", "x": "6eXHDpNoiUaAR5Cle6rfmrVgksSagyi8fzvLF1kedKc", "kid": "a3"}
         , {"kty": "oct", "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow", "kid":"HMAC key used in JWS A.1 example"}
         , {"kty":"EC", "crv":"P-256", "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", "use":"enc", "kid":"1"}
-        , {"kty":"RSA", "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", "e":"AQAB", "alg":"RS256", "kid":"2011-04-29"}
+        , {"kty":"RSA", "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", "e":"AQAB", "alg":"RS256", "kid":"2015-05-16T18:00:14.259Z"}
         , {"kty":"EC", "crv":"P-256", "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", "d":"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE", "use":"enc", "kid":"1"}
-        , {"kty":"RSA", "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", "e":"AQAB", "d":"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q", "p":"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs", "q":"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk", "dp":"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0", "dq":"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk", "qi":"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU", "alg":"RS256", "kid":"2011-04-29"}
+        , {"kty":"RSA", "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", "e":"AQAB", "d":"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q", "p":"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs", "q":"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk", "dp":"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0", "dq":"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk", "qi":"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU", "alg":"RS256", "kid":"2015-05-16T18:00:14.259Z"}
         ]
    }
 |]
@@ -37,7 +37,7 @@
 spec :: Spec
 spec = do
     let Success s@(JwkSet _) = fromJSON (Object keySet) :: Result JwkSet
-    describe "JWK encoding and decoding" $ do
+    describe "JWK encoding and decoding" $
         it "decodes and encodes an entire key set successfully" $ do
             let Just s' = decode' (encode s) :: Maybe JwkSet
                 kss = keys s'
@@ -50,17 +50,18 @@
                 RsaPublicJwk  _ key6Id Nothing    a6   = kss !! 6
                 EcPrivateJwk  _ key7Id (Just Enc) _ _  = kss !! 7
                 RsaPrivateJwk _ _      Nothing    a8   = kss !! 8
+                Success utcKeyId = fromJSON (String "2015-05-16T18:00:14.259Z")
             length kss @?= 9
             a0      @?= Nothing
-            key0Id  @?= Just "a0"
-            key1Id  @?= Just "a1"
-            key2Id  @?= Just "a2"
+            key0Id  @?= Just (KeyId "a0")
+            key1Id  @?= Just (KeyId "a1")
+            key2Id  @?= Just (KeyId "a2")
             public_curve k @?= getCurveByName SEC_p256r1
-            key3Id  @?= Just "a3"
-            key4Id  @?= Just "HMAC key used in JWS A.1 example"
-            key5Id  @?= Just "1"
-            key6Id  @?= Just "2011-04-29"
-            key7Id  @?= Just "1"
+            key3Id  @?= Just (KeyId "a3")
+            key4Id  @?= Just (KeyId "HMAC key used in JWS A.1 example")
+            key5Id  @?= Just (KeyId "1")
+            key6Id  @?= Just (UTCKeyId utcKeyId)
+            key7Id  @?= Just (KeyId "1")
             key0Use @?= Just Enc
             key1Use @?= Just Sig
             key2Use @?= Just Sig
@@ -81,7 +82,7 @@
             length jwks' @?= 3
 
         it "finds one key for RS256 decoding with kid specified" $ do
-            let jwks' = filter (canDecodeJws (defJwsHdr {jwsAlg = RS256, jwsKid = Just "a1"})) jwks
+            let jwks' = filter (canDecodeJws (defJwsHdr {jwsAlg = RS256, jwsKid = Just (KeyId "a1")})) jwks
             length jwks' @?= 1
 
         it "finds an RS1_5 key for encoding" $ do
