diff --git a/FirebaseRS256.php b/FirebaseRS256.php
new file mode 100644
index 0000000000000000000000000000000000000000..dfb292ffcd64db955536c1754777a1eb3b2c95a8
--- /dev/null
+++ b/FirebaseRS256.php
@@ -0,0 +1,21 @@
+<?php
+require __DIR__ . '/vendor/autoload.php';
+
+use \Firebase\JWT\JWT;
+
+class FirebaseRS256 {
+    function __construct() {
+        $this->private_key = file_get_contents('private.pem');
+        $this->public_key = file_get_contents('public.pem');
+    }
+
+    function encodeJwt($tokenObj) {
+        return JWT::encode($tokenObj, $this->private_key, 'RS256');
+    }
+
+    function decodeJwt($token) {
+        // Explicitly configured to be vulnerable:
+        // we expect a RS256 signature, but also accept a HS256 signature.
+        return JWT::decode($token, $this->public_key, ['RS256', 'HS256']);
+    }
+}
diff --git a/MishalHS256.php b/MishalHS256.php
new file mode 100644
index 0000000000000000000000000000000000000000..e4f10336f20896ec92ac2673956be26efab4e6f7
--- /dev/null
+++ b/MishalHS256.php
@@ -0,0 +1,23 @@
+<?php
+require __DIR__ . '/vendor/autoload.php';
+
+use Jwt\Jwt;
+use Jwt\Algorithm\NoneAlgorithm;
+use Jwt\Algorithm\HS256Algorithm;
+
+class MishalHS256 {
+    function __construct() {
+        $this->algorithms = [
+            'none' => new NoneAlgorithm(),
+            'HS256' => new HS256Algorithm('secret'),
+        ];
+    }
+
+    function encodeJwt($tokenObj) {
+        return Jwt::encode($tokenObj, $this->algorithms['HS256']);
+    }
+
+    function decodeJwt($token) {
+        return JWT::decode($token, ['algorithm' => array_values($this->algorithms)]);
+    }
+}
diff --git a/base.php b/base.php
index 832db13984d9ae5b50ab3c72ac021096f89b7107..bf919b2833d8aa9d5ec953c9fd01f58cf608463c 100644
--- a/base.php
+++ b/base.php
@@ -3,20 +3,23 @@
 <xmp>
 <?php
 
+require_once __DIR__ . '/common.php';
+
+if (!isset($jwtImpl)) {
+    die();
+}
+
 $token = getToken();
-$algorithms = getAlgorithmKeys();
 
 if ($token) {
     try {
-        printValidJwt(decodeJwt($token));
+        printValidJwt($jwtImpl->decodeJwt($token));
     } catch (Exception $e) {
         printInvalidJwt($e);
     }
 } else {
-    foreach ($algorithms as $name => $keys) {
-        $jwt = encodeJwt(createTokenObject(), $name, $keys);
-        echo "$name: $jwt\n";
-    }
+    $jwt = $jwtImpl->encodeJwt(createTokenObject());
+    echo "JWT: $jwt\n";
 }
 ?>
 </xmp>
diff --git a/common.php b/common.php
index a882e61cd744f57f48508f0b5fb05d45843030d5..7996accb9906d7857c2b897c4476e6a566f20b7d 100644
--- a/common.php
+++ b/common.php
@@ -9,23 +9,6 @@ function getToken() {
     return $auth_header;
 }
 
