[Django]-Apollo client subscription pass JWT token handled by Django Channels middleware

3๐Ÿ‘

โœ…

I managed to get the token in the consumer payload and inject the user into the context.

from tinga.schema import schema
import channels_graphql_ws
from channels.db import database_sync_to_async
from django.contrib.auth.models import AnonymousUser
from graphql_jwt.utils import jwt_decode
from core.models import User
from channels_graphql_ws.scope_as_context import ScopeAsContext


@database_sync_to_async
def get_user(email):
    try:
        user = User.objects.get(email=email)
        return user

    except User.DoesNotExist:
        return AnonymousUser()


class MyGraphqlWsConsumer(channels_graphql_ws.GraphqlWsConsumer):
    """Channels WebSocket consumer which provides GraphQL API."""
    schema = schema

    # Uncomment to send keepalive message every 42 seconds.
    # send_keepalive_every = 42

    # Uncomment to process requests sequentially (useful for tests).
    # strict_ordering = True

    async def on_connect(self, payload):
        """New client connection handler."""
        # You can `raise` from here to reject the connection.
        print("New client connected!")

        # Create object-like context (like in `Query` or `Mutation`)
        # from the dict-like one provided by the Channels.
        context = ScopeAsContext(self.scope)

        if 'token' in payload:
            # Decode the token
            decoded_data = jwt_decode(payload['token'])

            # Inject the user
            context.user = await get_user(email=decoded_data['email'])

        else:
            context.user = AnonymousUser

And then passing the token in the connectionParams

const wsLink = new WebSocketLink({
  uri: process.env.VUE_APP_WS_GRAPHQL_URL || "ws://0.0.0.0:8000/ws/graphql/",
  options: {
    reconnect: true,
    connectionParams: async () => {
      const { value: authStr } = await Storage.get({ key: "auth" });
      let token;
      if (authStr) {
        const auth = JSON.parse(authStr);
        token = auth.token;
        console.log(token); // So far so good the token is logged.
        return {
          token: token,
        };
      }

      return {};
    },
  },
});
๐Ÿ‘คBrieuc

Leave a comment