diff --git a/CHANGELOG b/CHANGELOG
index a081cc5077f32cea96152034960618eaec1f13ed..6b24e5b67af029f0e483901a11b63f100e3039ac 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,13 @@
+0.3.8 Apr 4:
+  o Properly raise KeyNotFound exception when looking for keys on
+    nickserver. Fixes #5415.
+  o Do not decode decrypted data, return as str.
+  o Use a better version handler for the gnupg version check.
+  o Memoize call to get_key. Closes #4784.
+  o Update auth to interact with webapp v2. Fixes #5120.
+
+-- 2014 --
+
 0.3.7 Dec 6:
   o Fix error return values on openpgp backend.
   o Remove address check when sending email and rely in the email
diff --git a/changes/VERSION_COMPAT b/changes/VERSION_COMPAT
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cc00ecf758435881eb726f20b30b07c1e061ba96 100644
--- a/changes/VERSION_COMPAT
+++ b/changes/VERSION_COMPAT
@@ -0,0 +1,10 @@
+#################################################
+# This file keeps track of the recent changes
+# introduced in internal leap dependencies.
+# Add your changes here so we can properly update
+# requirements.pip during the release process.
+# (leave header when resetting)
+#################################################
+#
+# BEGIN DEPENDENCY LIST -------------------------
+# leap.foo.bar>=x.y.z
diff --git a/pkg/requirements.pip b/pkg/requirements.pip
index 1515204a2cb81b0e1d3d05701e918ee1024047b6..8dd84bf4c067f750f4a53cb30a16a937540741ee 100644
--- a/pkg/requirements.pip
+++ b/pkg/requirements.pip
@@ -1,4 +1,4 @@
-leap.common>=0.3.0
+leap.common>=0.3.7
 simplejson
 requests
 # if we bump the gnupg version, bump also the sanity check
diff --git a/pkg/tools/with_venvwrapper.sh b/pkg/tools/with_venvwrapper.sh
new file mode 100755
index 0000000000000000000000000000000000000000..26229785c2028fee7a5559a2b7a91199c7246abc
--- /dev/null
+++ b/pkg/tools/with_venvwrapper.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+#Wraps a command in a virtualenwrapper passed as first argument.
+#Example:
+#with_virtualenvwrapper.sh leap-bitmask ./run_tests.sh
+
+wd=`pwd`
+source `which virtualenvwrapper.sh`
+echo "Activating virtualenv " $1
+echo "------------------------------------"
+workon $1
+cd $wd
+echo "running version: " `pyver leap.keymanager`
+echo "soledad version: " `pyver leap.soledad.common`
+$2 $3 $4 $5
diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py
index 6cfbf7102573a12093ae4e2b643de0f3cb75ba6c..41f352ecce902ee06c20bd1e8d6f4c1a81662da1 100644
--- a/src/leap/keymanager/__init__.py
+++ b/src/leap/keymanager/__init__.py
@@ -23,9 +23,9 @@ import sys
 try:
     from gnupg.gnupg import GPGUtilities
     assert(GPGUtilities)  # pyflakes happy
-    from gnupg import __version__
-    from distutils.version import LooseVersion as V
-    assert(V(__version__) >= V('1.2.3'))
+    from gnupg import __version__ as _gnupg_version
+    from pkg_resources import parse_version
+    assert(parse_version(_gnupg_version) >= parse_version('1.2.3'))
 
 except (ImportError, AssertionError):
     print "*******"
@@ -46,6 +46,7 @@ import requests
 from leap.common.check import leap_assert, leap_assert_type
 from leap.common.events import signal
 from leap.common.events import events_pb2 as proto
+from leap.common.decorators import memoized_method
 
 from leap.keymanager.errors import KeyNotFound
 
@@ -76,7 +77,7 @@ class KeyManager(object):
     OPENPGP_KEY = 'openpgp'
     PUBKEY_KEY = "user[public_key]"
 
