diff --git a/docs/index.md b/docs/index.md index df3d9a4c..5d96031f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -177,6 +177,7 @@ JWT_AUTH = { 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7), 'JWT_AUTH_HEADER_PREFIX': 'JWT', + 'JWT_AUTH_COOKIE': None, } ``` This packages uses the JSON Web Token Python implementation, [PyJWT](https://github.com/jpadilla/pyjwt) and allows to modify some of it's available options. @@ -276,9 +277,18 @@ Another common value used for tokens and Authorization headers is `Bearer`. Default is `JWT`. +### JWT_AUTH_COOKIE +You can set this to a string if you want to use http cookies in addition to the Authorization header as a valid transport for the token. +The string you set here will be used as the cookie name that will be set in the response headers when requesting a token. The token validation +procedure will also look into this cookie, if set. The 'Authorization' header takes precedence if both the header and the cookie are present in the request. + +Another common value used for tokens and Authorization headers is `Bearer`. + +Default is `None` and no cookie is set when creating tokens nor accepted when validating them. + ## Extending `JSONWebTokenAuthentication` -Right now `JSONWebTokenAuthentication` assumes that the JWT will come in the header. The JWT spec does not require this (see: [Making a service Call](https://developer.atlassian.com/static/connect/docs/concepts/authentication.html)). For example, the JWT may come in the querystring. The ability to send the JWT in the querystring is needed in cases where the user cannot set the header (for example the src element in HTML). +Right now `JSONWebTokenAuthentication` assumes that the JWT will come in the header, or a cookie if configured (see [JWT_AUTH_COOKIE](#JWT_AUTH_COOKIE)). The JWT spec does not require this (see: [Making a service Call](https://developer.atlassian.com/static/connect/docs/concepts/authentication.html)). For example, the JWT may come in the querystring. The ability to send the JWT in the querystring is needed in cases where the user cannot set the header (for example the src element in HTML). To achieve this functionality, the user might write a custom `Authentication`: ```python diff --git a/rest_framework_jwt/authentication.py b/rest_framework_jwt/authentication.py index 71e2c580..86b50b90 100644 --- a/rest_framework_jwt/authentication.py +++ b/rest_framework_jwt/authentication.py @@ -82,7 +82,12 @@ def get_jwt_value(self, request): auth = get_authorization_header(request).split() auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower() - if not auth or smart_text(auth[0].lower()) != auth_header_prefix: + if not auth: + if api_settings.JWT_AUTH_COOKIE: + return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE) + return None + + if smart_text(auth[0].lower()) != auth_header_prefix: return None if len(auth) == 1: diff --git a/rest_framework_jwt/settings.py b/rest_framework_jwt/settings.py index da742b84..254942c5 100644 --- a/rest_framework_jwt/settings.py +++ b/rest_framework_jwt/settings.py @@ -44,6 +44,7 @@ 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7), 'JWT_AUTH_HEADER_PREFIX': 'JWT', + 'JWT_AUTH_COOKIE': None, } # List of settings that may be in string import notation. diff --git a/rest_framework_jwt/views.py b/rest_framework_jwt/views.py index e34799c2..6f5d1fb9 100644 --- a/rest_framework_jwt/views.py +++ b/rest_framework_jwt/views.py @@ -1,6 +1,7 @@ from rest_framework.views import APIView from rest_framework import status from rest_framework.response import Response +from datetime import datetime from .settings import api_settings from .serializers import ( @@ -57,8 +58,15 @@ def post(self, request, *args, **kwargs): user = serializer.object.get('user') or request.user token = serializer.object.get('token') response_data = jwt_response_payload_handler(token, user, request) - - return Response(response_data) + response = Response(response_data) + if api_settings.JWT_AUTH_COOKIE: + expiration = (datetime.utcnow() + + api_settings.JWT_EXPIRATION_DELTA) + response.set_cookie(api_settings.JWT_AUTH_COOKIE, + response.data['token'], + expires=expiration, + httponly=True) + return response return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)