Last active
December 7, 2023 01:18
-
-
Save evandempsey/2cb349ce3aa9acc47183edb423ce8222 to your computer and use it in GitHub Desktop.
Setting up token authentication for Shopify App Bridge embedded apps in Django with Django Rest Framework
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Put the following in shopify_app.authentication.py. This assumes we have a | |
# custom User model in shopify_app.models with a unique myshopify_domain | |
# attribute. The Shopify app API key and shared secret are imported from | |
# settings.py. | |
import datetime | |
import jwt | |
from datetime import timezone | |
from rest_framework import authentication | |
from rest_framework import exceptions | |
from shopify_app.models import ( | |
ShopUser | |
) | |
from shopify_app.settings import ( | |
API_KEY, | |
SHARED_SECRET | |
) | |
class ShopifyAppBridgeAuthentication(authentication.BaseAuthentication): | |
def authenticate(self, request): | |
# Verify that the header exists and contains a token. | |
token = request.META.get('HTTP_AUTHORIZATION') | |
if not token or 'Bearer' not in token: | |
return None | |
# Extract the JWT token. | |
exploded = token.split(' ') | |
if len(exploded) != 2: | |
return None | |
# Decode the JWT token with PyJWT. | |
decoded = jwt.decode(exploded[1], SHARED_SECRET, | |
audience=API_KEY, algorithms=["HS256"]) | |
# Verify that the token is not expired. | |
now = datetime.datetime.now() | |
timestamp = now.replace(tzinfo=timezone.utc).timestamp() | |
if not decoded['nbf'] <= timestamp <= decoded['exp']: | |
raise exceptions.AuthenticationFailed('Token is expired.') | |
try: | |
myshopify_domain = decoded["dest"].replace("https://", "") | |
user = ShopUser.objects.get(myshopify_domain=myshopify_domain) | |
except ShopUser.DoesNotExist: | |
raise exceptions.AuthenticationFailed('No such user.') | |
return user, None | |
# Then in views.py, if we want to create a Django Rest Framework | |
# ModelViewSet for a model called ShopModel, we could do something | |
# like this. | |
class ShopModelViewSet(ModelViewSet): | |
serializer_class = ShopModelSerializer | |
authentication_classes = [ShopifyAppBridgeAuthentication] | |
permission_classes = [IsAuthenticated] | |
def get_queryset(self): | |
return ShopModel.objects.filter(user=request.user) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment