Skip to content
This repository has been archived by the owner on May 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #275 from sangoma/feature/jwt-auth-cookie-issue-120
Browse files Browse the repository at this point in the history
Allow using a cookie as a transport for the token
  • Loading branch information
jpadilla authored Mar 1, 2017
2 parents 2ec4fc7 + 947dde2 commit 9b9735c
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 4 deletions.
12 changes: 11 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion rest_framework_jwt/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions rest_framework_jwt/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 10 additions & 2 deletions rest_framework_jwt/views.py
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down Expand Up @@ -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)

Expand Down

0 comments on commit 9b9735c

Please sign in to comment.