-function getAlgorithmKeys() {
-    $shared_key = "secret";
-    $private_key = file_get_contents('private.pem');
-    $public_key = file_get_contents('public.pem');
-
-    return [
-        'none' => '',
-        'HS256' => $shared_key,
-        'RS256' => [$private_key, $public_key],
-    ];
-}
-
-function getAlgorithm($jwt) {
-    $header = json_decode(base64_decode(substr($auth_header, 0, strpos($auth_header, '.'))));
-    return $header->alg;
-}
-
 function createTokenObject() {
     return array(
         # Issuer
diff --git a/firebasejwt.php b/firebasejwt.php
deleted file mode 100644
index 43e55f5af1c08cfa24cfa3d1955cae4d9c91a1ee..0000000000000000000000000000000000000000
--- a/firebasejwt.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-require __DIR__ . '/vendor/autoload.php';
-require_once __DIR__ . '/common.php';
-
-use \Firebase\JWT\JWT;
-
-JWT::$leeway = 10; // $leeway in seconds
-
-function encodeJwt($tokenObj, $algorithmName, $keys) {
-    if ($algorithmName == 'none') {
-        return "not supported";
-    }
-
-    $key = $keys;
-    if (is_array($keys)) {
-        $key = $keys[0];
-    }
-    return JWT::encode($tokenObj, $key, $algorithmName);
-}
-
-function decodeJwt($token) {
-    $keys = getAlgorithmKeys();
-    $key = $keys['RS256'][1];
-
-    return JWT::decode($token, $key, array_keys($keys));
-}
-
-include('base.php');
diff --git a/hs256.php b/hs256.php
new file mode 100644
index 0000000000000000000000000000000000000000..a15d53361c24c0f100ee867fe9d1f7d6f70f7098
--- /dev/null
+++ b/hs256.php
@@ -0,0 +1,6 @@
+<?php
+
+require_once 'MishalHS256.php';
+
+$jwtImpl = new MishalHS256();
+include 'base.php';
diff --git a/mishaljwt.php b/mishaljwt.php
deleted file mode 100644
index 2295ef655eeaf2dae1e6ba8c8fac37a4e8d33d5b..0000000000000000000000000000000000000000
--- a/mishaljwt.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-require __DIR__ . '/vendor/autoload.php';
-require __DIR__ . '/common.php';
-
-use Jwt\Jwt;
-use Jwt\Algorithm\NoneAlgorithm;
-use Jwt\Algorithm\HS256Algorithm;
-use Jwt\Algorithm\RS256Algorithm;
-
-function getAlgorithmObjects() {
-    $keys = getAlgorithmKeys();
-
-    $algorithms = [
-        'none' => new NoneAlgorithm(),
-        'HS256' => new HS256Algorithm($keys['HS256']),
-        'RS256' => new RS256Algorithm($keys['RS256'][0], $keys['RS256'][1]),
-    ];
-    return $algorithms;
-}
-
-function decodeJwt($token) {
-    $algorithms = getAlgorithmObjects();
-    return JWT::decode($token, ['algorithm' => array_values($algorithms)]);
-}
-
-function encodeJwt($tokenObj, $algorithmName, $keys) {
-    $algorithms = getAlgorithmObjects();
-    return Jwt::encode($tokenObj, $algorithms[$algorithmName]);
-}
-
-include('base.php');
diff --git a/rs256.php b/rs256.php
new file mode 100644
index 0000000000000000000000000000000000000000..cc76d8fbe8fc05c87b80041aab999c1d7cc4cc35
--- /dev/null
+++ b/rs256.php
@@ -0,0 +1,6 @@
+<?php
+
+require_once 'FirebaseRS256.php';
+
+$jwtImpl = new FirebaseRS256();
+include 'base.php';
diff --git a/sjordjwt.php b/sjordjwt.php
deleted file mode 100644
index e8fff00a670535b6e471582b76d39c12006a3493..0000000000000000000000000000000000000000
--- a/sjordjwt.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-require __DIR__ . '/common.php';
-
-function urlsafeB64Encode($input)
-{
-    return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
-}
-
-function urlsafeB64Decode($input)
-{
-    $remainder = strlen($input) % 4;
-    if ($remainder) {
-        $padlen = 4 - $remainder;
-        $input .= str_repeat('=', $padlen);
-    }
-    return base64_decode(strtr($input, '-_', '+/'));
-}
-
-
-function verifySignature($signature, $message, $algo, $key) {
-    if ($algo == 'HS256') {
-        return $signature == hash_hmac('SHA256', $message, $key, true);
-    } else if ($algo == 'RS256') {
-        return openssl_verify($message, $signature, $key, 'SHA256');
-    } else if ($algo == 'none') {
-        return $signature == '';
-    } else {
-        throw new Exception("Unsupported algorithm $algo");
-    }
-}
-
-function decodeJwt($token) {
-    list($header, $content, $signature) = explode('.', $token);
-    $headerObj = json_decode(urlsafeB64Decode($header));
-    $contentObj = json_decode(urlsafeB64Decode($content));
-
-    $key = file_get_contents('public.pem');
-    if (!verifySignature(urlsafeB64Decode($signature), "$header.$content", $headerObj->alg, $key)) {
-        throw new Exception("Invalid signature");
-    }
-
-    return $contentObj;
-}
-
-function createSignature($message, $algo, $keys) {
-    if ($algo == 'HS256') {
-        return hash_hmac('SHA256', $message, $keys, true);
-    } else if ($algo == 'RS256') {
-        $signature = '';
-        openssl_sign($message, $signature, $keys[0], 'SHA256');
-        return $signature;
-    } else if ($algo == 'none') {
-        return '';
-    } else {
-        throw new Exception("Unsupported algorithm $algo");
-    }
-}
-
-function encodeJwt($tokenObj, $algorithmName, $keys) {
-    $headerObj = ["alg" => $algorithmName, "typ" => "JWT"];
-    $header = urlsafeB64Encode(json_encode($headerObj));
-    $content = urlsafeB64Encode(json_encode($tokenObj));
-    $signature = urlsafeB64Encode(createSignature("$header.$content", $algorithmName, $keys));
-    return "$header.$content.$signature";
-}
-
-include('base.php');