diff --git a/README.md b/README.md
index 3b804be90160f927d672681c2ee2fe2f81f67465..46b660453d4bff9ae9fa6dbd20add34ab0c3f1b9 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,31 @@ facilitates effective collaboration.
 
 ## Getting Started
 
+You can test out our web application at https://ryoko-planning.herokuapp.com/.
+
+### Simple deployment
+
+If you have [yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/) installed it is possible
+to build and start the complete project the same way it is deployed on our server.
+For this simply enter the root directory of the repository and execute the following three command in order:
+
+1. `yarn install` (or `npm install`) This will install all the dependencies for both the frontend and backend
+2. `yarn build` (or `npm run build`) This will bundle the source for the frontend and transpile backend
+3. `yarn start` (or `npm run start`) This will start the web server and host the webserver at `localhost:8000`
+
+Note:
+ * The server can use a public and private key pair to sign the authentication web token. They can
+either be placed into the directory `server/keys/` with the name `cert.pem` (public key) and
+`cert.key` (private key), or they can be given using the `JWT_PUBLIC_KEY` and `JWT_PRIVATE_KEY`
+envirenvironment variables. In any case the keys must be suitable for ES384 signatures. If these
+keys are not given it will use a simple password to sign the tokens.
+ * If your `PORT` environment variable is set that will be used as the port to host the webserver in stead of port 8000.
+ * If your `NODE_ENV` environment variable is set to `production` (with SSL) or `staging` (without SSL) the server will try
+to connect to a postgres database using the connection url inside `DATABASE_URL` or
+`postgresql://postgres@localhost/ryoko` if no such variable is present in the environment.
+
+### Details
+
 The source code for the repository is split into two parts. The backend code can be found inside the
 `server` directory while the frontend code can be found inside the `client` directory. Both parts
 are managed using the `yarn` package manager, but can also be used with `npm` if necessary. The
@@ -24,19 +49,19 @@ server and client parts also use the same commands for running building and test
 Before building or running you will have to make sure that you have installed all dependencies. This
 can be done by executing `yarn install` (or `npm install --legacy-peer-deps`).
 
-### How to Run
+#### How to Run
 
 To start a development server you can execute `yarn start` (or `npm run start`) inside the `server`
 and the `client` directories. Most parts of the client will also require the server to be running
 simultaneously.
 
-### How to Build
+#### How to Build
 
 To build a production build enter the respective directory (either `server` or `client`) and execute
 `yarn build` (or `npm run build`). The build output will be created inside a directory named `build`
 and can then be executed using node for the server, or served staticaly for the client.
 
-### How to Use
+#### How to Use
 
 After starting the development server inside `client`, the website is accessible at
 `http://localhost:3000`. Depending on your configuration the site will probably be opened
