diff --git a/db.py b/db.py
index 72217ad..9ace8fd 100644
--- a/db.py
+++ b/db.py
@@ -6,15 +6,13 @@ from os import path, urandom
 from pylibscrypt import scrypt_mcf, scrypt_mcf_check
 import sqlite3
 import pytoml as toml
-import sendmail
-import smtplib
+from mastodon import Mastodon
 
 
 class DB(object):
     def __init__(self):
         dbfile = path.join(path.dirname(path.abspath(__file__)),
                            'ticketfrei.sqlite')
-        #dbfile = ':memory:'
         self.conn = sqlite3.connect(dbfile)
         self.cur = self.conn.cursor()
         self.cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='user';")
@@ -132,13 +130,6 @@ class DB(object):
             return None
         return User(self, row[0])
 
-    def send_confirmation_mail(self, confirm_link, email):
-        m = sendmail.Mailer(self.config)
-        try:
-            m.send("Complete your registration here: " + confirm_link, email, "[Ticketfrei] Confirm your account")
-        except smtplib.SMTPRecipientsRefused:
-            return "Please enter a valid E-Mail address."
-
     def close(self):
         self.conn.close()
 
@@ -153,6 +144,44 @@ class User(object):
     def state(self):
         return dict(foo='bar')
 
+    def save_request_token(self, token):
+        self.db.cur.execute("INSERT INTO twitter_request_tokens(user_id, request_token) VALUES(?, ?);",
+                            (self.uid, token))
+        self.db.conn.commit()
+
+    def get_request_token(self):
+        self.db.cur.execute("SELECT request_token FROM twitter_request_tokens WHERE user_id = ?;", (id,))
+        request_token = self.db.cur.fetchone()[0]
+        self.db.cur.execute("DELETE FROM twitter_request_tokens WHERE user_id = ?;", (id,))
+        self.db.conn.commit()
+        return request_token
+
+    def save_twitter_token(self, access_token, access_token_secret):
+        self.db.cur.execute(
+            "INSERT INTO twitter_accounts(user_id, access_token_key, access_token_secret) VALUES(?, ?, ?);",
+            (id, access_token, access_token_secret))
+        self.db.conn.commit()
+
+    def get_mastodon_app_keys(self, instance):
+        self.db.cur.execute("SELECT client_id, client_secret FROM mastodon_instances WHERE instance = ?;", (instance, ))
+        try:
+            client_id, client_secret = self.db.cur.fetchone()[0]
+            return client_id, client_secret
+        except TypeError:
+            app_name = "ticketfrei" + str(self.db.secret)[0:4]
+            client_id, client_secret = Mastodon.create_app(app_name, api_base_url=instance)
+            self.db.cur.execute("INSERT INTO mastodon_instances(instance, client_id, client_secret) VALUES(?, ?, ?);",
+                                (instance, client_id, client_secret))
+            self.db.conn.commit()
+            return client_id, client_secret
+
+    def save_masto_token(self, access_token, instance):
+        self.db.cur.execute("SELECT id FROM mastodon_instances WHERE instance = ?;", (instance, ))
+        instance_id = self.db.cur.fetchone()[0]
+        self.db.cur.execute("INSERT INTO mastodon_accounts(user_id, access_token, mastodon_instances_id, active) "
+                            "VALUES(?, ?, ?, ?);", (self.uid, access_token, instance_id, 1))
+        self.db.commit()
+
 
 class DBPlugin(object):
     name = 'DBPlugin'
diff --git a/template/settings.tpl b/template/settings.tpl
index c77ec72..1d34116 100644
--- a/template/settings.tpl
+++ b/template/settings.tpl
@@ -16,6 +16,12 @@
     <h2>Log in with Mastodon</h2>
     <p>
         <form action="/login/mastodon" method='post'>