-    def __init__(self, address, nickserver_uri, soledad, session_id=None,
+    def __init__(self, address, nickserver_uri, soledad, token=None,
                  ca_cert_path=None, api_uri=None, api_version=None, uid=None,
                  gpgbinary=None):
         """
@@ -89,8 +90,8 @@ class KeyManager(object):
         :type url: str
         :param soledad: A Soledad instance for local storage of keys.
         :type soledad: leap.soledad.Soledad
-        :param session_id: The session ID for interacting with the webapp API.
-        :type session_id: str
+        :param token: The token for interacting with the webapp API.
+        :type token: str
         :param ca_cert_path: The path to the CA certificate.
         :type ca_cert_path: str
         :param api_uri: The URI of the webapp API.
@@ -105,7 +106,7 @@ class KeyManager(object):
         self._address = address
         self._nickserver_uri = nickserver_uri
         self._soledad = soledad
-        self._session_id = session_id
+        self._token = token
         self.ca_cert_path = ca_cert_path
         self.api_uri = api_uri
         self.api_version = api_version
@@ -179,11 +180,11 @@ class KeyManager(object):
             self._ca_cert_path is not None,
             'We need the CA certificate path!')
         leap_assert(
-            self._session_id is not None,
-            'We need a session_id to interact with webapp!')
+            self._token is not None,
+            'We need a token to interact with webapp!')
         res = self._fetcher.put(
             uri, data=data, verify=self._ca_cert_path,
-            cookies={'_session_id': self._session_id})
+            headers={'Authorization': 'Token token=%s' % self._token})
         # assert that the response is valid
         res.raise_for_status()
         return res
@@ -196,21 +197,25 @@ class KeyManager(object):
         :param address: The address bound to the keys.
         :type address: str
 
-        @raise KeyNotFound: If the key was not found on nickserver.
+        :raise KeyNotFound: If the key was not found on nickserver.
         """
         # request keys from the nickserver
         res = None
         try:
             res = self._get(self._nickserver_uri, {'address': address})
+            res.raise_for_status()
             server_keys = res.json()
             # insert keys in local database
             if self.OPENPGP_KEY in server_keys:
                 self._wrapper_map[OpenPGPKey].put_ascii_key(
                     server_keys['openpgp'])
+        except requests.exceptions.HTTPError as e:
+            if e.response.status_code == 404:
+                raise KeyNotFound(address)
+            logger.warning("HTTP error retrieving key: %r" % (e,))
+            logger.warning("%s" % (res.content,))
         except Exception as e:
-            logger.warning("Error retrieving the keys: %r" % (e,))
-            if res:
-                logger.warning("%s" % (res.content,))
+            logger.warning("Error retrieving key: %r" % (e,))
 
     #
     # key management
@@ -232,7 +237,7 @@ class KeyManager(object):
         :param ktype: The type of the key.
         :type ktype: KeyType
 
-        @raise KeyNotFound: If the key was not found in local database.
+        :raise KeyNotFound: If the key was not found in local database.
         """
         leap_assert(
             ktype is OpenPGPKey,
@@ -250,6 +255,13 @@ class KeyManager(object):
         self._put(uri, data)
         signal(proto.KEYMANAGER_DONE_UPLOADING_KEYS, self._address)
 
+    @memoized_method
+    def get_key_from_cache(self, *args, **kwargs):
+        """
+        Public interface to `get_key`, that is memoized.
+        """
+        return self.get_key(*args, **kwargs)
+
     def get_key(self, address, ktype, private=False, fetch_remote=True):
         """
         Return a key of type C{ktype} bound to C{address}.
@@ -266,9 +278,10 @@ class KeyManager(object):
 
         :return: A key of type C{ktype} bound to C{address}.
         :rtype: EncryptionKey
-        @raise KeyNotFound: If the key was not found both locally and in
-            keyserver.
+        :raise KeyNotFound: If the key was not found both locally and in
+                            keyserver.
         """
+        logger.debug("getting key for %s" % (address,))
         leap_assert(
             ktype in self._wrapper_map,
             'Unkown key type: %s.' % str(ktype))
@@ -288,7 +301,7 @@ class KeyManager(object):
                 raise
 
             signal(proto.KEYMANAGER_LOOKING_FOR_KEY, address)
-            self._fetch_keys_from_server(address)
+            self._fetch_keys_from_server(address)  # might raise KeyNotFound
             key = self._wrapper_map[ktype].get_key(address, private=False)
             signal(proto.KEYMANAGER_KEY_FOUND, address)
 
@@ -344,14 +357,14 @@ class KeyManager(object):
     # Setters/getters
     #
 
-    def _get_session_id(self):
-        return self._session_id
+    def _get_token(self):
+        return self._token
 
-    def _set_session_id(self, session_id):
-        self._session_id = session_id
+    def _set_token(self, token):
+        self._token = token
 
-    session_id = property(
-        _get_session_id, _set_session_id, doc='The session id.')
+    token = property(
+        _get_token, _set_token, doc='The session token.')
 
     def _get_ca_cert_path(self):
         return self._ca_cert_path
@@ -434,7 +447,7 @@ class KeyManager(object):
         :return: The decrypted data.
         :rtype: str
 
-        @raise InvalidSignature: Raised if unable to verify the signature with
+        :raise InvalidSignature: Raised if unable to verify the signature with
             C{verify} key.
         """
         leap_assert_type(privkey, EncryptionKey)
diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py
index 3a514e143b9593b03a0ea1a1bb135d498adcf402..28fca96821cdba12adcd0952488df16ce99be58e 100644
--- a/src/leap/keymanager/_version.py
+++ b/src/leap/keymanager/_version.py
@@ -17,6 +17,7 @@ git_full = "$Format:%H$"
 import subprocess
 import sys
 
+
 def run_command(args, cwd=None, verbose=False):
     try:
         # remember shell=False, so use git.cmd on windows, not just git
@@ -37,10 +38,10 @@ def run_command(args, cwd=None, verbose=False):
     return stdout
 
 
-import sys
 import re
 import os.path
 
+
 def get_expanded_variables(versionfile_source):
     # the code embedded in _version.py can just fetch the value of these
     # variables. When used from setup.py, we don't want to import
@@ -48,7 +49,7 @@ def get_expanded_variables(versionfile_source):
     # used from _version.py.
     variables = {}
     try:
-        f = open(versionfile_source,"r")
+        f = open(versionfile_source, "r")
         for line in f.readlines():
             if line.strip().startswith("git_refnames ="):
                 mo = re.search(r'=\s*"(.*)"', line)
@@ -63,12 +64,13 @@ def get_expanded_variables(versionfile_source):
         pass
     return variables
 
+
 def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
     refnames = variables["refnames"].strip()
     if refnames.startswith("$Format"):
         if verbose:
             print("variables are unexpanded, not using")
-        return {} # unexpanded, so not in an unpacked git-archive tarball
+        return {}  # unexpanded, so not in an unpacked git-archive tarball
     refs = set([r.strip() for r in refnames.strip("()").split(",")])
     # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
     # just "foo-1.0". If we see a "tag: " prefix, prefer those.
@@ -93,13 +95,14 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
             r = ref[len(tag_prefix):]
             if verbose:
                 print("picking %s" % r)
-            return { "version": r,
-                     "full": variables["full"].strip() }
+            return {"version": r,
+                    "full": variables["full"].strip()}
     # no suitable tags, so we use the full revision id
     if verbose:
         print("no suitable tags, using full revision id")
-    return { "version": variables["full"].strip(),
-             "full": variables["full"].strip() }
+    return {"version": variables["full"].strip(),
+            "full": variables["full"].strip()}
+
 
 def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
     # this runs 'git' from the root of the source tree. That either means
@@ -116,7 +119,7 @@ def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
         here = os.path.abspath(__file__)
     except NameError:
         # some py2exe/bbfreeze/non-CPython implementations don't do __file__
-        return {} # not always correct
+        return {}  # not always correct
 
     # versionfile_source is the relative path from the top of the source tree
     # (where the .git directory might live) to this file. Invert this to find
@@ -141,7 +144,8 @@ def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
         return {}
     if not stdout.startswith(tag_prefix):
         if verbose:
-            print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix))
+            print("tag '%s' doesn't start with prefix '%s'" %
+                  (stdout, tag_prefix))
         return {}
     tag = stdout[len(tag_prefix):]
     stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root)