diff --git a/client/src/adapters/auth.ts b/client/src/adapters/auth.ts
index 5dbde550cd0b01b26df3a6c66138459de4641edc..48198a66d066bf82d844922c4e9f870d20a4e540 100644
--- a/client/src/adapters/auth.ts
+++ b/client/src/adapters/auth.ts
@@ -37,7 +37,7 @@ async function extendAccessToken() {
             if (response.ok) {
                 const json = await response.json();
                 setToken(json.token);
-            } else if (response.status === 403) {
+            } else {
                 clearToken();
             }
         } catch(e) {
diff --git a/client/src/config.ts b/client/src/config.ts
index 38c8d39c67e67d3c160d59ad6e398406abdeb632..f7959fd9c4c74fbb54ca2116f8e95c33efdcde17 100644
--- a/client/src/config.ts
+++ b/client/src/config.ts
@@ -1,3 +1,9 @@
 
-export const apiRoot = `${window.location.origin}/v1`;
+export let apiRoot: string;
+
+if (process.env.NODE_ENV === 'production') {
+    apiRoot = `${window.location.origin}/v1`;
+} else {
+    apiRoot = `http://localhost:8000/v1`;
+}
 
diff --git a/package.json b/package.json
index 6110cb38b7413587b3c6d04d21fed959b2030b1f..2fae40f02450536b716f81a05dbee0f0a6910b6e 100644
--- a/package.json
+++ b/package.json
@@ -8,12 +8,14 @@
     "private": true,
     "main": "server/build.js",
     "scripts": {
-        "install": "cd server && yarn install --production=false && cd ../client && yarn install --production=false", 
+        "install": "cd server && yarn install --production=false && cd ../client && yarn install --production=false",
         "build": "cd server && yarn build && cd ../client && yarn build",
         "start": "cd server && node build/index.js"
     },
-    "keywords": [ ],
-    "dependencies": { },
+    "keywords": [],
+    "dependencies": {
+        "yarn": "^1.22.10"
+    },
     "engines": {
         "node": "16.x"
     }
diff --git a/server/src/config.ts b/server/src/config.ts
index 26fd98f447e9cad3fdbf8db5d0fd6c5346e72246..0e758a19ab66213d1c2dcf892ac34c82b22d2270 100644
--- a/server/src/config.ts
+++ b/server/src/config.ts
@@ -6,6 +6,7 @@ export const port = env.PORT ?? 8000;
 export const keys = {
     private: './keys/cert.key',
     public: './keys/cert.pem',
+    secret: 'SECRET',
 };
 
 export const allowedOrigins = [ "*" ];
diff --git a/server/src/keys.ts b/server/src/keys.ts
index 96e0edfb50554afd9e5333c1dfafd2dd19e66ee3..0c28f6b51e3190b2318398d6bbcfd7f37e660ee0 100644
--- a/server/src/keys.ts
+++ b/server/src/keys.ts
@@ -3,6 +3,25 @@ import { readFileBuffer } from './util';
 import { env } from 'process';
 import { keys } from './config';
 
+let hasKeys: boolean | null = null;
+
+export async function usePublicAndPrivate(): Promise<boolean> {
+    if (hasKeys === null) {
+        try {
+            await getPrivateKey();
+            await getPublicKey();
+            hasKeys = true;
+        } catch(e) {
+            hasKeys = false;
+        }
+    }
+    return hasKeys;
+}
+
+export function getSecret(): string {
+    return keys.secret;
+}
+
 let privateKey: string;
 
 export async function getPrivateKey(): Promise<string> {
diff --git a/server/src/knexconfig.ts b/server/src/knexconfig.ts
index 7f5a5030b168e6ef2bc5c57aac571a7073005cbe..66f12382c2c193d850168b9caeeded6e57a46b0d 100644
--- a/server/src/knexconfig.ts
+++ b/server/src/knexconfig.ts
@@ -3,7 +3,7 @@ import { env } from 'process';
 import { join } from 'path';
 import { parse } from 'pg-connection-string';
 
-const pgconfig: any = parse(env.DATABASE_URL ?? '');
+const pgconfig: any = parse(env.DATABASE_URL ?? 'postgresql://postgres@localhost/ryoko');
 
 export default {
     development: {
diff --git a/server/src/v1/auth.ts b/server/src/v1/auth.ts
index eb667d293338fd973919b0371344f54cd757e519..4bf740090e69f352b962e8cf7d36a714439aa530 100644
--- a/server/src/v1/auth.ts
+++ b/server/src/v1/auth.ts
@@ -6,7 +6,7 @@ import { sign, verify } from 'jsonwebtoken';
 
 import database from '../database';
 import { isOfType, asyncify } from '../util';
-import { getPublicKey, getPrivateKey } from '../keys';
+import { getPublicKey, getPrivateKey, getSecret, usePublicAndPrivate } from '../keys';
 
 const auth = express();
 
@@ -31,9 +31,21 @@ export async function tokenVerification(req: Request, _res: Response, next: Next
     if (token) {
         delete req.body.token;
         try {
-            const decoded = await asyncify(verify, token, await getPublicKey(), { algorithms: ["ES384"] });
+            let decoded;
+            if (await usePublicAndPrivate()) {
+                decoded = await asyncify(verify, token, await getPublicKey(), { algorithms: ["ES384"] });
+            } else {
+                decoded = await asyncify(verify, token, getSecret(), { algorithms: ["HS384"] });
+            }
             if (isOfType<Token>(decoded, [['id', 'string'], ['type', 'string']]) && decoded.type === authTokenType) {
-                req.body.token = decoded;
+                const user = await database('users')
+                    .select({ id: 'users.id' })
+                    .where({
+                        'users.id': decoded.id,
+                    });
+                if (user.length >= 1) {
+                    req.body.token = decoded;
+                }
             }
         } catch (err) { /* Token has already been deleted */ }
         next();
@@ -58,7 +70,11 @@ async function generateAuthToken(id: string) {
         id: id,
         type: authTokenType,
     };
-    return asyncify(sign, token, await getPrivateKey(), { algorithm: "ES384", expiresIn: 60 * 60 });
+    if (await usePublicAndPrivate()) {
+        return asyncify(sign, token, await getPrivateKey(), { algorithm: "ES384", expiresIn: 60 * 60 });
+    } else {
+        return asyncify(sign, token, getSecret(), { algorithm: "HS384", expiresIn: 60 * 60 });
+    }
 }
 
 interface RegisterBody {
diff --git a/yarn.lock b/yarn.lock
index fb57ccd13afbd082ad82051c2ffebef4840661ec..3bc13344a6f769c244ea0c2cb346d6e876039a6b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,3 +2,7 @@
 # yarn lockfile v1
 
 
+yarn@^1.22.10:
+  version "1.22.10"
+  resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.10.tgz#c99daa06257c80f8fa2c3f1490724e394c26b18c"
+  integrity sha512-IanQGI9RRPAN87VGTF7zs2uxkSyQSrSPsju0COgbsKQOOXr5LtcVPeyXWgwVa0ywG3d8dg6kSYKGBuYK021qeA==