diff --git a/frontend/js/apicalls.js b/frontend/js/apicalls.js
index bd9c42b867b059d12d894b3409ab366a9d0e1bcf..d03b0a878903e168803893cbe7982c6bd33ceb81 100644
--- a/frontend/js/apicalls.js
+++ b/frontend/js/apicalls.js
@@ -1,8 +1,32 @@
 // This file contains the api calls, as well as transform the data into html-text
-
 var apiUrl = "http://zam024.fritz.box/api/"; // TODO switch out with real url, ideally during deployment
 var allowedTypesList = [];
 
+// get data from url query variables
+function getUrlVars()
+{
+    var vars = [], hash;
+    var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
+    for(var i = 0; i < hashes.length; i++)
+    {
+        hash = hashes[i].split('=');
+        vars.push(hash[0]);
+        vars[hash[0]] = hash[1];
+    }
+    return vars;
+}
+
+// return the storage type
+function getType() {
+    var type = getUrlVars()["type"]
+    return type
+}
+
+// set the text of the typetext element 
+function setTypeText() {
+    $('#typetext').text(getType())
+}
+
 // return the dataset id
 function getId() {
     var id = getUrlVars()["oid"];
@@ -25,8 +49,28 @@ get html for table entry with a proeprty
 The value field is editable, but the edit is blocked by default
 authenticated users should be able to edit and submit
 */ 
-function getPropertyHTMLString(property, value) {
-    return '<tr><th scope="row">' + property + '</th><td><input class="form-control" type="text" value="' + value + '" readonly></td></tr>';
+function getPropertyHTMLString(property, value, readonly=true) {
+    return '<tr><th scope="row">' + property + '</th><td><input class="form-control" type="text" value="' + value + (readonly ? '" readonly' : '"') + '></td></tr>';
+}
+
+/*
+* Fill given table with data from given dataset
+* if readonly is false, make all but OID editable
+* else everything is readonly
+*/
+function fillDatasetTable(table, dataset, readonly=faltruese) {
+    // now append name and url to the view
+    table.append(getPropertyHTMLString('Name', dataset.name, readonly));
+    table.append(getPropertyHTMLString('OID', getId()));
+    table.append(getPropertyHTMLString('URL', dataset.url, readonly));
+
+    // insert a linebreak that announces other metadata
+    table.append('<tr><th class="info" scope="row" colspan="2">Other Metadata</th></tr>');
+
+    // iterate over metadata map and add additional properties
+    for (const [key, val] of Object.entries(dataset.metadata)) {
+        table.append(getPropertyHTMLString(key, val, editable));
+    }
 }
 
 // XMLHttpRequest EVENTLISTENER: if a dropdown-menu (a <ul> element) with the dropdownOptions id is present, update it with the available types
@@ -54,6 +98,15 @@ function setDatasetList() {
     });
 }
 
+// XMLHttpRequest EVENTLISTENER: show banner with new dataset id
+function showNewDatasetID() {
+    console.log("POST " + this.responseUrl + ": " + this.responseText);
+    var data = JSON.parse(this.responseText);
+    var id = data[0];
+    var alertHTML = '<div class="alert alert-success" role="alert">Dataset created! OID is: <a href="?type=' + getType() + '&oid=' + id + '">' + id + '</a></div>';
+    $('#storageTypeChooser').after(alertHTML);
+}
+
 // XMLHttpRequest EVENTLISTENER: show dataset in table
 function setDatasetView() {
     console.log("GET " + this.responseUrl + ": " + this.responseText);
@@ -68,19 +121,11 @@ function setDatasetView() {
     $('#datasetListTable').hide();
     $('#storageTypeChooser').hide();
     $('#datasetViewTable').show();
-
-    // now append name and url to the view
-    $('#datasetViewTableBody').append(getPropertyHTMLString('Name', dataset.name));
-    $('#datasetViewTableBody').append(getPropertyHTMLString('OID', getId()));
-    $('#datasetViewTableBody').append(getPropertyHTMLString('URL', dataset.url));
-    
-    // insert a linebreak that announces other metadata
-    $('#datasetViewTableBody').append('<tr><th class="info" scope="row" colspan="2">Other Metadata</th></tr>');
-
-    // iterate over metadata map and add additional properties
-    for (const [key, val] of Object.entries(dataset.metadata)) {
-        $('#datasetViewTableBody').append(getPropertyHTMLString(key, val));
+    if (window.sessionStorage.auth_token) {
+        $('#modifyDatasetButtonGroup').show();
     }
+
+    fillDatasetTable($('#datasetViewTableBody'), dataset, true);
 }
 
 // get available types from api, put them in the relevant dropdown (via listener)
@@ -125,13 +170,32 @@ async function showListingOrSingleDataset() {
         window.location.href = "?type=" + allowedTypesList[0];
     }
     if (!getId()) { // no id given, so list all elements
+        if (window.sessionStorage.auth_token) {
+            $('#addNewDatasetButton').show();
+        }
         listDatasets(getType());
+    } else if (getId() == "new") {
+        alert ("Do stuff for new dataset i.e. edit datset with empty oid");
     } else { // an id is given, show the dataset, error message if invalid
         showDataset(getType(), getId());
     }
 }
 
 
-// TODO function(s) to POST new Dataset (get bearer token from auth.js)
-// TODO function(s) to PUT existing Dataset (get bearer token from auth.js)
-// TODO function(s) to DELETE existing Dataset (get bearer token from auth.js)
\ No newline at end of file
+// POST new Dataset (get bearer token from session storage)
+function createNewDataset(datatype, name, url, metadata) {
+    var dataset = {"name" : name, "url" : url, "metadata" : metadata};
+    var fullUrl = apiUrl + datatype;
+    console.log("Full url for creating new dataset is " + fullUrl)
+    console.log("New Dataset is " + dataset)
+    var xmlhttp = new XMLHttpRequest();
+    xmlhttp.addEventListener("loadend", showNewDatasetID);
+    xmlhttp.open("POST", fullUrl);
+    xmlhttp.setRequestHeader('Authorization', 'Bearer ' + window.sessionStorage.auth_token);
+    xmlhttp.setRequestHeader('Content-Type', 'application/json');
+    xmlhttp.send(JSON.stringify(dataset));
+    // TODO disable all buttons, put a spinner on save
+}
+
+// TODO function(s) to PUT existing Dataset (get bearer token from session storage)
+// TODO function(s) to DELETE existing Dataset (get bearer token from session storage)
\ No newline at end of file
diff --git a/frontend/js/auth.js b/frontend/js/auth.js
index 8c6ff1b57a572685ece77fed7557bc99aae1d11a..07fa1855328550d420b8f7f9b57f4d918153c9e5 100644
--- a/frontend/js/auth.js
+++ b/frontend/js/auth.js
@@ -1,16 +1,120 @@
 // This file will contain functions to manage authentication (including the token storage and access)
 
-// TODO function to rewrite Login as logout
-// TODO function to add "ME" option to navbar (maybe add both and hide as needed)
+// TODO function to rewrite Login as username
 
-// TODO function(s) to post to receive and store bearer token
+/************************************************
+ * Event Listeners for XMLHttpRequests
+ ************************************************/
+
+// XMLHttpRequest EVENTLISTENER: if the call was successful, store the token locally and reload login page
+function setLoginToken() {
+    console.log("POST " + this.responseUrl + ": " + this.responseText);
+    if (this.status >= 400) {
+        alert("The username and/ or the password is invalid!");
+        logout();
+    } else {
+        var tokenData = JSON.parse(this.responseText);
+        window.sessionStorage.auth_token = tokenData.access_token;
+        location.reload();
+    }
+}
+
+// To be called by an inline XMLHttpRequest EVENTLISTENER: if the call was successful, update the userdata
+function setUserdata(data, updateView) {
+    console.log("GET " + data.responseUrl + ": " + data.responseText);
+    if (this.status >= 400) {
+        logout();
+    } else {
+        var userdata = JSON.parse(data.responseText);
+        console.log("Userdata: " + userdata.username + " - " + userdata.email);
+        // store username and email in sessionData (blind overwrite if exists)
+        window.sessionStorage.username = userdata.username;
+        window.sessionStorage.email = userdata.email;
+        if (updateView) {
+            $('#usernameLabel').html(window.sessionStorage.username);
+            $('#emailLabel').html(window.sessionStorage.email);
+        }
+    }
+}
 
 /*
-makes a post call for the token and stores it in localstorage
+* makes a post call for the token and stores it in localstorage
 */
-function login(username, password) {
+function loginPOST(username, password) {
+    var fullUrl = apiUrl + "token";
+    console.log("Full url for token request is " + fullUrl)
+    var xmlhttp = new XMLHttpRequest();
+    xmlhttp.addEventListener("loadend", setLoginToken);
+    xmlhttp.open("POST", fullUrl);
+    xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+    xmlhttp.send("username=" + encodeURIComponent(username) + "&password=" + encodeURIComponent(password));
+}
 
+/**
+* checks the textfields for username and password, gives an error message if not given, then calls the loginPOST(username, password) function 
+*/
+function login() {
+    $('#loginButton').prepend('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>');
+    $('#loginButton').attr("disabled", true);
+    loginPOST($('#usernameField').val(), $('#passwordField').val());
 }
 
-// TODO funciton to call /me
-// TODO function to get bearer token (for external use)
\ No newline at end of file
+
+/*
+* clear sessionStorage of all auth related data and redirect to the login page
+*/
+function logout() {
+    delete window.sessionStorage.auth_token;
+    delete window.sessionStorage.username;
+    delete window.sessionStorage.email;
+    location.reload();
+}
+
+/* 
+* call API/me to get ifo about the user and check if token is valid
+* if updateView is true, also update the username and email fields in the login page (with data from the sessionstorage)
+* The function returns true if the token is valid and the server responded with the desired data
+*/
+function getInfo(updateView=false) {
+    if (window.sessionStorage.auth_token === undefined) {
+        return false;
+    } else {
+        // if updateView, set text to spinners, eventlistener will fill correct values
+        if (updateView) {
+            $('#usernameLabel').append('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>');
+            $('#emailLabel').append('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>');
+        }
+
+        // start GET /me, pass wether an update of the user labels is needed
+        var fullUrl = apiUrl + "me";
+        console.log("Full url for /me request is " + fullUrl)
+        var xmlhttp = new XMLHttpRequest();
+        xmlhttp.open("GET", fullUrl);
+        xmlhttp.setRequestHeader('Authorization', 'Bearer ' + window.sessionStorage.auth_token);
+        xmlhttp.addEventListener("loadend", async function() {
+            setUserdata(this, updateView);
+        });
+        xmlhttp.updateView = updateView;
+        xmlhttp.send();
+        return true; // this true is okay, if the request fails, it will automatically logout and reload anyway
+    }
+}
+
+/*
+* either show the userinfo table (true) or the loginform (false) (if present)
+* also adjust the Log In Navbar element
+* also show edit/ save and addNew Buttons (true) (if present)
+*/
+function showElementsDependingOnLoginStatus(loggedIn = true) {
+    if (loggedIn) {
+        $('#loginForm').hide();
+        $('#userinfoViewer').show();
+        $('#loginOutText').html('Logged In (<b>' + window.sessionStorage.username + '</b>)');
+    } else {
+        $('#userinfoViewer').hide();
+        $('#loginForm').show();
+        $('#loginOutText').text("Log In");
+        $('#modifyDatasetButtonGroup').hide();
+        $('#addNewDatasetButton').hide();
+    }
+}
\ No newline at end of file
diff --git a/frontend/js/choose_storage.js b/frontend/js/choose_storage.js
deleted file mode 100644
index 07784301ed19e18257147ac846556794616a9e15..0000000000000000000000000000000000000000
--- a/frontend/js/choose_storage.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// get data from url query variables
-function getUrlVars()
-{
-    var vars = [], hash;
-    var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
-    for(var i = 0; i < hashes.length; i++)
-    {
-        hash = hashes[i].split('=');
-        vars.push(hash[0]);
-        vars[hash[0]] = hash[1];
-    }
-    return vars;
-}
-
-// return the storage type
-function getType() {
-    var type = getUrlVars()["type"]
-    console.log("Type: " + type)
-    return type
-}
-
-// set the text of the typetext element 
-function setTypeText() {
-    $('#typetext').text(getType())
-}
\ No newline at end of file