@@ -153,7 +157,8 @@ def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
     return {"version": tag, "full": full}
 
 
-def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False):
+def versions_from_parentdir(parentdir_prefix, versionfile_source,
+                            verbose=False):
     if IN_LONG_VERSION_PY:
         # We're running from _version.py. If it's from a source tree
         # (execute-in-place), we can work upwards to find the root of the
@@ -163,7 +168,7 @@ def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False)
             here = os.path.abspath(__file__)
         except NameError:
             # py2exe/bbfreeze/non-CPython don't have __file__
-            return {} # without __file__, we have no hope
+            return {}  # without __file__, we have no hope
         # versionfile_source is the relative path from the top of the source
         # tree to _version.py. Invert this to find the root from __file__.
         root = here
@@ -180,7 +185,8 @@ def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False)
     dirname = os.path.basename(root)
     if not dirname.startswith(parentdir_prefix):
         if verbose:
-            print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" %
+            print("guessing rootdir is '%s', but '%s' doesn't start "
+                  "with prefix '%s'" %
                   (root, dirname, parentdir_prefix))
         return None
     return {"version": dirname[len(parentdir_prefix):], "full": ""}
@@ -189,8 +195,9 @@ tag_prefix = ""
 parentdir_prefix = "leap.keymanager-"
 versionfile_source = "src/leap/keymanager/_version.py"
 
