Repository: saleor/saleor

Issue:
Unhandled exception -- JSONWebTokenExpired: Signature has expired
When `JSONWebTokenExpired` occurs, the exception is not handled. This assumes a crash.

```
ExpiredSignatureError: Signature has expired
  File "graphql_jwt/utils.py", line 86, in get_payload
    payload = jwt_settings.JWT_DECODE_HANDLER(token, context)
  File "graphql_jwt/utils.py", line 45, in jwt_decode
    return jwt.decode(
  File "jwt/api_jwt.py", line 104, in decode
    self._validate_claims(payload, merged_options, **kwargs)
  File "jwt/api_jwt.py", line 134, in _validate_claims
    self._validate_exp(payload, now, leeway)
  File "jwt/api_jwt.py", line 175, in _validate_exp
    raise ExpiredSignatureError('Signature has expired')

JSONWebTokenExpired: Signature has expired
(4 additional frame(s) were not displayed)
...
  File "graphql_jwt/middleware.py", line 72, in resolve
    user = authenticate(request=context, **kwargs)
  File "django/contrib/auth/__init__.py", line 72, in authenticate
    user = backend.authenticate(request, **credentials)
  File "graphql_jwt/backends.py", line 14, in authenticate
    return get_user_by_token(token, request)
  File "graphql_jwt/shortcuts.py", line 20, in get_user_by_token
    payload = get_payload(token, context)
  File "graphql_jwt/utils.py", line 88, in get_payload
    raise exceptions.JSONWebTokenExpired()

An error occurred while resolving field Query.shop
```


Discussion:
There should be only one error but the Graphene JWT library raises two. Maybe we can handle it, I need to check it. To have correct reporting we should probably add these errors to `GraphQLView. HANDLED_EXCEPTIONS`.

Resolving patch:
diff --git a/saleor/graphql/views.py b/saleor/graphql/views.py
--- a/saleor/graphql/views.py
+++ b/saleor/graphql/views.py
@@ -22,7 +22,7 @@
     format_error as format_graphql_error,
 )
 from graphql.execution import ExecutionResult
-from graphql_jwt.exceptions import PermissionDenied
+from graphql_jwt.exceptions import JSONWebTokenError
 
 from ..core.utils import is_valid_ipv4, is_valid_ipv6
 
@@ -58,7 +58,7 @@ class GraphQLView(View):
     middleware = None
     root_value = None
 
-    HANDLED_EXCEPTIONS = (GraphQLError, PermissionDenied)
+    HANDLED_EXCEPTIONS = (GraphQLError, JSONWebTokenError)
 
     def __init__(
         self, schema=None, executor=None, middleware=None, root_value=None, backend=None
diff --git a/saleor/settings.py b/saleor/settings.py
--- a/saleor/settings.py
+++ b/saleor/settings.py
@@ -1,6 +1,7 @@
 import ast
 import os.path
 import warnings
+from datetime import timedelta
 
 import dj_database_url
 import dj_email_url
@@ -473,9 +474,12 @@ def get_host():
 # Django GraphQL JWT settings
 GRAPHQL_JWT = {
     "JWT_PAYLOAD_HANDLER": "saleor.graphql.utils.create_jwt_payload",
+    # How long until a token expires, default is 5m from graphql_jwt.settings
+    "JWT_EXPIRATION_DELTA": timedelta(minutes=5),
+    # Whether the JWT tokens should expire or not
+    # Enabled by default in production mode; disabled in development mode by default
+    "JWT_VERIFY_EXPIRATION": get_bool_from_env("JWT_VERIFY_EXPIRATION", not DEBUG),
 }
-if not DEBUG:
-    GRAPHQL_JWT["JWT_VERIFY_EXPIRATION"] = True  # type: ignore
 
 # CELERY SETTINGS
 CELERY_BROKER_URL = (


Test patch: