diff --git a/apps/api/viewsets.py b/apps/api/viewsets.py
index 97acac139efb7b3fb012add107864993402bab72..faeadee1f5f9b15cf646c600fed36f514328fa09 100644
--- a/apps/api/viewsets.py
+++ b/apps/api/viewsets.py
@@ -24,7 +24,6 @@ class ReadProtectedModelViewSet(ModelViewSet):
         self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
 
     def get_queryset(self):
-        self.request.session.setdefault("permission_mask", 42)
         return self.queryset.filter(PermissionBackend.filter_queryset(self.request, self.model, "view")).distinct()
 
 
@@ -38,7 +37,6 @@ class ReadOnlyProtectedModelViewSet(ReadOnlyModelViewSet):
         self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
 
     def get_queryset(self):
-        self.request.session.setdefault("permission_mask", 42)
         return self.queryset.filter(PermissionBackend.filter_queryset(self.request, self.model, "view")).distinct()
 
 
diff --git a/apps/logs/signals.py b/apps/logs/signals.py
index 4a6f9015e9536d6fc1d4e22f718a6b12cf7651da..a3166eed00a3445f8f75044cda105597566640e3 100644
--- a/apps/logs/signals.py
+++ b/apps/logs/signals.py
@@ -83,7 +83,7 @@ def save_object(sender, instance, **kwargs):
             ip = request.META.get('REMOTE_ADDR')
 
         if not user.is_authenticated:
-            # For registration purposes
+            # For registration and OAuth2 purposes
             user = None
 
     # noinspection PyProtectedMember
@@ -160,6 +160,10 @@ def delete_object(sender, instance, **kwargs):
         else:
             ip = request.META.get('REMOTE_ADDR')
 
+        if not user.is_authenticated:
+            # For registration and OAuth2 purposes
+            user = None
+
     # On crée notre propre sérialiseur JSON pour pouvoir sauvegarder les modèles
     class CustomSerializer(ModelSerializer):
         class Meta:
diff --git a/apps/note/api/views.py b/apps/note/api/views.py
index e4f7404c8be7657e154ac037479ade705d404e01..4342b666cb37084762a2ee73e66ad03a3173014c 100644
--- a/apps/note/api/views.py
+++ b/apps/note/api/views.py
@@ -39,7 +39,6 @@ class NotePolymorphicViewSet(ReadProtectedModelViewSet):
         Parse query and apply filters.
         :return: The filtered set of requested notes
         """
-        self.request.session.setdefault("permission_mask", 42)
         queryset = self.queryset.filter(PermissionBackend.filter_queryset(self.request, Note, "view")
                                         | PermissionBackend.filter_queryset(self.request, NoteUser, "view")
                                         | PermissionBackend.filter_queryset(self.request, NoteClub, "view")
@@ -204,6 +203,5 @@ class TransactionViewSet(ReadProtectedModelViewSet):
     ordering_fields = ['created_at', 'amount', ]
 
     def get_queryset(self):
-        self.request.session.setdefault("permission_mask", 42)
         return self.model.objects.filter(PermissionBackend.filter_queryset(self.request, self.model, "view"))\
             .order_by("created_at", "id")
diff --git a/apps/permission/backends.py b/apps/permission/backends.py
index b4c08efd0f9c1144bb5b9c91a4450cf552b99745..7883b4277ba735b89525265a65131739bad5c608 100644
--- a/apps/permission/backends.py
+++ b/apps/permission/backends.py
@@ -26,14 +26,31 @@ class PermissionBackend(ModelBackend):
 
     @staticmethod
     @memoize
-    def get_raw_permissions(user, t):
+    def get_raw_permissions(request, t):
         """
         Query permissions of a certain type for a user, then memoize it.
-        :param user: The owner of the permissions
+        :param request: The current request
         :param t: The type of the permissions: view, change, add or delete
         :return: The queryset of the permissions of the user (memoized) grouped by clubs
         """
-        if not user.is_authenticated:
+        if hasattr(request, 'auth') and request.auth is not None and hasattr(request.auth, 'scope'):
+            # OAuth2 Authentication
+            user = request.auth.user
+
+            def permission_filter(membership_obj):
+                query = Q(pk=-1)
+                for scope in request.auth.scope.split(' '):
+                    permission_id, club_id = scope.split('_')
+                    if int(club_id) == membership_obj.club_id:
+                        query |= Q(pk=permission_id)
+                return query
+        else:
+            user = request.user
+
+            def permission_filter(membership_obj):
+                return Q(mask__rank__lte=request.session.get("permission_mask", -1))
+
+        if user.is_anonymous:
             # Unauthenticated users have no permissions
             return Permission.objects.none()
 
@@ -43,8 +60,7 @@ class PermissionBackend(ModelBackend):
 
         for membership in memberships:
             for role in membership.roles.all():
-                for perm in role.permissions.filter(
-                        type=t, mask__rank__lte=get_current_request().session.get("permission_mask", -1)).all():
+                for perm in role.permissions.filter(permission_filter(membership), type=t).all():
                     if not perm.permanent:
                         if membership.date_start > date.today() or membership.date_end < date.today():
                             continue
@@ -53,16 +69,22 @@ class PermissionBackend(ModelBackend):
         return perms
 
     @staticmethod
-    def permissions(user, model, type):
+    def permissions(request, model, type):
         """
         List all permissions of the given user that applies to a given model and a give type
