Skip to content

Permissions🔗

Permissions classes🔗

Implements graphene-permissions style permission classes.

These methods can be overridden in subclasses to implement custom permissions:

has_permission🔗

  • args:
    • user: User | AnonymousUser

This is the main method for checking permissions. has_node_permission, has_filter_permission, and has_mutation_permission will default to this if not overridden.

has_node_permission🔗

  • args:
    • instance: Model
    • user: User | AnonymousUser
    • filters: dict[str, Any]

Override this method to add specific permissions to a node field defined for a DjangoNode.

has_filter_permission🔗

  • args:
    • user: User | AnonymousUser
    • filters: dict[str, Any]

Override this method to add specific permissions to a list or connections fields defined for a DjangoNode.

has_mutation_permission🔗

  • args:
    • user: User | AnonymousUser
    • input_data: dict[str, Any]

Override this method to add specific permissions to all mutations. has_create_permission, has_update_permission, and has_delete_permission will default to this if not overridden.

has_create_permission🔗

  • args:
    • user: User | AnonymousUser
    • input_data: dict[str, Any]

Override this method to add specific permissions to a create mutation defined by CreateMutation.

has_update_permission🔗

  • args:
    • instance: Model
    • user: User | AnonymousUser
    • input_data: dict[str, Any]

Override this method to add specific permissions to an update mutation defined by UpdateMutation.

has_delete_permission🔗

  • args:
    • instance: Model
    • user: User | AnonymousUser
    • input_data: dict[str, Any]

Override this method to add specific permissions to a delete mutation defined by DeleteMutation.

Typing🔗

BasePermission is generic over the model and the user type. Without subscription, the model is Model and the user is User | AnonymousUser, as in the method arguments above. Subscribe the class to type the methods for a specific model and user, for example when the project uses a custom user model:

1
2
3
4
5
6
7
from graphene_django_extensions.permissions import BasePermission


class ExamplePermission(BasePermission[Example, MyUser]):
    @classmethod
    def has_update_permission(cls, instance: Example, user: MyUser, input_data: dict[str, Any]) -> bool:
        return user.is_staff

To avoid repeating the user type, make a project base class that only takes the model:

1
2
3
4
5
6
7
8
from django.db.models import Model
from graphene_django_extensions import permissions


class BasePermission[TModel: Model](permissions.BasePermission[TModel, MyUser]): ...


class ExamplePermission(BasePermission[Example]): ...

Restricted fields🔗

To add more fine-grained permissions to individual fields, the restricted_field decorator can be used on field resolvers. This will perform the permission check before the resolver is called, and raise an exception if the permission check fails.

There are two allowed interfaces for permissions checks:

def permission_check(user: User | AnonymousUser) -> bool: ...

or

def permission_check(user: User | AnonymousUser, instance: Model) -> bool: ...

...where the instance is the instance of the model that the field resolver is being called on. The user and the model can be any type. When restricted_field is used as a decorator, the types are taken from the permission check.

When using DjangoNode, the Meta.restricted_fields option can be used to add permission checks without having to use the decorator on each field resolver.

from graphene_django_extensions import DjangoNode
from graphene_django_extensions.permissions import restricted_field


class ExampleNode(DjangoNode):
    class Meta:
        model = Example
        fields = ["example_field"]
        # Option 1
        restricted_fields = {
            "example_field": lambda user: user.is_authenticated,
        }

    # Option 2
    @restricted_field(lambda user: user.is_authenticated)
    def resolve_example_field(root: Example, info: GQLInfo):
        return root.example_field

Field permissions will return errors in the following format:

{
    "errors": [
        {
            "message": "No permission to access field.",
            "path":  ["examples", "edges", 0, "node", "email"],
            "extensions": {"code": "FIELD_PERMISSION_DENIED"},
            "locations": [{"column": 38, "line": 1}]
        }
    ]
}

The message and code can be changed using the following settings:

Message setting Message default Code setting Code default
FIELD_PERMISSION_ERROR_MESSAGE No permission to access field. FIELD_PERMISSION_ERROR_CODE FIELD_PERMISSION_DENIED