diff --git a/login/app.py b/login/app.py
index ac27ff34fda3127563d70d5acaaacdf3ee9c4a33..1ea53adb68590735e544253184dd06d454b956b0 100644
--- a/login/app.py
+++ b/login/app.py
@@ -1,48 +1,111 @@
 
+
+
+import logging
+import os
+import click
+
+
+# Flask
 from flask import abort, Flask, redirect, request, render_template
-from os import urandom, environ
+from flask_sqlalchemy import SQLAlchemy
+from flask_migrate import Migrate
+from flask.cli import AppGroup
+
+from sqlalchemy import select
+from sqlalchemy.orm import Session
+from sqlalchemy import create_engine
 
 # Hydra admin
-from hydra_client import HydraAdmin
 import hydra_client
 
 # Kratos ?
 from kratos import User, KratosError
 from forms import LoginForm
 
-# Flask
-from flask_sqlalchemy import SQLAlchemy
-from flask_migrate import Migrate
-
-import logging
-import os
-
-# Configure Hydra Admin port
-HYDRA_ADMIN_URL = environ['HYDRA_ADMIN_URL']
 
-HYDRA = HydraAdmin(HYDRA_ADMIN_URL)
 
+# Initaliaze the FLASK app
 app = Flask(__name__)
-app.config.from_object(os.environ['APP_SETTINGS'])
-
-app.config['SECRET_KEY'] = urandom(16)
-app.config['HYDRA_ADMIN_URL'] = environ['HYDRA_ADMIN_URL'];
-app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
 
+# Load config
+app.config.from_object(os.environ['APP_SETTINGS'])
 
-app.debug = True if "FLASK_ENV" in environ and environ["FLASK_ENV"] == "development" else False
+# Move to config?
 app.logger.setLevel(logging.INFO)
 
 
+# Creat HYDRA admin interface
+HYDRA_ADMIN_URL = os.environ['HYDRA_ADMIN_URL']
+HYDRA = hydra_client.HydraAdmin(HYDRA_ADMIN_URL)
 
 
+# Create DB interface
 db = SQLAlchemy(app)
+engine = create_engine(app.config["SQLALCHEMY_DATABASE_URI"])
+
+
+# Migrate interface
 migrate = Migrate(app, db)
 
+# Import models
+from models import User, App, AppRole
+
 
-from models import User
+# Import CLI routes
 
 
+# Flask CLI
+user_cli = AppGroup('user')
+app_cli = AppGroup('app')
+
+@app_cli.command('create')
+@click.argument('slug')
+@click.argument('name')
+def create_app(slug, name):
+    app.logger.info("Creating app definition: {1} ({0})".format(slug, name))
+
+    obj = App()
+    obj.name = name
+    obj.slug = slug
+
+    db.session.add(obj)
+    db.session.commit()
+
+@app_cli.command('list')
+def list_app():
+    app.logger.info("Listing apps")
+
+    apps = App.query.all()
+    
+    for obj in apps:
+        print("App name: %s \t Slug: %s" %(obj.name, obj.slug))
+
+
+@app_cli.command('delete',)
+@click.argument('slug')
+def delete_app(slug):
+    app.logger.info("Trying to delete app: {0}".format(slug))
+    obj = App.query.filter_by(slug=slug).first()
+
+    if not obj:
+        app.logger.info("Not found")
+        return
+
+    db.session.delete(obj)
+    db.session.commit()
+    app.logger.info("Success")
+    return
+
+
+app.cli.add_command(app_cli)
+
+
+@user_cli.command('create')
+@click.argument('email')
+def create_user(email):
+    app.logger.info("Creating user: {0}".format(email))
+app.cli.add_command(user_cli)
 
 @app.route('/login', methods=['GET', 'POST'])
 def login():
@@ -63,19 +126,19 @@ def login():
 
     # TODO: Empty/short passwors is a form Error
     challenge = None
-    # Retrieve the challenge id from the request. Depending on the method it is saved in the
-    # form (POST) or in a GET variable.
+
+    # Retrieve the challenge id from the request. Depending on the method it is 
+    # saved in the form (POST) or in a GET variable. If this variable is not set
+    # we can not continue.
     if request.method == 'GET':
         challenge = request.args.get("login_challenge")
