diff --git a/lib/keysigner/ca.js b/lib/keysigner/ca.js
index 5ae54a7dbfa5fe60e954fb87b05236851a141098..0336f68b33071711b131987384a7164b14844231 100644
--- a/lib/keysigner/ca.js
+++ b/lib/keysigner/ca.js
@@ -70,7 +70,7 @@ function parseCert(serializedCert) {
 function certify(email, publicKey, expiration) {
   if (expiration == null)
     throw "expiration cannot be null";
-  return new jwcert.JWCert(HOSTNAME, expiration, publicKey, {email: email}).sign(secret_key);
+  return new jwcert.JWCert(HOSTNAME, expiration, new Date(), publicKey, {email: email}).sign(secret_key);
 }
 
 function verifyChain(certChain, cb) {
diff --git a/package.json b/package.json
index 3df8ca188ec77fd8450c0d7e7100eca184b61547..38c351802eeb1a2e0d9631a0fc9bf4516d09358c 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,7 @@
     , "colors" : "0.5.0"
     , "sax" : "0.2.3"
     , "mimelib-noiconv" : "0.1.3"
-    , "jwcrypto": "https://github.com/mozilla/jwcrypto/tarball/d29c6feae538b23f3"
+    , "jwcrypto": "https://github.com/mozilla/jwcrypto/tarball/b63362"
     , "postprocess": "0.0.3"
     , "urlparse": "0.0.1"
   }
diff --git a/resources/static/shared/user.js b/resources/static/shared/user.js
index 9cf2ff1b603ae63b8e4b3f40bc10f2f39ce1bcab..fa362732edbda0cb5493509ae39dd5ecea55a78e 100644
--- a/resources/static/shared/user.js
+++ b/resources/static/shared/user.js
@@ -55,72 +55,65 @@ BrowserID.User = (function() {
   "use strict";
   // remove identities that are no longer valid
   function cleanupIdentities(cb) {
-    network.domainKeyCreationTime(function(creationTime) {
-      // Determine if a certificate is expired.  That will be
-      // if the time it was issued (expiration time minus six hours)
-      // was *before* the domain key was last created.  Also, if the
-      // certificate expires in less that 5 minutes, we consider
-      // it to be expired.
-      //
-      // In human:  If the cert was issued after we changed the
-      // main keypair on the server, then we should reissue a cert
-      function isExpired(cert) {
-        // if it expires in less than 5 minutes, it's too old to use.
-        var diff = cert.expires.valueOf() - new Date().valueOf();
-        if (diff < (60 * 5 * 1000)) {
-          return true;
-        }
-
-        // or if it was issued before the last time the domain key
-        // was updated, it's invalid
-        //
-        // (This must be sync'd with certificate_validity_ms in keysigner configuration.
-        //  It would be better to stamp issue time into certs.)
-        if (cert.expires.valueOf() - creationTime.valueOf() < (24 * 60 * 60 * 1000)) {
-          alert("cert was issued before creationTime");
-          return true;
-        }
+    network.serverTime(function(serverTime) {
+      network.domainKeyCreationTime(function(creationTime) {
+        // Determine if a certificate is expired.  That will be
+        // if it was issued *before* the domain key was last updated or
+        // if the certificate expires in less that 5 minutes from now.
+        function isExpired(cert) {
+          // if it expires in less than 5 minutes, it's too old to use.
+          var diff = cert.expires.valueOf() - serverTime.valueOf();
+          if (diff < (60 * 5 * 1000)) {
+            return true;
+          }
 
-        return false;
-      }
+          // or if it was issued before the last time the domain key
+          // was updated, it's invalid
+          if (!cert.issued_at || cert.issued_at < creationTime) {
+            return true;
+          }
 
-      var emails = storage.getEmails();
-      var issued_identities = {};
-      prepareDeps();
-      _(emails).each(function(email_obj, email_address) {
-        try {
-          email_obj.pub = jwk.PublicKey.fromSimpleObject(email_obj.pub);
-        } catch (x) {
-          storage.invalidateEmail(email_address);
-          return;
+          return false;
         }
 
-        // no cert? reset
-        if (!email_obj.cert) {
-          storage.invalidateEmail(email_address);
-        } else {
+        var emails = storage.getEmails();
+        var issued_identities = {};
+        prepareDeps();
+        _(emails).each(function(email_obj, email_address) {
           try {
-            // parse the cert
-            var cert = new jwcert.JWCert();
-            cert.parse(emails[email_address].cert);
+            email_obj.pub = jwk.PublicKey.fromSimpleObject(email_obj.pub);
+          } catch (x) {
+            storage.invalidateEmail(email_address);
+            return;
+          }
 
-            // check if this certificate is still valid.
-            if (isExpired(cert)) {
+          // no cert? reset
+          if (!email_obj.cert) {
+            storage.invalidateEmail(email_address);
+          } else {
+            try {
+              // parse the cert
+              var cert = new jwcert.JWCert();
+              cert.parse(emails[email_address].cert);
+
+              // check if this certificate is still valid.
+              if (isExpired(cert)) {
+                storage.invalidateEmail(email_address);
+              }
+
+            } catch (e) {
+              // error parsing the certificate!  Maybe it's of an old/different
+              // format?  just delete it.
+              try { console.log("error parsing cert for", email_address ,":", e); } catch(e2) { }
               storage.invalidateEmail(email_address);
             }
-
-          } catch (e) {
-            // error parsing the certificate!  Maybe it's of an old/different
-            // format?  just delete it.
-            try { console.log("error parsing cert for", email_address ,":", e); } catch(e2) { }
-            storage.invalidateEmail(email_address);
           }
-        }
+        });
+        cb();
+      }, function(e) {
+        // we couldn't get domain key creation time!  uh oh.
+        cb();
       });
-      cb();
-    }, function(e) {
-      // we couldn't get domain key creation time!  uh oh.
-      cb();
     });
   }