+
 def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
-    variables = { "refnames": git_refnames, "full": git_full }
+    variables = {"refnames": git_refnames, "full": git_full}
     ver = versions_from_expanded_variables(variables, tag_prefix, verbose)
     if not ver:
         ver = versions_from_vcs(tag_prefix, versionfile_source, verbose)
@@ -200,4 +207,3 @@ def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
     if not ver:
         ver = default
     return ver
-
diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py
index 856b21e449d63491a03cc6a6f2a8b16a3bc41f6c..950d022c9aa6550ba95c3ece8e43ed0e2ea5c384 100644
--- a/src/leap/keymanager/openpgp.py
+++ b/src/leap/keymanager/openpgp.py
@@ -14,19 +14,13 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
 """
 Infrastructure for using OpenPGP keys in Key Manager.
 """
-
-
-import locale
 import logging
 import os
 import re
 import shutil
-import sys
 import tempfile
 
 from contextlib import closing
@@ -298,7 +292,7 @@ class OpenPGPScheme(EncryptionScheme):
         @raise KeyNotFound: If the key was not found on local storage.
         """
         # Remove the identity suffix after the '+' until the '@'
-        # e.g.: test_user+something@provider.com becomes test_user@probider.com
+        # e.g.: test_user+something@provider.com becomes test_user@provider.com
         # since the key belongs to the identity without the '+' suffix.
         address = re.sub(r'\+.*\@', '@', address)
 
@@ -526,7 +520,7 @@ class OpenPGPScheme(EncryptionScheme):
                 return result.data
             except errors.GPGError as e:
                 logger.error('Failed to decrypt: %s.' % str(e))
-                raise error.EncryptError()
+                raise errors.EncryptError()
 
     def decrypt(self, data, privkey, passphrase=None, verify=None):
         """
@@ -568,20 +562,11 @@ class OpenPGPScheme(EncryptionScheme):
                             'Failed to verify signature with key %s: %s' %
                             (verify.key_id, result.stderr))
 