-        if not challenge:
-            return abort(400)
-    elif login_form.validate_on_submit():
-        challenge = login_form.challenge.data
-
-
+    if request.method == 'POST':
+        challenge = request.args.post("login_challenge")
+ 
     if not challenge:
         app.logger.error("No challange given. Error in request")
-        abort(401)
+        abort(404)
+
 
     # Now that we have the challenge id, we can request the challenge object from the hydra
     # admin API
@@ -88,6 +151,41 @@ def login():
         app.logger.error("Conflict. Login request has been used already. challenge={0}".format(challenge))
         abort(503)
 
+
+
+    # Skip, if true, let's us know that Hydra has already successfully authenticated
+    # the user. we don't need to check anything and we can accept the request right away.
+    if login_request.skip:
+        app.logger.info("{0} is already logged in. Skip authentication".format(login_request.subject))
+        return redirect(login_request.accept(login_request.subject))
+
+        #skip = request.args.get("skip")
+        #logout = request.args.get("logout")
+        #if skip:
+        #    app.logger.info("{0} is already logged in. Skip authentication".format(login_request.subject))
+        #    return redirect(login_request.accept(login_request.subject))
+        #elif logout:
+        #    login_form.challenge.data = challenge
+        #    HYDRA.invalidate_login_sessions(login_request.subject);
+        #    return redirect(login_request.reject(
+        #        "Login cancelled",
+        #        error_description="Login was cancelled and user session was terminated"))
+        #else:
+        #    return render_template('skip.html', challenge=challenge, logo=login_request.client.logo_uri, application_name=login_request.client.client_name, username=login_request.subject)
+    else:
+      app.logger.info("Not yet logged in. Requesting login credentials")
+
+
+
+
+    if "ory_kratos_session" not in request.cookies:
+      app.logger.info("No kratos cookie, get kratos cookie")
+      kratos = ory_kratos_client.ApiClient(app.config["KRATOS_PUBLIC_URL"])
+        
+
+      login_flow = LoginFlow(app.config["KRATOS_PUBLIC_URL"])
+      return_to = f"{app.config['PUBLIC_URL']}/login?login_challenge={challenge}"
+
     # We need to decide here whether we want to accept or decline the login request.
     # if a login form was submitted, we need to confirm that the userdata, the agent
     # send us via POST is valid
@@ -119,24 +217,6 @@ def login():
             app.logger.info("{0} failed to login".format(user.username))
         return redirect(redirect_to)
 
-    # Skip, if true, let's us know that Hydra has already successfully authenticated
-    # the user. we don't need to check anything and we can accept the request right away.
-    elif login_request.skip:
-        skip = request.args.get("skip")
-        logout = request.args.get("logout")
-        if skip:
-            app.logger.info("{0} is already logged in. Skip authentication".format(login_request.subject))
-            return redirect(login_request.accept(login_request.subject))
-        elif logout:
-            login_form.challenge.data = challenge
-            HYDRA.invalidate_login_sessions(login_request.subject);
-            return redirect(login_request.reject(
-                "Login cancelled",
-                error_description="Login was cancelled and user session was terminated"))
-        else:
-            return render_template('skip.html', challenge=challenge, logo=login_request.client.logo_uri, application_name=login_request.client.client_name, username=login_request.subject)
-
-
 
     # If Skip is not true and the user has not submitted any data via a form, we need
     # to display a login form for the user to type in their username and password.
diff --git a/login/config.py b/login/config.py
index 3231b95e1924e977e4f8ba980092df4530352d6f..a48114b2352f52dd35ad467c31c857664efcf159 100644
--- a/login/config.py
+++ b/login/config.py
@@ -8,8 +8,13 @@ class Config(object):
     DEBUG = False
     TESTING = False
     CSRF_ENABLED = True
-    SECRET_KEY = 'this-really-needs-to-be-changed'
     SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
