diff --git a/hiboo/__init__.py b/hiboo/__init__.py
index 6fd5692d19fa6cce2f050e8e0787adcd821a30d2..470c7c6b7afa19ceb2abbffc0538537488713bf8 100644
--- a/hiboo/__init__.py
+++ b/hiboo/__init__.py
@@ -30,8 +30,10 @@ def create_app_from_config(config):
         return dict(config=app.config, utils=utils)
 
     # Import views
-    from hiboo import account, service, sso
+    from hiboo import account, user, identity, service, sso
     app.register_blueprint(account.blueprint, url_prefix='/account')
+    app.register_blueprint(user.blueprint, url_prefix='/user')
+    app.register_blueprint(identity.blueprint, url_prefix='/identity')
     app.register_blueprint(service.blueprint, url_prefix='/service')
     app.register_blueprint(sso.blueprint, url_prefix='/sso')
 
diff --git a/hiboo/account/__init__.py b/hiboo/account/__init__.py
index 125e097fed4688a5d9cdcf8ba9feb0ba22a01756..94a5a7de563864608d15580fd5bd2a3bb9342c24 100644
--- a/hiboo/account/__init__.py
+++ b/hiboo/account/__init__.py
@@ -1,6 +1,6 @@
-from flask import Blueprint
+import flask
 
 
-blueprint = Blueprint("account", __name__, template_folder="templates")
+blueprint = flask.Blueprint("account", __name__, template_folder="templates")
 
-from hiboo.account import login, profiles, settings
+from hiboo.account import login, home, settings
diff --git a/hiboo/account/forms.py b/hiboo/account/forms.py
index 26598641c924b510ef18bc68185d616e1f46a20b..141d55fd4a91fff6e66b279049037d7c4bdcb75c 100644
--- a/hiboo/account/forms.py
+++ b/hiboo/account/forms.py
@@ -1,4 +1,4 @@
-from wtforms import validators, fields, widgets
+from wtforms import validators, fields
 from flask_babel import lazy_gettext as _
 
 import flask_wtf
@@ -28,17 +28,3 @@ class PasswordForm(flask_wtf.FlaskForm):
     password2 = fields.PasswordField(_('Confirm new password'),
         [validators.DataRequired(), validators.EqualTo('password')])
     submit = fields.SubmitField(_('Change password'))
-
-
-class ProfileForm(flask_wtf.FlaskForm):
-    username = fields.StringField(_('Username'), [validators.DataRequired()])
-    comment = fields.StringField(_('Comment'))
-    submit = fields.SubmitField(_('Create profile'))
-
-
-class ProfilePickForm(flask_wtf.FlaskForm):
-    profile_uuid = fields.TextField('profile', [])
-
-
-class AvatarForm(flask_wtf.FlaskForm):
-    submit = fields.SubmitField(_('Sign up'), [])
diff --git a/hiboo/account/home.py b/hiboo/account/home.py
new file mode 100644
index 0000000000000000000000000000000000000000..822fe98e67428aa1d7b092f2114e91ed56059bae
--- /dev/null
+++ b/hiboo/account/home.py
@@ -0,0 +1,12 @@
+from hiboo.account import blueprint
+from hiboo import security
+
+import flask
+import flask_login
+
+
+@blueprint.route("/home")
+@security.authentication_required()
+def home():
+    history = flask_login.current_user.history
+    return flask.render_template("account_home.html", history=history)
diff --git a/hiboo/account/profiles.py b/hiboo/account/profiles.py
deleted file mode 100644
index a27af3fb732ed6bad0861e7c084daa30faf1b466..0000000000000000000000000000000000000000
--- a/hiboo/account/profiles.py
+++ /dev/null
@@ -1,131 +0,0 @@
-from hiboo.account import blueprint, forms
-from hiboo.sso import forms as sso_forms
-from hiboo import models, utils, security
-
-import flask
-import flask_login
-
-
-def get_profile(service, **redirect_args):
-    form = forms.ProfilePickForm()
-    if form.validate_on_submit():
-        profile = models.Profile.query.get(form.profile_uuid.data)
-        if not (profile.user == flask_login.current_user and
-                profile.service == service and
-                profile.status == models.Profile.ACTIVE):
-            return None
-        return profile
-    next = ("account.pick_avatar" if service.max_profiles == 0
-            else "account.pick_profile")
-    utils.force_redirect(utils.url_for(next, **redirect_args))
-
-
-@blueprint.route("/profile/pick")
-@security.authentication_required()
-def pick_profile():
-    service_uuid = flask.request.args.get("service_uuid") or flask.abort(404)
-    service = models.Service.query.get(service_uuid) or flask.abort(404)
-    profiles = models.Profile.filter(service, flask_login.current_user).all()
-    form = forms.ProfilePickForm()
-    return flask.render_template("profile_pick.html",
-        service=service, profiles=profiles, form=form,
-        action_create=utils.url_for("account.create_profile", intent="account.pick_profile"),
-        action_pick=utils.url_or_intent("account.home"))
-
-
-@blueprint.route("/profile/create", methods=["GET", "POST"])
-@security.authentication_required()
-def create_profile():
-    service_uuid = flask.request.args.get("service_uuid") or flask.abort(404)
-    service = models.Service.query.get(service_uuid) or flask.abort(404)
-    status = models.Profile.ACTIVE
-    profiles = models.Profile.filter(service, flask_login.current_user).all()
-    # Do not create profile for reserved or locked services
-    if service.policy in (models.Service.RESERVED, models.Service.LOCKED):
-        flask.flash("You cannot request a profile for this service", "danger")
-        return flask.redirect(flask.url_for("account.home"))
-    # Only burst services are allowed to exceed profile count
-    elif len(profiles) >= service.max_profiles and service.policy != models.Service.BURST:
-        flask.flash("Your reached the maximum number of profiles", "danger")
-        return flask.redirect(flask.url_for("account.home"))
-    # Managed services and bursting accounts require approval
-    elif len(profiles) >= service.max_profiles or service.policy == models.Service.MANAGED:
-        flask.flash("Your profile creation requires approval", "warning")
-        status = models.Profile.REQUEST
-    # Actually display the form
-    form = forms.ProfileForm()
-    if form.validate_on_submit():
-        conflict = models.Profile.query.filter_by(
-            service_uuid=service_uuid, username=form.username.data
-        ).first()
-        if conflict:
-            flask.flash("A profile with that username exists already", "danger")
-        else:
-            profile = models.Profile()
-            profile.username = form.username.data
-            profile.user = flask_login.current_user
-            profile.service = service
-            profile.comment = form.comment.data
-            profile.status = status
-            models.db.session.add(profile)
-            models.log(models.History.CREATE, profile.username, profile.comment,
-                user=flask_login.current_user, service=service, profile=profile)
-            models.db.session.commit()
-            return flask.redirect(utils.url_or_intent("account.home"))
-    return flask.render_template("profile_create.html", form=form, service=service)
-
-
-@blueprint.route("/avatar/pick")
-@security.authentication_required()
-def pick_avatar():
-    service_uuid = flask.request.args.get("service_uuid") or flask.abort(404)
-    service = models.Service.query.get(service_uuid) or flask.abort(404)
-    avatar = models.Profile.filter(service, flask_login.current_user).first()
-    form = forms.ProfilePickForm()
-    if avatar:
-        if avatar.status == models.Profile.REQUEST:
-            flask.flash("Your account request is awaiting approval", "warning")
-            return flask.redirect(fflask.url_for("account.home"))
-        elif avatar.status == models.Profile.BLOCKED:
-            flask.flash("You are currently blocked", "danger")
-            return flask.redirect(fflask.url_for("account.home"))
-        elif avatar.status in (models.Profile.DELETED, models.Profile.UNCLAIMED):
-            flask.flash("Your avatar is unavailable", "danger")
-            return flask.redirect(fflask.url_for("account.home"))
-    elif service.policy not in (models.Service.OPEN, models.Service.MANAGED):
-        flask.flash("You cannot access this service", "danger")
-        return flask.redirect(fflask.url_for("account.home"))
-    else:
-        return flask.redirect(utils.url_for("account.create_avatar", intent="account.pick_avatar"))
-    return flask.render_template("avatar_pick.html",
-        service=service, avatar=avatar, form=form,
-        action_pick=utils.url_or_intent("account.home"),
-        action_create=utils.url_for("account.create_avatar", intent="account.pick_avatar"))
-
-
-@blueprint.route("/avatar/create", methods=["GET", "POST"])
-@security.authentication_required()
-def create_avatar():
-    service_uuid = flask.request.args.get("service_uuid") or flask.abort(404)
-    service = models.Service.query.get(service_uuid) or flask.abort(404)
-    # Cannot create an avatar if one exists already
-    existing = models.Profile.filter(service, flask_login.current_user).first()
-    existing and flask.abort(403)
-    # Cannot create an avatar for anything but a managed or open service
-    if service.policy == models.Service.OPEN:
-        status = models.Profile.ACTIVE
-    elif service.policy == models.Service.MANAGED:
-        status = models.Profile.REQUEST
-    else:
-        flask.abort(403)
-    form = forms.AvatarForm()
-    if form.validate_on_submit():
-        avatar = models.Profile()
-        avatar.username = flask_login.current_user.username
-        avatar.user = flask_login.current_user
-        avatar.service = service
-        avatar.status = models.Profile.ACTIVE
-        models.db.session.add(avatar)
-        models.db.session.commit()
-        return flask.redirect(utils.url_or_intent("account.home"))
-    return flask.render_template("avatar_create.html", form=form, service=service)
diff --git a/hiboo/account/settings.py b/hiboo/account/settings.py
index c9fcd271130146ed992bf4afc2212ac7f8897e9d..0680926c825bd72c440834009a555f6d7b101890 100644
--- a/hiboo/account/settings.py
+++ b/hiboo/account/settings.py
@@ -5,13 +5,6 @@ import flask
 import flask_login
 
 
