diff --git a/biscuit/core/menus.py b/biscuit/core/menus.py
index 53dbb37a5c27c024ad52e57d1948c23e4ae3bd05..c85af6bfb840d54ce535f86c403ea361dbd3f005 100644
--- a/biscuit/core/menus.py
+++ b/biscuit/core/menus.py
@@ -14,3 +14,7 @@ Menu.add_item('main', MenuItem('Logout',
 Menu.add_item('main', MenuItem(_('Persons'),
                                reverse('persons'),
                                check=lambda request: request.user.is_authenticated))
+
+Menu.add_item('main', MenuItem(_('Groups'),
+                               reverse('groups'),
+                               check=lambda request: request.user.is_authenticated))
diff --git a/biscuit/core/tables.py b/biscuit/core/tables.py
index f4a8e508a4af78c69c81d75a77c00d2b1b3249e8..f7fbeb93a7ecab450d6cc3d4061ea92c0dc56c58 100644
--- a/biscuit/core/tables.py
+++ b/biscuit/core/tables.py
@@ -9,3 +9,10 @@ class PersonsTable(tables.Table):
 
     first_name = tables.LinkColumn('person_by_id', args=[A('id')])
     last_name = tables.LinkColumn('person_by_id', args=[A('id')])
+
+class GroupsTable(tables.Table):
+    class Meta:
+        attrs = {'class': 'table table-striped table-bordered table-hover table-responsive-xl'}
+
+    name = tables.LinkColumn('group_by_id', args=[A('id')])
+    short_name = tables.LinkColumn('group_by_id', args=[A('id')])
diff --git a/biscuit/core/templates/core/group_full.html b/biscuit/core/templates/core/group_full.html
new file mode 100644
index 0000000000000000000000000000000000000000..d4c0854be55f523c8bd670a1956c9b4a154a6614
--- /dev/null
+++ b/biscuit/core/templates/core/group_full.html
@@ -0,0 +1,35 @@
+{% extends "core/base.html" %}
+{% load bootstrap4 font_awesome i18n staticfiles %}
+
+{% block content %}
+<div class="col-sm-12 col-md-12">
+ {% if group %}
+  <h2>{{ group.name }} <small>{{ group.short_name }}</small></h2>
+  <p>
+   <a href="{{ '#' }}">
+    {% blocktrans %}Edit group{% endblocktrans %}
+   </a>
+  </p>
+  <h3>{% blocktrans %}Details{% endblocktrans %}</h3>
+  <table class="table table-responsive-xl table-border table-striped">
+   <tr>
+    <td>{% fa 'users' %}</td>
+    <td>{{ group.name }}</td>
+    <td>{{ group.short_name }}</td>
+   </tr>
+  </table>
+
+  <h3>Members</h3>
+  {% render_table persons_table %}
+
+ {% else %}
+  <h2>{% blocktrans %}Person not found{% endblocktrans %}</h2>
+
+  <p>
+   {% blocktrans %}
+    There is no group with this id.
+   {% endblocktrans %}
+  </p>
+ {% endif %}
+</div>
+{% endblock %}
diff --git a/biscuit/core/templates/core/groups.html b/biscuit/core/templates/core/groups.html
new file mode 100644
index 0000000000000000000000000000000000000000..fbcadfbb5efde537c75269d37c560799b93ff51e
--- /dev/null
+++ b/biscuit/core/templates/core/groups.html
@@ -0,0 +1,14 @@
+{% extends "core/base.html" %}
+{% load bootstrap4 i18n %}
+{% load render_table from django_tables2 %}
+
+{% block page_title %}{% blocktrans %}Groups{% endblocktrans %}{% endblock %}
+
+{% block content %}
+ <h2>
+  {% blocktrans %}List of all groups{% endblocktrans %}
+ </h2>
+
+ {% render_table groups_table %}
+
+{% endblock %}
diff --git a/biscuit/core/urls.py b/biscuit/core/urls.py
index f3688a3685379612a93de7da9483634b9240bfbd..47e3dcba81a93d7816525f59a2fa3075d65c6a28 100644
--- a/biscuit/core/urls.py
+++ b/biscuit/core/urls.py
@@ -15,6 +15,9 @@ urlpatterns = [
          {'template': 'full'}, name='person_by_id'),
     path('person/<int:id_>/card', views.person,
          {'template': 'card'}, name='person_by_id_card'),
+    path('groups', views.groups, name='groups'),
+    path('group/<int:id_>', views.group,
+         {'template': 'full'}, name='group_by_id'),
     path('', views.index, name='index'),
 ]
 
diff --git a/biscuit/core/views.py b/biscuit/core/views.py
index 9ece571c01078c54d8d7a0e42b6b0190066051db..0a83c17766fddda7ce4ca6d7baf62f6d546e7b79 100644
--- a/biscuit/core/views.py
+++ b/biscuit/core/views.py
@@ -2,8 +2,8 @@ from django.contrib.auth.decorators import login_required
 from django.http import Http404
 from django.shortcuts import render
 from django_tables2 import RequestConfig
-from .models import Person
-from .tables import PersonsTable
+from .models import Person, Group
+from .tables import PersonsTable, GroupsTable
 
 
 def index(request):
@@ -40,3 +40,43 @@ def person(request, id_, template):
     context['person'] = person
 
     return render(request, 'core/person_%s.html' % template, context)
+
+@login_required
+def group(request, id_, template):
+    context = {}
+
+    # Get group and check if it exist
+    try:
+        group = Group.objects.get(pk=id_)
+    except Group.DoesNotExist as e:
+        # Turn not-found object into a 404 error
+        raise Http404 from e
+
+    context['group'] = group
+
+    # Get group
+    group = Group.objects.get(pk=id_)
+
+    # Get members
+    persons = group.members
+
+    # Build table
+    persons_table = PersonsTable(persons)
+    RequestConfig(request).configure(persons_table)
+    context['persons_table'] = persons_table
+
+    return render(request, 'core/group_%s.html' % template, context)
+
+@login_required
+def groups(request):
+    context = {}
+
+    # Get all groups
+    groups = Group.objects.all()
+
+    # Build table
+    groups_table = GroupsTable(groups)
+    RequestConfig(request).configure(groups_table)
+    context['groups_table'] = groups_table
+
+    return render(request, 'core/groups.html', context)