diff --git a/tests/models/test_oauth2.py b/tests/models/test_oauth2.py
index 52b66299c2d2e550e70e762e33cc02653b3bed5a..3a2dc85ed091f59a22c579499b035935bb902a39 100644
--- a/tests/models/test_oauth2.py
+++ b/tests/models/test_oauth2.py
@@ -71,6 +71,7 @@ class TestOAuth2Key(UffdTestCase):
 
 	def test_encode_jwt(self):
 		jwtdata = self.key.encode_jwt({'aud': 'test', 'foo': 'bar'})
+		self.assertIsInstance(jwtdata, str) # Regression check for #165
 		self.assertEqual(
 			jwt.get_unverified_header(jwtdata),
 			# typ is optional, x5u/x5c/jku/jwk are discoraged by OIDC Core 1.0 spec section 2
diff --git a/uffd/models/oauth2.py b/uffd/models/oauth2.py
index bdd503872384168982aa823aa85795752381bc94..ded3a2da9077888f6e18d9e37558bb3aa218ada9 100644
--- a/uffd/models/oauth2.py
+++ b/uffd/models/oauth2.py
@@ -243,7 +243,11 @@ class OAuth2Key(db.Model):
 	def encode_jwt(self, payload):
 		if not self.active:
 			raise jwt.exceptions.InvalidKeyError(f'Key {self.id} not active')
-		return jwt.encode(payload, key=self.private_key, algorithm=self.algorithm, headers={'kid': self.id})
+		res = jwt.encode(payload, key=self.private_key, algorithm=self.algorithm, headers={'kid': self.id})
+		# pyjwt pre-v2 compat (Buster/Bullseye)
+		if isinstance(res, bytes):
+			res = res.decode()
+		return res
 
 	# Hash algorithm for at_hash/c_hash from OpenID Connect Core 1.0 section 3.1.3.6
 	def oidc_hash(self, value):