+    HYDRA_ADMIN_URL = os.environ['HYDRA_ADMIN_URL'];
+    SECRET_KEY = os.urandom(16)
+    SQLALCHEMY_TRACK_MODIFICATIONS = False
+    HYDRA_ADMIN_URL = os.environ['HYDRA_ADMIN_URL']
+
+
 
 
 class ProductionConfig(Config):
diff --git a/login/migrations/versions/051274550b64_add_roles_and_apps.py b/login/migrations/versions/207081778bb2_.py
similarity index 65%
rename from login/migrations/versions/051274550b64_add_roles_and_apps.py
rename to login/migrations/versions/207081778bb2_.py
index e14d294598bb79cfcad746350548950b4fe3f2df..b9e3c65dacac6a91f83fdd0f886194adef2f8f51 100644
--- a/login/migrations/versions/051274550b64_add_roles_and_apps.py
+++ b/login/migrations/versions/207081778bb2_.py
@@ -1,17 +1,17 @@
-"""Add roles and apps
+"""empty message
 
-Revision ID: 051274550b64
-Revises: fc0307250700
-Create Date: 2021-11-15 15:40:04.662936
+Revision ID: 207081778bb2
+Revises: 
+Create Date: 2021-11-16 08:18:27.697307
 
 """
 from alembic import op
 import sqlalchemy as sa
-from sqlalchemy.dialects import postgresql
+
 
 # revision identifiers, used by Alembic.
-revision = '051274550b64'
-down_revision = 'fc0307250700'
+revision = '207081778bb2'
+down_revision = None
 branch_labels = None
 depends_on = None
 
@@ -20,11 +20,16 @@ def upgrade():
     # ### commands auto generated by Alembic - please adjust! ###
     op.create_table('apps',
     sa.Column('id', sa.Integer(), nullable=False),
-    sa.Column('app', sa.String(), nullable=True),
+    sa.Column('name', sa.String(), nullable=True),
     sa.Column('slug', sa.String(), nullable=True),
-    sa.Column('result_all', postgresql.JSON(astext_type=sa.Text()), nullable=True),
-    sa.Column('result_no_stop_words', postgresql.JSON(astext_type=sa.Text()), nullable=True),
-    sa.PrimaryKeyConstraint('id')
+    sa.PrimaryKeyConstraint('id'),
+    sa.UniqueConstraint('slug')
+    )
+    op.create_table('users',
+    sa.Column('id', sa.Integer(), nullable=False),
+    sa.Column('email', sa.String(), nullable=True),
+    sa.PrimaryKeyConstraint('id'),
+    sa.UniqueConstraint('email')
     )
     op.create_table('user_app_roles',
     sa.Column('user_id', sa.Integer(), nullable=False),
@@ -40,5 +45,6 @@ def upgrade():
 def downgrade():
     # ### commands auto generated by Alembic - please adjust! ###
     op.drop_table('user_app_roles')
+    op.drop_table('users')
     op.drop_table('apps')
     # ### end Alembic commands ###
diff --git a/login/migrations/versions/fc0307250700_initial_migration.py b/login/migrations/versions/fc0307250700_initial_migration.py
deleted file mode 100644
index 945e1b5d9c4721387bdaf9c7082389ef715eee10..0000000000000000000000000000000000000000
--- a/login/migrations/versions/fc0307250700_initial_migration.py
+++ /dev/null
@@ -1,34 +0,0 @@
-"""Initial migration.
-
-Revision ID: fc0307250700
-Revises: 
-Create Date: 2021-11-15 15:29:32.420084
-
-"""
-from alembic import op
-import sqlalchemy as sa
-from sqlalchemy.dialects import postgresql
-
-# revision identifiers, used by Alembic.
-revision = 'fc0307250700'
-down_revision = None
-branch_labels = None
-depends_on = None
-
-
-def upgrade():
-    # ### commands auto generated by Alembic - please adjust! ###
-    op.create_table('users',
-    sa.Column('id', sa.Integer(), nullable=False),
-    sa.Column('email', sa.String(), nullable=True),
-    sa.Column('result_all', postgresql.JSON(astext_type=sa.Text()), nullable=True),
-    sa.Column('result_no_stop_words', postgresql.JSON(astext_type=sa.Text()), nullable=True),
-    sa.PrimaryKeyConstraint('id')
-    )
-    # ### end Alembic commands ###
-
-
-def downgrade():
-    # ### commands auto generated by Alembic - please adjust! ###
-    op.drop_table('users')
-    # ### end Alembic commands ###
diff --git a/login/models.py b/login/models.py
index 66cfe5e27971c68891d55462ded89d92981d2f0b..2a898cd5d90b51b8d9d469b8edc7df2c190e7c21 100644
--- a/login/models.py
+++ b/login/models.py
@@ -1,20 +1,19 @@
 
-
 from app import db
 from sqlalchemy.dialects.postgresql import JSON
 
+from sqlalchemy.orm import relationship
+from sqlalchemy import Column, Integer, String, ForeignKey
+
+
+
 class User(db.Model):
     __tablename__ = 'users'
 
-    id = db.Column(db.Integer, primary_key=True)
-    email = db.Column(db.String())
-    result_all = db.Column(JSON)
-    result_no_stop_words = db.Column(JSON)
+    id = db.Column(Integer, primary_key=True)
+    email = db.Column(String, unique=True)
 
-    def __init__(self, email, result_all, result_no_stop_words):
-        self.email = email
-        self.result_all = result_all
-        self.result_no_stop_words = result_no_stop_words
+    app_roles = relationship('AppRole', back_populates="user")
 
     def __repr__(self):
         return '<id {}>'.format(self.id)
@@ -24,17 +23,9 @@ class User(db.Model):
 class App(db.Model):
     __tablename__ = 'apps'
 
-    id = db.Column(db.Integer, primary_key=True)
-    app = db.Column(db.String())
-    slug = db.Column(db.String())
-    result_all = db.Column(JSON)
-    result_no_stop_words = db.Column(JSON)
-
-    def __init__(self, app, slug, result_all, result_no_stop_words):
-        self.app = app
-        self.slug = slug
-        self.result_all = result_all
-        self.result_no_stop_words = result_no_stop_words
+    id = db.Column(Integer, primary_key=True)
+    name = db.Column(String())
+    slug = db.Column(db.String(), unique=True)
 
     def __repr__(self):
         return '<id {}>'.format(self.id)
@@ -43,13 +34,13 @@ class App(db.Model):
 class AppRole(db.Model):
     __tablename__ = 'user_app_roles'
 
-    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
-    user = db.relationship("User", back_populates="app_roles")
+    user_id = db.Column(Integer, ForeignKey('users.id'), primary_key=True)
+    user = relationship("User", back_populates="app_roles")
 
-    app_id = db.Column(db.Integer, db.ForeignKey('apps.id'),
+    app_id = db.Column(Integer, ForeignKey('apps.id'),
                              primary_key=True)
-    app = db.relationship("App")
+    app = relationship("App")
 
-    role = db.Column(db.String())
+    role = db.Column(String)
 
 
diff --git a/login/requirements.txt b/login/requirements.txt
index ebf62f551239743d54257d72a6fc634008da5197..15b4601fff892a432dd06a686e67770f3cb6a813 100644
--- a/login/requirements.txt
+++ b/login/requirements.txt
@@ -6,5 +6,4 @@ Flask-SQLAlchemy
 Flask-Migrate
 Flask-Script
 psycopg2
-bcrypt
-graphqlclient
+ory-kratos-client
diff --git a/login/source_env b/login/source_env
index 323f07c682971ef47d9a3e1abf37010d050953a5..8a03fb801b79e0bccd3cc13d532b1772629ca7b5 100755
--- a/login/source_env
+++ b/login/source_env
@@ -4,5 +4,8 @@
 export FLASK_RUN_HOST=0.0.0.0
 export FLASK_RUN_PORT=5000
 export HYDRA_ADMIN_URL=http://localhost:4445
+export KRATOS_PUBLIC_URL=http://localhost:8080
+export KRATOS_ADMIN_URL=http://localhost:8000
+
 export DATABASE_URL="postgresql://stackspin:stackspin@localhost/stackspin"
 export APP_SETTINGS="config.DevelopmentConfig"