diff --git a/templates/layout.html b/templates/layout.html
index 585ea5b..02e1018 100755
--- a/templates/layout.html
+++ b/templates/layout.html
@@ -14,6 +14,8 @@
 <div class="page">
 	<h1>Supysonic</h1>
 
+	<p>{% if session.get('userid') %}<a href="{{ url_for('logout') }}">Log out</a>{% else %}<a href="{{ url_for('login') }}">Log in</a>{% endif %}</p>
+
 	{% if get_flashed_messages() %}
 	<div class="flash">
 		{% for message in get_flashed_messages() %}
diff --git a/templates/login.html b/templates/login.html
new file mode 100755
index 0000000..59ea841
--- /dev/null
+++ b/templates/login.html
@@ -0,0 +1,9 @@
+{% extends "layout.html" %}
+{% block body %}
+<form method="post">
+	<label for="user">User</label><input type="text" id="user" name="user" value="{{ request.form.user }}" /><br />
+	<label for="password">Password</label><input type="password" id="password" name="password" /><br />
+	<input type="submit" />
+</form>
+{% endblock %}
+
diff --git a/user.py b/user.py
index 3182869..1d161b2 100755
--- a/user.py
+++ b/user.py
@@ -1,67 +1,105 @@
-# coding: utf-8
-
-from flask import Flask, request, flash, render_template, redirect, url_for
-import string, random, hashlib
-import uuid
-
-from web import app
-import db
-
-@app.route('/user')
-def user_index():
-	return render_template('users.html', users = db.User.query.all())
-
-@app.route('/user/add', methods = [ 'GET', 'POST' ])
-def add_user():
-	if request.method == 'GET':
-		return render_template('adduser.html')
-
-	error = False
-	(name, passwd, passwd_confirm, mail, admin) = map(request.form.get, [ 'name', 'passwd', 'passwd_confirm', 'mail', 'admin' ])
-	if name in (None, ''):
-		flash('The name is required.')
-		error = True
-	elif db.User.query.filter(db.User.name == name).first():
-		flash('There is already a user with that name. Please pick another one.')
-		error = True
-	if passwd in (None, ''):
-		flash('Please provide a password.')
-		error = True
-	elif passwd != passwd_confirm:
-		flash("The passwords don't match.")
-		error = True
-	if admin is None:
-		admin = True if db.User.query.filter(db.User.admin == True).count() == 0 else False
-	else:
-		admin = True
-	if error:
-		return render_template('adduser.html')
-
-	salt = ''.join(random.choice(string.printable.strip()) for i in xrange(6))
-	crypt = hashlib.sha1(salt + passwd).hexdigest()
-	user = db.User(name = name, mail = mail, password = crypt, salt = salt, admin = admin)
-	db.session.add(user)
-	db.session.commit()
-	flash("User '%s' successfully added" % name)
-
-	return redirect(url_for('index'))
-
-@app.route('/user/del/<id>')
-def del_user(id):
-	try:
-		idid = uuid.UUID(id)
-	except ValueError:
-		flash('Invalid user id')
-		return redirect(url_for('index'))
-
-	user = db.User.query.get(idid)
-	if user is None:
-		flash('No such user')
-		return redirect(url_for('index'))
-
-	db.session.delete(user)
-	db.session.commit()
-	flash("Deleted user '%s'" % user.name)
-
-	return redirect(url_for('index'))
-
+# coding: utf-8
+
+from flask import Flask, request, session, flash, render_template, redirect, url_for
+import string, random, hashlib
+import uuid
+
+from web import app
+import db
+
+@app.route('/user')
+def user_index():
+	return render_template('users.html', users = db.User.query.all())
+
+@app.route('/user/add', methods = [ 'GET', 'POST' ])
+def add_user():
+	if request.method == 'GET':
+		return render_template('adduser.html')
+
+	error = False
+	(name, passwd, passwd_confirm, mail, admin) = map(request.form.get, [ 'name', 'passwd', 'passwd_confirm', 'mail', 'admin' ])
+	if name in (None, ''):
+		flash('The name is required.')
+		error = True
+	elif db.User.query.filter(db.User.name == name).first():
+		flash('There is already a user with that name. Please pick another one.')
+		error = True
+	if passwd in (None, ''):
+		flash('Please provide a password.')
+		error = True
+	elif passwd != passwd_confirm:
+		flash("The passwords don't match.")
+		error = True
+	if admin is None:
+		admin = True if db.User.query.filter(db.User.admin == True).count() == 0 else False
+	else:
+		admin = True
+	if error:
+		return render_template('adduser.html')
+
+	salt = ''.join(random.choice(string.printable.strip()) for i in xrange(6))
+	crypt = hashlib.sha1(salt + passwd).hexdigest()
+	user = db.User(name = name, mail = mail, password = crypt, salt = salt, admin = admin)
+	db.session.add(user)
+	db.session.commit()
+	flash("User '%s' successfully added" % name)
+
+	return redirect(url_for('user_index'))
+
+@app.route('/user/del/<id>')
+def del_user(id):
+	try:
+		idid = uuid.UUID(id)
+	except ValueError:
+		flash('Invalid user id')
+		return redirect(url_for('index'))
+
+	user = db.User.query.get(idid)
+	if user is None:
+		flash('No such user')
+		return redirect(url_for('index'))
+
+	db.session.delete(user)
+	db.session.commit()
+	flash("Deleted user '%s'" % user.name)
+
+	return redirect(url_for('user_index'))
+
+@app.route('/user/login', methods = [ 'GET', 'POST'])
+def login():
+	return_url = request.args.get('returnUrl') or url_for('index')
+	if session.get('userid'):
+		flash('Already logged in')
+		return redirect(return_url)
+
+	if request.method == 'GET':
+		return render_template('login.html')
+
+	user, password = map(request.form.get, [ 'user', 'password' ])
+	error = False
+	if user in ('', None):
+		flash('Missing user name')
+		error = True
+	if password in ('', None):
+		flash('Missing password')
+		error = True
+	if not error:
+		dbuser = db.User.query.filter(db.User.name == user).first()
+		if not dbuser:
+			flash('Unknown user')
+		elif hashlib.sha1(dbuser.salt + password).hexdigest() != dbuser.password:
+			flash('Wrong password')
+		else:
+			session['userid'] = str(dbuser.id)
+			session['admin'] = dbuser.admin
+			flash('Logged in!')
+			return redirect(return_url)
+
+	return render_template('login.html')
+
+@app.route('/user/logout')
+def logout():
+	session.clear()
+	flash('Logged out!')
+	return redirect(url_for('login'))
+
diff --git a/web.py b/web.py
index ca44d05..deee9d8 100755
--- a/web.py
+++ b/web.py
@@ -1,7 +1,6 @@
 # coding: utf-8
 
-from flask import Flask, request, flash, render_template, redirect, url_for
-from sqlalchemy.orm.exc import NoResultFound
+from flask import Flask, request, session, flash, render_template, redirect, url_for
 import os.path
 import uuid
 
@@ -12,14 +11,19 @@ import db
 from scanner import Scanner
 
 @app.before_request
-def init_check():
+def init_and_login_check():
 	if request.path.startswith('/rest/'):
 		return
 
-	if db.User.query.filter(db.User.admin == True).count() == 0 and request.endpoint != 'add_user':
+	admin_count = db.User.query.filter(db.User.admin == True).count()
+	if admin_count == 0 and request.endpoint != 'add_user':
 		flash('Not configured. Please create the first admin user')
 		return redirect(url_for('add_user'))
 
+	if not (admin_count == 0 and request.endpoint == 'add_user') and not session.get('userid') and request.endpoint != 'login':
+		flash('Please login')
+		return redirect(url_for('login', returnUrl = request.url[len(request.url_root)-1:]))
+
 @app.teardown_request
 def teardown(exception):
 	db.session.remove()