-        :param user: The owner of the permissions
+        :param request: The current request
         :param model: The model that the permissions shoud apply
         :param type: The type of the permissions: view, change, add or delete
         :return: A generator of the requested permissions
         """
 
-        for permission in PermissionBackend.get_raw_permissions(user, type):
+        if hasattr(request, 'auth') and request.auth is not None and hasattr(request.auth, 'scope'):
+            # OAuth2 Authentication
+            user = request.auth.user
+        else:
+            user = request.user
+
+        for permission in PermissionBackend.get_raw_permissions(request, type):
             if not isinstance(model.model_class()(), permission.model.model_class()) or not permission.membership:
                 continue
 
@@ -98,13 +120,17 @@ class PermissionBackend(ModelBackend):
         :param field: The field of the model to test, if concerned
         :return: A query that corresponds to the filter to give to a queryset
         """
-        user = request.user
-
-        if user is None or not user.is_authenticated:
-            # Anonymous users can't do anything
+        if hasattr(request, 'auth') and request.auth is not None and hasattr(request.auth, 'scope'):
+            # OAuth2 Authentication
+            user = request.auth.user
+        else:
+            user = request.user
+
+        if user is None or user.is_anonymous:
+            # Anonymous users can't do asetdefaultnything
             return Q(pk=-1)
 
-        if user.is_superuser and get_current_request().session.get("permission_mask", -1) >= 42:
+        if user.is_superuser and request.session.get("permission_mask", -1) >= 42:
             # Superusers have all rights
             return Q()
 
@@ -113,7 +139,7 @@ class PermissionBackend(ModelBackend):
 
         # Never satisfied
         query = Q(pk=-1)
-        perms = PermissionBackend.permissions(user, model, t)
+        perms = PermissionBackend.permissions(request, model, t)
         for perm in perms:
             if perm.field and field != perm.field:
                 continue
@@ -134,11 +160,14 @@ class PermissionBackend(ModelBackend):
         (e.g. for a transaction, the balance of the user could change)
         """
         user_obj = request.user
+        sess = request.session
 
-        if user_obj is None or not user_obj.is_authenticated:
-            return False
+        if hasattr(request, 'auth') and request.auth is not None and hasattr(request.auth, 'scope'):
+            # OAuth2 Authentication
+            user_obj = request.auth.user
 
-        sess = request.session
+        if user_obj is None or user_obj.is_anonymous:
+            return False
 
         if user_obj.is_superuser and sess.get("permission_mask", -1) >= 42:
             return True
@@ -152,7 +181,7 @@ class PermissionBackend(ModelBackend):
 
         ct = ContentType.objects.get_for_model(obj)
         if any(permission.applies(obj, perm_type, perm_field)
-               for permission in PermissionBackend.permissions(user_obj, ct, perm_type)):
+               for permission in PermissionBackend.permissions(request, ct, perm_type)):
             return True
         return False
 
@@ -167,4 +196,4 @@ class PermissionBackend(ModelBackend):
 
     def get_all_permissions(self, user_obj, obj=None):
         ct = ContentType.objects.get_for_model(obj)
-        return list(self.permissions(user_obj, ct, "view"))
+        return list(self.permissions(get_current_request(), ct, "view"))
diff --git a/apps/permission/signals.py b/apps/permission/signals.py
index 2e4d6ea94e9a7e3cd0a29a12c833d231d3dfcc08..78d0b8f98a52c9017c85fc176cc73d3beb614718 100644
--- a/apps/permission/signals.py
+++ b/apps/permission/signals.py
@@ -16,6 +16,9 @@ EXCLUDED = [
     'contenttypes.contenttype',
     'logs.changelog',
     'migrations.migration',
+    'oauth2_provider.accesstoken',
+    'oauth2_provider.grant',
+    'oauth2_provider.refreshtoken',
     'sessions.session',
 ]