-@blueprint.route("/home")
-@security.authentication_required()
-def home():
-    history = flask_login.current_user.history
-    return flask.render_template("account_home.html", history=history)
-
-
 @blueprint.route("/password", methods=["GET", "POST"])
 @security.authentication_required()
 def password():
diff --git a/hiboo/account/templates/account_home.html b/hiboo/account/templates/account_home.html
index 109482accc079314abc994d805b75da3aea2f328..99223ac5d4596d6f889e952e602a04b911ebbd55 100644
--- a/hiboo/account/templates/account_home.html
+++ b/hiboo/account/templates/account_home.html
@@ -12,7 +12,7 @@
           {{ macros.infobox("Account age", "{} days".format((current_user.created_at.today() - current_user.created_at).total_seconds() // 86400), "aqua", "calendar") }}
         </div>
         <div class="col-md-6 col-xs-12">
-          {{ macros.infobox("Profile count", current_user.profiles.__len__(), "red", "users") }}
+          {{ macros.infobox("Identity count", current_user.identities.__len__(), "red", "users") }}
         </div>
       </div>
       <div class="row">
diff --git a/hiboo/account/templates/avatar_create.html b/hiboo/account/templates/avatar_create.html
deleted file mode 100644
index 6b38b12d02df337d916888301df3e549c7b13cf9..0000000000000000000000000000000000000000
--- a/hiboo/account/templates/avatar_create.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}{% trans %}Sign-up{% endtrans %}{% endblock %}
-{% block subtitle %}{% trans %}for the service {{ service.name }}{% endtrans %}{% endblock %}
-
-{% block content %}
-<div class="box">
-  <div class="box-body">
-    <p>{% trans %}Your are about to sign up for {{ service.name }}{% endtrans %}.</p>
-  </div>
-  <form method="POST" action="{{ action_pick }}" class="form">
-      {{ form.hidden_tag() }}
-      <input type="submit" value="Sign up" style="opacity: 0.8" class="btn btn-lg btn-flat bg-gray text-black">
-  </form>
-</div>
-{% endblock %}
diff --git a/hiboo/account/templates/avatar_pick.html b/hiboo/account/templates/avatar_pick.html
deleted file mode 100644
index 0236ad1281cc59be23e0635dcb144601a1c4d058..0000000000000000000000000000000000000000
--- a/hiboo/account/templates/avatar_pick.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}{% trans %}Sign in{% endtrans %}{% endblock %}
-{% block subtitle %}{% trans %}for the service {{ service.name }}{% endtrans %}{% endblock %}
-
-{% block content %}
-<div class="box">
-  <div class="box-body">
-    <p>{% trans %}Please confirm that you wish to sign in to {{ service.name }}.{% endtrans %}</p>
-  </div>
-  <form method="POST" action="{{ action_pick }}" class="form">
-      {{ form.hidden_tag() }}
-      <input type="hidden" name="profile_uuid" value="{{ avatar.uuid }}">
-      <input type="submit" value="Sign in" style="opacity: 0.8" class="btn btn-lg btn-flat bg-gray text-black">
-  </form>
-</div>
-{% endblock %}
diff --git a/hiboo/identity/__init__.py b/hiboo/identity/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..ec4054a4e3e13fd178523c0a56a409ed505dec9c
--- /dev/null
+++ b/hiboo/identity/__init__.py
@@ -0,0 +1,23 @@
+import flask
+
+
+blueprint = flask.Blueprint("identity", __name__, template_folder="templates")
+
+import flask_login
+from hiboo import models, utils
+from hiboo.identity import profiles, avatars, forms
+
+
+def get_identity(service, **redirect_args):
+    form = forms.IdentityPickForm()
+    if form.validate_on_submit():
+        identity = models.Identity.query.get(form.identity_uuid.data)
+        if not (identity and
+                identity.user == flask_login.current_user and
+                identity.service == service and
+                identity.status == models.Identity.ACTIVE):
+            return None
+        return identity
+    next = ("identity.pick_avatar" if service.max_profiles == 0
+            else "identity.pick_profile")
+    utils.force_redirect(utils.url_for(next, **redirect_args))
diff --git a/hiboo/identity/avatars.py b/hiboo/identity/avatars.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c248fab9799915f8ac7c453fb04a0f846ec4e53
--- /dev/null
+++ b/hiboo/identity/avatars.py
@@ -0,0 +1,57 @@
+from hiboo.identity import blueprint, forms
+from hiboo import models, utils, security
+
+import flask
+import flask_login
+
+
+@blueprint.route("/avatar/pick/<service_uuid>")
+@security.authentication_required()
+def pick_avatar(service_uuid):
+    service = models.Service.query.get(service_uuid) or flask.abort(404)
+    service.max_profiles == 0 or flask.abort(404)
+    avatar = models.Identity.filter(service, flask_login.current_user).first()
+    form = forms.IdentityPickForm()
+    if avatar:
+        if avatar.status == models.Identity.REQUEST:
+            flask.flash("Your account request is awaiting approval", "warning")
+            return flask.redirect(fflask.url_for("account.home"))
+        elif avatar.status == models.Identity.BLOCKED:
+            flask.flash("You are currently blocked", "danger")
+            return flask.redirect(fflask.url_for("account.home"))
+        elif avatar.status in (models.Identity.DELETED, models.Identity.UNCLAIMED):
+            flask.flash("Your avatar is unavailable", "danger")
+            return flask.redirect(fflask.url_for("account.home"))
+    elif service.policy not in (models.Service.OPEN, models.Service.MANAGED):
+        flask.flash("You cannot access this service", "danger")
+        return flask.redirect(fflask.url_for("account.home"))
+    else:
+        return flask.redirect(utils.url_for("identity.create_avatar", intent=True))
+    return flask.render_template("avatar_pick.html", service=service, avatar=avatar, form=form)
+
+
+@blueprint.route("/avatar/create/<service_uuid>", methods=["GET", "POST"])
+@security.authentication_required()
+def create_avatar(service_uuid):
+    service = models.Service.query.get(service_uuid) or flask.abort(404)
+    service.max_profiles == 0 or flask.abort(404)
+    # Cannot create an avatar if one exists already
+    models.Identity.filter(service, flask_login.current_user).first() and flask.abort(403)
+    # Cannot create an avatar for anything but a managed or open service
+    if service.policy == models.Service.OPEN:
+        status = models.Identity.ACTIVE
+    elif service.policy == models.Service.MANAGED:
+        status = models.Identity.REQUEST
+    else:
+        flask.abort(403)
+    form = forms.AvatarForm()
+    if form.validate_on_submit():
+        avatar = models.Identity()
+        avatar.username = flask_login.current_user.username
+        avatar.user = flask_login.current_user
+        avatar.service = service
+        avatar.status = models.Identity.ACTIVE
+        models.db.session.add(avatar)
+        models.db.session.commit()
+        return flask.redirect(utils.url_or_intent("account.home"))
+    return flask.render_template("avatar_create.html", form=form, service=service)
diff --git a/hiboo/identity/forms.py b/hiboo/identity/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..26963bc3f42405bcffd73d3e7a741175f1c11c82
--- /dev/null
+++ b/hiboo/identity/forms.py
@@ -0,0 +1,24 @@
+from wtforms import validators, fields
+from flask_babel import lazy_gettext as _
+
+import flask_wtf
+
+
+class ProfileForm(flask_wtf.FlaskForm):
+    username = fields.StringField(_('Username'), [validators.DataRequired()])
+    comment = fields.StringField(_('Comment'))
+    submit = fields.SubmitField(_('Create profile'))
+
+
+class IdentityPickForm(flask_wtf.FlaskForm):
+    identity_uuid = fields.TextField('identity', [])
+
+
+class AvatarForm(flask_wtf.FlaskForm):
+    submit = fields.SubmitField(_('Sign up'), [])
+
+
+class ClaimForm(flask_wtf.FlaskForm):
+    username = fields.StringField(_('Username'), [validators.DataRequired()])
+    password = fields.PasswordField(_('Password'), [validators.DataRequired()])
+    submit = fields.SubmitField(_('Claim profile'))
diff --git a/hiboo/identity/profiles.py b/hiboo/identity/profiles.py
new file mode 100644
index 0000000000000000000000000000000000000000..75ec2f67a42b3b065740487feba75caf8a42fb02
--- /dev/null
+++ b/hiboo/identity/profiles.py
@@ -0,0 +1,107 @@
+from hiboo.identity import blueprint, forms
+from hiboo import models, utils, security
+from hiboo import user as hiboo_user
+from passlib import context, hash
+
+import flask
+import flask_login
+
+
+@blueprint.route("/profile/pick/<service_uuid>")
+@security.authentication_required()
+def pick_profile(service_uuid):
+    service = models.Service.query.get(service_uuid) or flask.abort(404)
+    service.max_profiles > 0 or flask.abort(404)
+    profiles = models.Identity.filter(service, flask_login.current_user).all()
+    form = forms.IdentityPickForm()
+    return flask.render_template("profile_pick.html", service=service, profiles=profiles, form=form)
+
+
+@blueprint.route("/profile/create_for/<service_uuid>", methods=["GET", "POST"], defaults={"create_for": True}, endpoint="create_profile_for")
+@blueprint.route("/profile/create/<service_uuid>", methods=["GET", "POST"])
+@security.authentication_required()
+def create_profile(service_uuid, create_for=False):
+    service = models.Service.query.get(service_uuid) or flask.abort(404)
+    service.max_profiles > 0 or flask.abort(404)
+    status = models.Identity.ACTIVE
+    # If the admin passed a user uuid, use that one, otherwise ignore it
+    if create_for and flask_login.current_user.is_admin:
+        user = hiboo_user.get_user(intent="identity.create_profile_for", create_for=None)
+    else:
+        user = flask_login.current_user
+    # Do not create profile for locked services
+    if service.policy == models.Service.LOCKED:
+        flask.flash("You cannot request a profile for this service", "danger")
+        return flask.redirect(flask.url_for("account.home"))
+    # Other restrictions do not apply to admins or managers
+    if not flask_login.current_user.is_admin:
+        profiles = models.Identity.filter(service, user).all()
+        # Do not create profile for locked services
+        if service.policy == models.Service.RESERVED:
+            flask.flash("You cannot request a profile for this service", "danger")
+            return flask.redirect(flask.url_for("account.home"))
+        # Only burst services are allowed to exceed profile count
+        elif len(profiles) >= service.max_profiles and service.policy != models.Service.BURST:
+            flask.flash("Your reached the maximum number of profiles", "danger")
+            return flask.redirect(flask.url_for("account.home"))
+        # Managed services and bursting accounts require approval
+        elif len(profiles) >= service.max_profiles or service.policy == models.Service.MANAGED:
+            flask.flash("Your profile creation requires approval", "warning")
+            status = models.Profile.REQUEST
+    # Actually display the form
+    form = forms.ProfileForm()
+    if form.validate_on_submit():
+        existing = models.Identity.query.filter_by(
+            service_uuid=service_uuid, username=form.username.data
+        ).first()
+        if existing:
+            flask.flash("A profile with that username exists already", "danger")
+        else:
+            profile = models.Identity()
+            profile.username = form.username.data
+            profile.user = user
+            profile.service = service
+            profile.comment = form.comment.data
+            profile.status = status
+            models.db.session.add(profile)
+            models.log(models.History.CREATE, profile.username, profile.comment,
+                user=user, service=service, identity=profile)
+            models.db.session.commit()
+            return flask.redirect(utils.url_or_intent("account.home"))
+    return flask.render_template("profile_create.html", form=form, service=service,
+        user=user, create_for=create_for)
+
+
+@blueprint.route("/profile/claim/<service_uuid>", methods=["GET", "POST"])
+@security.authentication_required()
+def claim_profile(service_uuid):
+    service = models.Service.query.get(service_uuid) or flask.abort(404)
+    service.max_profiles > 0 or flask.abort(404)
+    form = forms.ClaimForm()
+    if form.validate_on_submit():
+        profile = models.Identity.query.filter_by(
+            service_uuid=service_uuid, username=form.username.data,
+            status = models.Identity.UNCLAIMED
+        ).first()
+        check = context.CryptContext([
+            scheme for scheme in dir(hash) if not scheme.startswith('__')
+        ])
+        if profile and check.verify(form.password.data, profile.extra.get("password")):
+            profile.user = flask_login.current_user
+            profile.status = models.Identity.ACTIVE
+            del profile.extra["password"]
+            models.db.session.add(profile)
+            models.db.session.commit()
+            flask.flash("Successfully claimed the profile!", "success")
+        else:
+            flask.flash("Wrong username or password", "danger")
+    return flask.render_template("profile_claim.html", form=form, service=service)
+
+
+@blueprint.route("/profile/service/<service_uuid>")
+@security.admin_required()
+def list_profiles(service_uuid=None):
+    service = models.Service.query.get(service_uuid) or flask.abort(404)
+    service.max_profiles > 0 or flask.abort(404)
+    return flask.render_template("profile_list.html", profiles=service.profiles,
+        service=service)
diff --git a/hiboo/identity/templates/avatar_create.html b/hiboo/identity/templates/avatar_create.html
new file mode 100644
index 0000000000000000000000000000000000000000..83cec6ee3d7bf49c9d698766508174e0421eaf2c
--- /dev/null
+++ b/hiboo/identity/templates/avatar_create.html
@@ -0,0 +1,13 @@
+{% extends "base.html" %}
+
+{% block title %}{% trans %}Sign-up{% endtrans %}{% endblock %}
+{% block subtitle %}{% trans service_name %}for the service {{ service_name }}{% endtrans %}{% endblock %}
+
+{% block content %}
+<div class="box">
+  <div class="box-body">
+    <p>{% trans %}Your are about to sign up for {{ service.name }}{% endtrans %}.</p>
+  </div>
+  {{ macros.form(form) }}
+</div>
+{% endblock %}
diff --git a/hiboo/identity/templates/avatar_pick.html b/hiboo/identity/templates/avatar_pick.html
new file mode 100644
index 0000000000000000000000000000000000000000..e7efa23fdbca345047723089c6a9a21ff7e02c3a
--- /dev/null
+++ b/hiboo/identity/templates/avatar_pick.html
@@ -0,0 +1,17 @@
+{% extends "base.html" %}
+
+{% block title %}{% trans %}Sign in{% endtrans %}{% endblock %}
+{% block subtitle %}{% trans service_name %}for the service {{ service_name }}{% endtrans %}{% endblock %}
+
+{% block content %}
+<div class="box">
+  <div class="box-body">
+    <p>{% trans %}Please confirm that you wish to sign in to {{ service.name }}.{% endtrans %}</p>
+  </div>
+  <form method="POST" action="{{ utils.url_or_intent("account.home") }}" class="form">
+      {{ form.hidden_tag() }}
+      <input type="hidden" name="identity_uuid" value="{{ avatar.uuid }}">
+      <input type="submit" value="Sign in" class="btn btn-lg btn-flat bg-gray text-black">
+  </form>
+</div>
+{% endblock %}
diff --git a/hiboo/identity/templates/profile_claim.html b/hiboo/identity/templates/profile_claim.html
new file mode 100644
index 0000000000000000000000000000000000000000..fed37c23fe6b20419cbef5cb50b12f59675d9704
--- /dev/null
+++ b/hiboo/identity/templates/profile_claim.html
@@ -0,0 +1,17 @@
+{% extends "base.html" %}
+
+{% set service_name = service.name %}
+{% block title %}{% trans %}Claim profile{% endtrans %}{% endblock %}
+{% block subtitle %}{% trans service_name %}for the service {{ service_name }}{% endtrans %}{% endblock %}
+
+{% block content %}
+
+{% call macros.help(_("Claim an existing profile"), auto=utils.display_help("main")) %}
+  <p>{% trans %}You are about to create your first profile.{% endtrans %}</p>
+  <p>{% trans %}Please choose a username wisely, you will not be able to change it later. You may pick anything that is valid for the service, as long as it is available.{% endtrans %}</p>
+  <p>{% trans %}If your profile request is submitted for validation, please add a useful comment that will help us validate (describe shortly what your profile is for or why you need one).{% endtrans %}</p>
+{% endcall %}
+
+{{ macros.form(form) }}
+
+{% endblock %}
diff --git a/hiboo/account/templates/profile_create.html b/hiboo/identity/templates/profile_create.html
similarity index 79%
rename from hiboo/account/templates/profile_create.html
rename to hiboo/identity/templates/profile_create.html
index 6d5e26fc3db74e6cec0c9ea194cdfec52e5ca7c8..408762a2b811e3be2435c490cccbd0a9a8a83c77 100644
--- a/hiboo/account/templates/profile_create.html
+++ b/hiboo/identity/templates/profile_create.html
@@ -2,7 +2,10 @@
 
 {% set service_name = service.name %}
 {% block title %}{% trans %}New profile{% endtrans %}{% endblock %}
-{% block subtitle %}{% trans service_name %}for the service {{ service_name }}{% endtrans %}{% endblock %}
+{% block subtitle %}
+  {% trans service_name %}for the service {{ service_name }}{% endtrans %}
+  {% if create_for %}{% trans %}and user{% endtrans %} {{ user.username }}{% endif %}
+{% endblock %}
 
 {% block content %}
 
diff --git a/hiboo/identity/templates/profile_list.html b/hiboo/identity/templates/profile_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..762ef2df48de2ee364fa7b88482977e8db343c79
--- /dev/null
+++ b/hiboo/identity/templates/profile_list.html
@@ -0,0 +1,37 @@
+{% extends "base.html" %}
+
+{% block title %}{% trans %}Profile list{% endtrans %}{% endblock %}
+{% block subtitle %}{% if service %}{{ service.name }}{% endif %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-xs-12">
+    <div class="box">
+      <div class="box-body table-responsive no-padding">
+        <table class="table table-hover">
+          <tr>
+            <th>{% trans %}Service{% endtrans %}</th>
+            <th>{% trans %}User{% endtrans %}</th>
+            <th>{% trans %}Identity{% endtrans %}</th>
+            <th>{% trans %}Created on{% endtrans %}</th>
+          </tr>
+          {% for profile in profiles %}
+          <tr>
+            <td>{{ profile.service.name }}</td>
+            <td>{{ profile.user.username }}</td>
+            <td>{{ profile.username }}</td>
+            <td>{{ profile.created_on }}</td>
+          </tr>
+          {% endfor %}
+        </table>
+      </div>
+    </div>
+  </div>
+</div>
+{% endblock %}
+
+{% block actions %}
+{% if service %}
+<a href="{{ url_for(".create_profile_for", service_uuid=service.uuid) }}" class="btn btn-success">{% trans %}Create a profile{% endtrans %}</a>
+{% endif %}
+{% endblock %}
diff --git a/hiboo/account/templates/profile_pick.html b/hiboo/identity/templates/profile_pick.html
similarity index 85%
rename from hiboo/account/templates/profile_pick.html
rename to hiboo/identity/templates/profile_pick.html
index ed86316812a5bfb351c6e601f3cf8d80dd2b7cac..41f19fe564353bd02c56667a90fbdf99f5694d4b 100644
--- a/hiboo/account/templates/profile_pick.html
+++ b/hiboo/identity/templates/profile_pick.html
@@ -13,9 +13,9 @@
     <div class="box box-widget widget-user-2">
       <div class="widget-user-header bg-{{ colors[loop.index0 % 7] }}">
         {% if profile.status == "active" %}
-        <form method="POST" action="{{ action_pick }}" class="form">
+        <form method="POST" action="{{ utils.url_or_intent("account.home") }}" class="form">
             {{ form.hidden_tag() }}
-            <input type="hidden" name="profile_uuid" value="{{ profile.uuid }}">
+            <input type="hidden" name="identity_uuid" value="{{ profile.uuid }}">
             <input type="submit" value="Sign in" style="opacity: 0.8" class="btn btn-lg btn-flat bg-gray text-black pull-right">
         </form>
         {% elif profile.status == "blocked" %}
@@ -61,11 +61,14 @@
 {% endblock %}
 
 {% block actions %}
+{% if service.policy not in ("locked") %}
+<a href="{{ utils.url_for(".claim_profile", intent=True) }}" class="btn btn-primary">Claim profile</a>
+{% endif %}
 {% if service.policy in ("open", "burst") and profiles.__len__() < service.max_profiles %}
-<a href="{{ utils.url_for(".create_profile") }}" class="btn btn-primary">Create profile</a>
+<a href="{{ utils.url_for(".create_profile", intent=True) }}" class="btn btn-success">Create profile</a>
 {% elif service.policy in ("managed", "burst") %}
-<a href="{{ utils.url_for(".create_profile") }}" class="btn btn-warning">Request profile</a>
+<a href="{{ utils.url_for(".create_profile", intent=True) }}" class="btn btn-warning">Request profile</a>
 {% else %}
-<a href="#" class="btn btn-primary" disabled>Create profile</a>
+<a href="#" class="btn btn-success" disabled>Create profile</a>
 {% endif %}
 {% endblock %}
diff --git a/hiboo/models.py b/hiboo/models.py
index 8acbadecc1eeeea9b486a053be29af95d7fa9716..0a6481dc9dc1e37e3ac2037d7deddf37892b84ef 100644
--- a/hiboo/models.py
+++ b/hiboo/models.py
@@ -10,7 +10,7 @@ import json
 import uuid
 
 
-def log(category, value=None, comment=None, user=None, profile=None, service=None, actor=None):
+def log(category, value=None, comment=None, user=None, identity=None, service=None, actor=None):
     """ Log a history event
     """
     event = History()
@@ -18,7 +18,7 @@ def log(category, value=None, comment=None, user=None, profile=None, service=Non
     event.value = value
     event.comment = comment
     event.user = user
-    event.profile = profile
+    event.identity = identity
     event.service = service
     event.actor = actor
     db.session.add(event)
@@ -164,10 +164,11 @@ class Service(db.Model):
     config = db.Column(JSONEncoded)
 
 
-class Profile(db.Model):
-    """ A profile is a user instance for a given service.
+class Identity(db.Model):
+    """ An identity is either a profile or an avatar for a user and given
+    service.
     """
-    __tablename__ = "profile"
+    __tablename__ = "identity"
 
     UNCLAIMED = "unclaimed"
     REQUEST = "request"
@@ -184,6 +185,7 @@ class Profile(db.Model):
 
     username = db.Column(db.String(255), nullable=False)
     status = db.Column(db.String(25), nullable=False)
+    extra = db.Column(JSONEncoded)
 
     @property
     def email(self):
@@ -198,7 +200,7 @@ class Profile(db.Model):
 
 
 class History(db.Model):
-    """ Records an even in an account's or profile's lifetime.
+    """ Records an even in an account's or identity's lifetime.
     """
     __tablename__ = "history"
 
@@ -211,17 +213,17 @@ class History(db.Model):
 
     DESCRIPTION = {
         SIGNUP: _("signed up for this account"),
-        CREATE: _("created the profile {this.profile.username} on {this.service.name}"),
+        CREATE: _("created the identity {this.identity.username} on {this.service.name}"),
         PASSWORD: _("changed your password")
     }
 
     user_uuid = db.Column(db.String(36), db.ForeignKey(User.uuid))
-    profile_uuid = db.Column(db.String(36), db.ForeignKey(Profile.uuid))
+    identity_uuid = db.Column(db.String(36), db.ForeignKey(Identity.uuid))
     service_uuid = db.Column(db.String(36), db.ForeignKey(Service.uuid))
     actor_uuid = db.Column(db.String(36), db.ForeignKey(User.uuid))
     user = db.relationship(User, foreign_keys=[user_uuid],
         backref=db.backref('history', cascade='all, delete-orphan'))
-    profile = db.relationship(Profile,
+    identity = db.relationship(Identity,
         backref=db.backref('history', cascade='all, delete-orphan'))
     service = db.relationship(Service,
         backref=db.backref('history', cascade='all, delete-orphan'))
diff --git a/hiboo/security.py b/hiboo/security.py
index b7bd1d29b6e80986a54aff8e05dff083bd598f1a..6ee5ea39a4d49e7bbfc639080ddb3f320429dcd6 100644
--- a/hiboo/security.py
+++ b/hiboo/security.py
@@ -1,6 +1,9 @@
 import flask_login
+import flask_wtf
 import flask
 import functools
+import flask_babel
+import wtforms
 
 
 def permissions_wrapper(handler):
@@ -39,3 +42,23 @@ def authentication_required(args, kwargs):
     """ The view is only available to logged in users.
     """
     return True
+
+
+class ConfirmationForm(flask_wtf.FlaskForm):
+    submit = wtforms.fields.SubmitField(flask_babel.lazy_gettext('Confirm'))
+
+
+def confirmation_required(action):
+    """ The view is only available after manual confirmation.
+    """
+    def inner(decorated):
+        @functools.wraps(decorated)
+        def wrapper(*args, **kwargs):
+            form = ConfirmationForm()
+            if form.validate_on_submit():
+                return decorated(*args, **kwargs)
+            return flask.render_template(
+                "confirm.html", action=action.format(*args, **kwargs), form=form
+            )
+        return wrapper
+    return inner
diff --git a/hiboo/service/__init__.py b/hiboo/service/__init__.py
index 148372807beeeb2193a49aeca4eb5d06c1364fd6..6332441f0e7b2d958b488b7c99ca846a294d226c 100644
--- a/hiboo/service/__init__.py
+++ b/hiboo/service/__init__.py
@@ -1,6 +1,6 @@
-from flask import Blueprint
+import flask
 
 
-blueprint = Blueprint("service", __name__, template_folder="templates")
+blueprint = flask.Blueprint("service", __name__, template_folder="templates")
 
 from hiboo.service import admin
diff --git a/hiboo/service/admin.py b/hiboo/service/admin.py
index a47fe15d60e765a720010a054f2c22322f5e86f9..ad7b0b14370507e1f52bdd45a1ce8e7f4ce39581 100644
--- a/hiboo/service/admin.py
+++ b/hiboo/service/admin.py
@@ -14,14 +14,11 @@ def list():
 
 
 @blueprint.route("/create")
-@security.admin_required()
-def create():
-    return flask.render_template("service_create.html", protocols=protocols)
-
-
 @blueprint.route("/create/<protocol_name>", methods=["GET", "POST"])
 @security.admin_required()
-def create_protocol(protocol_name):
+def create(protocol_name=None):
+    if protocol_name is None:
+        return flask.render_template("protocol_pick.html", protocols=protocols)
     protocol = protocols.get(protocol_name, None) or flask.abort(404)
     form = protocol.Config.derive_form(forms.ServiceForm)()
     if form.validate_on_submit():
@@ -35,7 +32,7 @@ def create_protocol(protocol_name):
         models.db.session.commit()
         flask.flash("Service successfully created", "success")
         return flask.redirect(flask.url_for(".list"))
-    return flask.render_template("service_create_form.html",
+    return flask.render_template("service_create.html",
         protocol=protocol, form=form)
 
 
@@ -44,3 +41,13 @@ def create_protocol(protocol_name):
 def details(service_uuid):
     service = models.Service.query.get(service_uuid) or flask.abort(404)
     return flask.render_template("service_details.html", service=service)
+
+
+@blueprint.route("/delete/<service_uuid>", methods=["GET", "POST"])
+@security.admin_required()
+@security.confirmation_required("delete the service")
+def delete(service_uuid):
+    service = models.Service.query.get(service_uuid) or flask.abort(404)
+    models.db.session.delete(service)
+    models.db.session.commit()
+    return flask.redirect(flask.url_for(".list"))
diff --git a/hiboo/service/templates/protocol_pick.html b/hiboo/service/templates/protocol_pick.html
new file mode 100644
index 0000000000000000000000000000000000000000..49b9632b471b8d9aaeef3052ce26fc02567bbe4d
--- /dev/null
+++ b/hiboo/service/templates/protocol_pick.html
@@ -0,0 +1,25 @@
+{% extends "base.html" %}
+
+{% block title %}{% trans %}Create a service{% endtrans %}{% endblock %}
+{% block subtitle %}{% trans %}pick a protocol{% endtrans %}{% endblock %}
+
+{% set colors = ['blue', 'green', 'orange', 'teal', 'red', 'purple', 'maroon'] %}
+
+{% block content %}
+<div class="row">
+{% for protocol in protocols %}
+{% import "protocol_" + protocol + ".html" as protocol_macros %}
+<div class="col-md-4 col-s-6 col-xs-12">
+  <div class="box box-widget widget-user-2">
+    <div class="widget-user-header bg-{{ colors[loop.index0 % 7] }}">
+      <a href="{{ url_for(".create", protocol_name=protocol) }}" style="opacity: 0.8" class="btn btn-lg bg-gray text-black pull-right">
+        {% trans %}Create {% endtrans %}{{ protocol_macros.name() }}
+      </a>
+      <h3 class="widget-header-username">{{ protocol_macros.name() }}</h3>
+      <h5 class="widget-header-desc">{{ protocol_macros.description() }}&nbsp;</h5>
+    </div>
+  </div>
+</div>
+{% endfor %}
+</div>
+{% endblock %}
diff --git a/hiboo/service/templates/service_create.html b/hiboo/service/templates/service_create.html
index 7e68d86dbe51a1c8240fa55cf833e7f32b9f5142..40db580b03391a421f5bf2a364983166ec0bb813 100644
--- a/hiboo/service/templates/service_create.html
+++ b/hiboo/service/templates/service_create.html
@@ -1,25 +1,4 @@
-{% extends "base.html" %}
+{% extends "form.html" %}
 
 {% block title %}{% trans %}Create a service{% endtrans %}{% endblock %}
-{% block subtitle %}{% trans %}pick a protocol{% endtrans %}{% endblock %}
-
-{% set colors = ['blue', 'green', 'orange', 'teal', 'red', 'purple', 'maroon'] %}
-
-{% block content %}
-<div class="row">
-{% for protocol in protocols %}
-{% import "protocol_" + protocol + ".html" as protocol_macros %}
-<div class="col-md-4 col-s-6 col-xs-12">
-  <div class="box box-widget widget-user-2">
-    <div class="widget-user-header bg-{{ colors[loop.index0 % 7] }}">
-      <a href="{{ url_for(".create_protocol", protocol_name=protocol) }}" style="opacity: 0.8" class="btn btn-lg bg-gray text-black pull-right">
-        {% trans %}Create {% endtrans %}{{ protocol_macros.name() }}
-      </a>
-      <h3 class="widget-header-username">{{ protocol_macros.name() }}</h3>
-      <h5 class="widget-header-desc">{{ protocol_macros.description() }}&nbsp;</h5>
-    </div>
-  </div>
-</div>
-{% endfor %}
-</div>
-{% endblock %}
+{% block subtitle %}{% trans %}add a SAML service{% endtrans %}{% endblock %}
diff --git a/hiboo/service/templates/service_create_form.html b/hiboo/service/templates/service_create_form.html
deleted file mode 100644
index 40db580b03391a421f5bf2a364983166ec0bb813..0000000000000000000000000000000000000000
--- a/hiboo/service/templates/service_create_form.html
+++ /dev/null
@@ -1,4 +0,0 @@
-{% extends "form.html" %}
-
-{% block title %}{% trans %}Create a service{% endtrans %}{% endblock %}
-{% block subtitle %}{% trans %}add a SAML service{% endtrans %}{% endblock %}
diff --git a/hiboo/service/templates/service_details.html b/hiboo/service/templates/service_details.html
index 8ccae60a81ab7fa0d52eb97e3182556810746692..e690ad0682f3c66617be94e466a89f7505467f1c 100644
--- a/hiboo/service/templates/service_details.html
+++ b/hiboo/service/templates/service_details.html
@@ -28,6 +28,7 @@
 {% endblock %}
 
 {% block actions %}
+<a href="{{ url_for("identity.list_profiles", service_uuid=service.uuid) }}" class="btn btn-primary">{% trans %}View profiles{% endtrans %}</a>
 <a href="{{ url_for(".create") }}" class="btn btn-primary">{% trans %}Edit this service{% endtrans %}</a>
-<a href="{{ url_for(".create") }}" class="btn btn-danger">{% trans %}Delete this service{% endtrans %}</a>
+<a href="{{ url_for(".delete", service_uuid=service.uuid) }}" class="btn btn-danger">{% trans %}Delete this service{% endtrans %}</a>
 {% endblock %}
diff --git a/hiboo/service/templates/service_list.html b/hiboo/service/templates/service_list.html
index d1f13db4e0bc297b977d081f0a2f460792818812..7917d32dc3d8f7d7e8e8d52e41b6e14ff5b36631 100644
--- a/hiboo/service/templates/service_list.html
+++ b/hiboo/service/templates/service_list.html
@@ -31,5 +31,5 @@
 {% endblock %}
 
 {% block actions %}
-<a href="{{ url_for(".create") }}" class="btn btn-primary">{% trans %}Create a service{% endtrans %}</a>
+<a href="{{ url_for(".create") }}" class="btn btn-success">{% trans %}Create a service{% endtrans %}</a>
 {% endblock %}
diff --git a/hiboo/sso/__init__.py b/hiboo/sso/__init__.py
index a845b1ff61518710fba0afacd7245b6ed9fd7a31..504ae9128498376348dfd4d28738825113730714 100644
--- a/hiboo/sso/__init__.py
+++ b/hiboo/sso/__init__.py
@@ -1,7 +1,7 @@
-from flask import Blueprint
+import flask
 
 
-blueprint = Blueprint("sso", __name__, template_folder="templates")
+blueprint = flask.Blueprint("sso", __name__, template_folder="templates")
 
 from hiboo.sso import saml, oidc
 
diff --git a/hiboo/sso/saml.py b/hiboo/sso/saml.py
index 332a39b0dd3a67330079998573c2f2b098a5b2d1..c62b6cb61cd078445fe5b931bb715de2cef8b7ff 100644
--- a/hiboo/sso/saml.py
+++ b/hiboo/sso/saml.py
@@ -6,7 +6,7 @@ from saml2 import sigver
 sigver.security_context = security_context
 
 from hiboo.sso import blueprint, forms
-from hiboo import models, utils, account, security
+from hiboo import models, utils, identity, security
 from saml2 import server, saml, config, mdstore, assertion
 from cryptography import x509
 from cryptography.hazmat import primitives, backends
@@ -22,7 +22,7 @@ class Config(object):
     def derive_form(cls, form):
         """ Add required fields to a form.
         """
-        return type('NewForm', (form, forms.SAMLForm), {})
+        return type('NewForm', (forms.SAMLForm, form), {})
 
     @classmethod
     def populate_service(cls, form, service):
@@ -159,9 +159,7 @@ def saml_redirect(service_uuid):
     # Get the profile from user input (implies redirects)
     service = models.Service.query.get(service_uuid) or flask.abort(404)
     service.protocol == "saml" or flask.abort(404)
-    profile = account.profiles.get_profile(
-        service, intent="sso.saml_redirect", service_uuid=service_uuid
-    ) or flask.abort(403)
+    profile = identity.get_identity(service, intent=True) or flask.abort(403)
     # Parse the authentication request and check the ACS
     idp = server.Server(config=(MetaData.get_config(service)))
     xml = flask.request.args["SAMLRequest"]
diff --git a/hiboo/templates/confirm.html b/hiboo/templates/confirm.html
new file mode 100644
index 0000000000000000000000000000000000000000..61d3a3872b43b50841679b9b5aac542987a4116f
--- /dev/null
+++ b/hiboo/templates/confirm.html
@@ -0,0 +1,11 @@
+{% extends "base.html" %}
+
+{% block title %}{% trans %}Confirm your action{% endtrans %}{% endblock %}
+{% block subtitle %}{{ action }}{% endblock %}
+
+{% block content %}
+<p>
+  {% trans action %}Your are about to {{ action }}. Do you wish to confirm that action?{% endtrans %}
+</p>
+{{ macros.form(form) }}
+{% endblock %}
diff --git a/hiboo/user/__init__.py b/hiboo/user/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d4e63e11834e0c6c1b517d50e3d5b367c7e7f7e
--- /dev/null
+++ b/hiboo/user/__init__.py
@@ -0,0 +1,14 @@
+import flask
+
+
+blueprint = flask.Blueprint("user", __name__, template_folder="templates")
+
+from hiboo import models, utils
+from hiboo.user import users
+
+
+def get_user(**redirect_args):
+    user_uuid = flask.request.args.get("user_uuid")
+    if user_uuid:
+        return models.User.query.get(user_uuid) or None
+    utils.force_redirect(utils.url_for("user.pick_user", **redirect_args))
diff --git a/hiboo/user/forms.py b/hiboo/user/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..eccf3fc665912ce79c87ef12bc73cc51f19ecdd7
--- /dev/null
+++ b/hiboo/user/forms.py
@@ -0,0 +1,8 @@
+from wtforms import validators, fields
+from flask_babel import lazy_gettext as _
+
+import flask_wtf
+
+
+class UserPickForm(flask_wtf.FlaskForm):
+    user_uuid = fields.TextField('user', [])
diff --git a/hiboo/user/templates/user_pick.html b/hiboo/user/templates/user_pick.html
new file mode 100644
index 0000000000000000000000000000000000000000..c2a52dfeddce2f2e38a44888a3fe1c7cabe323ae
--- /dev/null
+++ b/hiboo/user/templates/user_pick.html
@@ -0,0 +1,26 @@
+{% extends "base.html" %}
+
+{% block title %}{% trans %}Pick a user{% endtrans %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-xs-12">
+    <div class="box">
+      <div class="box-body table-responsive no-padding">
+        <table class="table table-hover">
+          <tr>
+            <th>{% trans %}Username{% endtrans %}</th>
+            <th>{% trans %}Created on{% endtrans %}</th>
+          </tr>
+          {% for user in users %}
+          <tr>
+            <td><a href="{{ utils.url_or_intent("account.home", user_uuid=user.uuid) }}">{{ user.username }}</a></td>
+            <td>{{ user.created_at.date() }}</td>
+          </tr>
+          {% endfor %}
+        </table>
+      </div>
+    </div>
+  </div>
+</div>
+{% endblock %}
diff --git a/hiboo/user/users.py b/hiboo/user/users.py
new file mode 100644
index 0000000000000000000000000000000000000000..9121666d8f058665cb115fee0b37c8cf2459f576
--- /dev/null
+++ b/hiboo/user/users.py
@@ -0,0 +1,12 @@
+from hiboo.user import blueprint, forms
+from hiboo import models, utils, security
+
+import flask
+
+
+@blueprint.route("/user/pick")
+@security.admin_required()
+def pick_user():
+    users = models.User.query.all()
+    form = forms.UserPickForm()
+    return flask.render_template("user_pick.html", users=users, form=form)
diff --git a/hiboo/utils.py b/hiboo/utils.py
index 56afd08803195cd1993bf5f8169c91e1554de656..d5d319fd278d41245b69349c0ee9d7bbbfa5c366 100644
--- a/hiboo/utils.py
+++ b/hiboo/utils.py
@@ -27,25 +27,31 @@ def url_for(endpoint, intent=None, *args, **kwargs):
     an intent
     """
     query_string = dict(flask.request.args)
+    query_string.update(dict(flask.request.view_args or {}))
     for key, value in kwargs.items():
         if value is None and key in query_string:
             del query_string[key]
         elif value is not None:
             query_string[key] = value
-    if INTENTS in query_string and intent is not None:
-        query_string[INTENTS] += ":" + intent
-    elif INTENTS not in query_string and intent is not None:
-        query_string[INTENTS] = intent
+    if intent is not None:
+        if intent == True:
+            intent = flask.request.endpoint
+        if INTENTS in query_string:
+            query_string[INTENTS] += ":" + intent
+        else:
+            query_string[INTENTS] = intent
     return flask.url_for(endpoint, *args, **query_string)
 
 
-def url_or_intent(endpoint):
+def url_or_intent(endpoint, **kwargs):
     """ Return the latest intent, or the endpoint url if none
     """
     intents = flask.request.args.get(INTENTS, "")
     if intents:
         intents = intents.split(":")
-        return url_for(intents.pop(), intents=":".join(intents) or None)
+        return url_for(
+            intents.pop(), intents=":".join(intents) or None, **kwargs
+        )
     else:
         return flask.url_for(endpoint)
 
@@ -53,7 +59,9 @@ def url_or_intent(endpoint):
 def force_redirect(destination):
     """ Force a redirect by triggering an exception
     """
-    raise routing.RequestRedirect(destination)
+    redirect = routing.RequestRedirect(destination)
+    redirect.code = 302
+    raise redirect
 
 
 def display_help(identifier):
diff --git a/migrations/versions/cfb466a78348_.py b/migrations/versions/cfb466a78348_.py
index 2c1cfad2e29d5c5c0f86bd4f4adf58abf346c078..129c0f12e82d3233fa5a342290b704f69246e2e9 100644
--- a/migrations/versions/cfb466a78348_.py
+++ b/migrations/versions/cfb466a78348_.py
@@ -51,11 +51,12 @@ def upgrade():
     sa.ForeignKeyConstraint(['user_uuid'], ['user.uuid'], ),
     sa.PrimaryKeyConstraint('uuid')
     )
-    op.create_table('profile',
+    op.create_table('identity',
     sa.Column('user_uuid', sa.String(length=36), nullable=True),
     sa.Column('service_uuid', sa.String(length=36), nullable=True),
     sa.Column('username', sa.String(length=255), nullable=False),
     sa.Column('status', sa.String(length=25), nullable=False),
+    sa.Column('extra', sa.String(), nullable=True),
     sa.Column('uuid', sa.String(length=36), nullable=False),
     sa.Column('created_at', sa.DateTime(), nullable=False),
     sa.Column('updated_at', sa.DateTime(), nullable=True),
@@ -66,7 +67,7 @@ def upgrade():
     )
     op.create_table('history',
     sa.Column('user_uuid', sa.String(length=36), nullable=True),
-    sa.Column('profile_uuid', sa.String(length=36), nullable=True),
+    sa.Column('identity_uuid', sa.String(length=36), nullable=True),
     sa.Column('service_uuid', sa.String(length=36), nullable=True),
     sa.Column('actor_uuid', sa.String(length=36), nullable=True),
     sa.Column('category', sa.String(length=25), nullable=True),
@@ -76,7 +77,7 @@ def upgrade():
     sa.Column('updated_at', sa.DateTime(), nullable=True),
     sa.Column('comment', sa.String(length=255), nullable=True),
     sa.ForeignKeyConstraint(['actor_uuid'], ['user.uuid'], ),
-    sa.ForeignKeyConstraint(['profile_uuid'], ['profile.uuid'], ),
+    sa.ForeignKeyConstraint(['identity_uuid'], ['identity.uuid'], ),
     sa.ForeignKeyConstraint(['service_uuid'], ['service.uuid'], ),
     sa.ForeignKeyConstraint(['user_uuid'], ['user.uuid'], ),
     sa.PrimaryKeyConstraint('uuid')
@@ -85,7 +86,7 @@ def upgrade():
 
 def downgrade():
     op.drop_table('history')
-    op.drop_table('profile')
+    op.drop_table('identity')
     op.drop_table('auth')
     op.drop_table('user')
     op.drop_table('service')