-                # XXX: this is the encoding used by gpg module
-                # https://github.com/isislovecruft/python-gnupg/\
-                #   blob/master/gnupg/_meta.py#L121
-                encoding = locale.getpreferredencoding()
-                if encoding is None:
-                    encoding = sys.stdin.encoding
-                if encoding is None:
-                    encoding = 'utf-8'
-                return result.data.decode(encoding, 'replace')
+                return result.data
             except errors.GPGError as e:
                 logger.error('Failed to decrypt: %s.' % str(e))
                 raise errors.DecryptError(str(e))
 
-
     def is_encrypted(self, data):
         """
         Return whether C{data} was asymmetrically encrypted using OpenPGP.
diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py
index 67676e9c0e6f2e33bbea6c4e0449a84c75875035..e2558e457e0e3487ab1b3a2fff155d552fddd91f 100644
--- a/src/leap/keymanager/tests/test_keymanager.py
+++ b/src/leap/keymanager/tests/test_keymanager.py
@@ -118,9 +118,21 @@ class KeyManagerWithSoledadTestCase(BaseLeapTest):
         Soledad._get_secrets_from_shared_db = Mock(return_value=None)
         Soledad._put_secrets_in_shared_db = Mock(return_value=None)
 
+        class MockSharedDB(object):
+
+            get_doc = Mock(return_value=None)
+            put_doc = Mock()
+            lock = Mock(return_value=('atoken', 300))
+            unlock = Mock(return_value=True)
+
+            def __call__(self):
+                return self
+
+        Soledad._shared_db = MockSharedDB()
+
         self._soledad = Soledad(
-            "leap@leap.se",
-            "123456",
+            u"leap@leap.se",
+            u"123456",
             secrets_path=self.tempdir + "/secret.gpg",
             local_db_path=self.tempdir + "/soledad.u1db",
             server_url='',
diff --git a/versioneer.py b/versioneer.py
index 34e48073fef7a33bef0e4af12e49794a67cb0a04..4e2c0a556ca0b1d4fa90d47f44e35e35e664fcc9 100644
--- a/versioneer.py
+++ b/versioneer.py
@@ -115,7 +115,7 @@ import sys
 
 def run_command(args, cwd=None, verbose=False):
     try:
-        # remember shell=False, so use git.cmd on windows, not just git
+        # remember shell=False, so use git.exe on windows, not just git
         p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd)
     except EnvironmentError:
         e = sys.exc_info()[1]
@@ -230,7 +230,7 @@ def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
 
     GIT = "git"
     if sys.platform == "win32":
-        GIT = "git.cmd"
+        GIT = "git.exe"
     stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"],
                          cwd=root)
     if stdout is None:
@@ -305,7 +305,7 @@ import sys
 
 def run_command(args, cwd=None, verbose=False):
     try:
-        # remember shell=False, so use git.cmd on windows, not just git
+        # remember shell=False, so use git.exe on windows, not just git
         p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd)
     except EnvironmentError:
         e = sys.exc_info()[1]
@@ -420,7 +420,7 @@ def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
 
     GIT = "git"
     if sys.platform == "win32":
-        GIT = "git.cmd"
+        GIT = "git.exe"
     stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"],
                          cwd=root)
     if stdout is None:
@@ -476,7 +476,7 @@ import sys
 def do_vcs_install(versionfile_source, ipy):
     GIT = "git"
     if sys.platform == "win32":
-        GIT = "git.cmd"
+        GIT = "git.exe"
     run_command([GIT, "add", "versioneer.py"])
     run_command([GIT, "add", versionfile_source])
     run_command([GIT, "add", ipy])
@@ -489,13 +489,13 @@ def do_vcs_install(versionfile_source, ipy):
                     present = True
         f.close()
     except EnvironmentError:
-        pass    
+        pass
     if not present:
         f = open(".gitattributes", "a+")
         f.write("%s export-subst\n" % versionfile_source)
         f.close()
         run_command([GIT, "add", ".gitattributes"])
-    
+
 
 SHORT_VERSION_PY = """
 # This file was generated by 'versioneer.py' (0.7+) from