.. _authentication-permissions: Authentication/Permissions ========================== Description ----------- Authentication and permissions are **handled in the same way** as in DRF. In this in mind you logically can have project-wide default authentication and authorization classes and / or service-specific ones. please refer to : - `DRF Permissions `_ - `DRF Authentication `_ However, there are a couple of details that add behavior to default DRF ``Permission`` / ``Authentication`` classes. For instance, :func:`auth_without_session_middleware` (see: :ref:`middlewares ` ) will call the service :func:`perform_authentication` method which will inject ``user`` into ``context`` arg accessible to service methods and permission classes. The :func:`perform_authentication` will then call all the :func:`authentication_classes` of the service as in DRF to try to authenticate user. The distinction is simple however it's worth to note that while django-rest-framework `BasePermission `_ will have ``request, view`` as args, DSG ``GRPCActionBasePermission`` (that inherits from django-rest-framework `BasePermission `_) will have ``context`` (:func:`GRPCInternalProxyContext`), ``service`` (:func:`Service`) args instead Authentication Example ---------------------- To specify an Authentication methods there is two ways as in DRF: - Globaly, by settings the :ref:`DEFAULT_AUTHENTICATION_CLASSE` settings .. code-block:: python GRPC_FRAMEWORK = { ... # oidc_auth package comes from https://github.com/ByteInternet/drf-oidc-auth # If you want to use an other auth package and having issue using it please open an issue we will be happy to help "DEFAULT_AUTHENTICATION_CLASSES": ["oidc_auth.authentication.JSONWebTokenAuthentication"], ... } - By service, by settings the :func:`authentication_classes` attributes: .. code-block:: python # oidc_auth package comes from https://github.com/ByteInternet/drf-oidc-auth # If you want to use an other auth package and having issue using it please open an issue we will be happy to help from oidc_auth.authentication import JSONWebTokenAuthentication from rest_framework.permissions import IsAuthenticated from django_socio_grpc.generics import AsyncModelService class ExampleService(AsyncModelService): authentication_classes = [JSONWebTokenAuthentication] permission_classes = [IsAuthenticated] Permission Example ------------------ .. code-block:: python from django_socio_grpc.permissions import GRPCActionBasePermission from django_socio_grpc.generics import AsyncModelService from rest_framework.permissions import SAFE_METHODS class OnlySafeOrAdminOrOwner(GRPCActionBasePermission): def has_permission(self, context, service): if self.context.method in SAFE_METHODS: return True if context.grpc_action == "SomeCustomSafeEndpoint": return True return context.user.is_superuser def has_object_permission(self, context, service, obj): if self.context.method in SAFE_METHODS: return True if str(obj.created_by) == str(request.user.pk): return True return context.user.is_superuser class ExampleService(AsyncModelService): permission_classes = [OnlySafeOrAdminOrOwner] Python Client Example --------------------- To use the authentication system in our client you need to pass the the value of the headers as you would do in classic DRF in the metadata ``headers`` key (See :ref:`settings for key configuration`): .. code-block:: python :emphasize-lines: 10,13 import json import asyncio import grpc from datetime import datetime from myapp.grpc import my_app_pb2_grpc, my_app_pb2 async def main(): async with grpc.aio.insecure_channel("localhost:50051") as channel: my_service_client = my_app_pb2_grpc.MyServiceControllerStub(channel) metadata = (("headers", json.dumps({"Authorization": "faketoken"})),) request = my_app_pb2.MyServiceListRequest() response = await my_service_client.List(request, metadata=metadata) if __name__ == "__main__": asyncio.run(main()) Web Client Example ------------------ See :ref:`gRPC-web Documentation page ` for more information. .. code-block:: Javascript :emphasize-lines: 12,17 import { MyServiceController } from '../gen/example_bib_app_connect' import { createPromiseClient } from "@connectrpc/connect"; import { createGrpcWebTransport } from "@connectrpc/connect-web"; const transport = createGrpcWebTransport({ baseUrl: "http://localhost:9001", }); const authorClient = createPromiseClient(MyServiceController, transport); let headers = {"headers": JSON.stringify({"Authorization": "faketoken"})} // See https://connectrpc.com/docs/web/headers-and-trailers const res = await authorClient.list( {}, {headers: headers} ) console.log(res) let items = res.results