+            <label for="email">E-Mail of your Mastodon-Account</label>
+            <input type="text" placeholder="Enter Email" name="email" id="email" required>
+
+            <label for="pass">Mastodon Password</label>
+            <input type="password" placeholder="Enter Password" name="pass" id="pass" required>
+
             <label>Mastodon instance:
                 <input type='text' name='instance_url' list='instances' placeholder='social.example.net'/>
             </label>
diff --git a/ticketfrei-web.py b/ticketfrei-web.py
index 5d93371..d176ef3 100644
--- a/ticketfrei-web.py
+++ b/ticketfrei-web.py
@@ -1,6 +1,10 @@
 import bottle
 from bottle import get, post, redirect, request, response, view
 from db import DBPlugin
+import tweepy
+import sendmail
+import smtplib
+from mastodon import Mastodon
 
 
 @get('/')
@@ -8,6 +12,7 @@ from db import DBPlugin
 def propaganda():
     pass
 
+
 @post('/register', db='db')
 @view('template/register.tpl')
 def register_post(db):
@@ -24,6 +29,14 @@ def register_post(db):
     return dict(info='Confirmation mail sent.')
 
 
+def send_confirmation_mail(self, confirm_link, email):
+    m = sendmail.Mailer(self.config)
+    try:
+        m.send("Complete your registration here: " + confirm_link, email, "[Ticketfrei] Confirm your account")
+    except smtplib.SMTPRecipientsRefused:
+        return "Please enter a valid E-Mail address."
+
+
 @get('/confirm/<token>', db='db')
 @view('template/propaganda.tpl')
 def confirm(db, token):
@@ -59,6 +72,7 @@ def api_enable(user):
 def static(filename):
     return bottle.static_file(filename, root='static')
 
+
 @get('/logout/')
 def logout():
     # clear auth cookie
@@ -67,5 +81,62 @@ def logout():
     return redirect('/')
 
 
+@get('/login/twitter', user='user')
+def login_twitter(user):
+    """
+    Starts the twitter OAuth authentication process.
+    :return: redirect to twitter.
+    """
+    consumer_key = user.db.config["tapp"]["consumer_key"]
+    consumer_secret = user.db.config["tapp"]["consumer_secret"]
+    callback_url = bottle.request.get_header('host') + "/login/twitter/callback"
+    auth = tweepy.OAuthHandler(consumer_key, consumer_secret, callback_url)
+    try:
+        redirect_url = auth.get_authorization_url()
+    except tweepy.TweepError:
+        return 'Error! Failed to get request token.'
+    user.save_request_token(auth.request_token)
+    return bottle.redirect(redirect_url)
+
+
+@get('/login/twitter/callback', user="user")
+def twitter_callback(user):
+    """
+    Gets the callback
+    :return:
+    """
+    # twitter passes the verifier/oauth token secret in a GET request.
+    verifier = bottle.request.query('oauth_verifier')
+    consumer_key = user.db.config["tapp"]["consumer_key"]
+    consumer_secret = user.db.config["tapp"]["consumer_secret"]
+    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
+    request_token = user.get_request_token
+    auth.request_token = {"oauth_token": request_token,
+                          "oauth_token_secret": verifier}
+    auth.get_access_token(verifier)
+    user.save_twitter_token(auth.access_token, auth.access_token_secret)
+    return bottle.redirect("/settings")
+
+
+@post('/login/mastodon', user="user")
+def login_mastodon(user):
+    """
+    Starts the mastodon OAuth authentication process.
+    :return: redirect to twitter.
+    """
+    # get app tokens
+    instance_url = bottle.request.forms.get('instance_url')
+    masto_email = bottle.request.forms.get('email')
+    masto_pass = bottle.request.forms.get('password')
+    client_id, client_secret = user.get_mastodon_app_keys(instance_url)
+    m = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=instance_url)
+    try:
+        access_token = m.log_in(masto_email, masto_pass)
+        user.save_masto_token(access_token, instance_url)
+        return dict(info='Thanks for supporting decentralized social networks!')
+    except:
+        return dict(error='Login to Mastodon failed.')
+
+
 bottle.install(DBPlugin('/'))
 bottle.run(host='localhost', port=8080)