Skip to content

Commit

Permalink
Merge pull request #115 from ahopkins/dev
Browse files Browse the repository at this point in the history
Version 1.1.2 - 2018-06-18
  • Loading branch information
ahopkins committed Jun 18, 2018
2 parents facb6f6 + b49a8fe commit 2ea96d4
Show file tree
Hide file tree
Showing 12 changed files with 413 additions and 6 deletions.
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
# The short X.Y version.
version = u"1.1"
# The full version, including alpha/beta/rc tags.
release = u"1.1.1"
release = u"1.1.2"

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
8 changes: 8 additions & 0 deletions docs/source/pages/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Changelog

The format is based on `Keep a Changelog <http://keepachangelog.com/en/1.0.0/>`_ and this project adheres to `Semantic Versioning <http://semver.org/spec/v2.0.0.html>`_.

++++++++++++++++++++++++++
Version 1.1.2 - 2018-06-18
++++++++++++++++++++++++++

| **Added**
| - Ability to send authorization tokens via query string parameters
|
++++++++++++++++++++++++++
Version 1.1.1 - 2018-06-14
++++++++++++++++++++++++++
Expand Down
34 changes: 33 additions & 1 deletion docs/source/pages/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ Settings
``cookie_set``
--------------

| **Purpose**: By default, the application will lookie for access tokens in the HTTP request headers. If you would instead prefer to send them through cookies, enable this to ``True``.
| **Purpose**: By default, the application will look for access tokens in the HTTP request headers. If you would instead prefer to send them through cookies, enable this to ``True``.
| **Default**: ``False``
|
Expand Down Expand Up @@ -345,6 +345,38 @@ Alias for ``cookie_access_token_name``

Alias for ``secret``

----------------------------------
``query_string_access_token_name``
----------------------------------

| **Purpose**: The name of the cookie to be set for storing the refresh token if using query string based authentication.
| **Default**: ``'access_token'``
|
-----------------------------------
``query_string_refresh_token_name``
-----------------------------------

| **Purpose**: The name of the cookie to be set for storing the refresh token if using query string based authentication.
| **Default**: ``'refresh_token'``
|
--------------------
``query_string_set``
--------------------

| **Purpose**: By default, the application will look for access tokens in the HTTP request headers. If you would instead prefer to send them as a URL query string, enable this to ``True``.
| **Default**: ``False``
|
-----------------------
``query_string_strict``
-----------------------

| **Purpose**: If ``query_string_set`` is enabled, an exception will be raised if the query string is not present. To allow for an authorization header to be used as a fallback, turn ``query_string_strict`` to ``False``.
| **Default**: ``True``
|
-------------------------
``refresh_token_enabled``
-------------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/source/pages/endpoints.rst
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ What if we wanted a ``/register`` endpoint? It could easily be added like this:
refresh_token = await self.instance.auth.get_refresh_token(request, user)
output.update({
self.config.refresh_token_name: refresh_token
self.config.refresh_token_name(): refresh_token
})
response = self.responses.get_token_reponse(
Expand Down
18 changes: 17 additions & 1 deletion docs/source/pages/protected.rst
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ Now, Sanic JWT will reject any request that does not have a valid access token i

| ``cookie_domain`` - changes domain associated with a cooke (defaults to '')
| ``cookie_httponly`` - whether to set an httponly flag on the cookie (defaults to ``True``)
| ``cookie_access_token_name`` - the name where the cookie is stored
| ``cookie_access_token_name`` - the name where the cookie is stored for access token
| ``cookie_refresh_token_name`` - the name where the cookie is stored for refresh token
|
.. code-block:: python
Expand All @@ -143,6 +144,21 @@ Now, Sanic JWT will reject any request that does not have a valid access token i
If you are using cookies to pass JWTs, then it is recommended that you do **not** disable ``cookie_httponly``. Doing so means that any javascript running on the client can access the token. Bad news.


~~~~~~~~~~~~~~~~~~~
Query String Tokens
~~~~~~~~~~~~~~~~~~~

Sometimes, both header based authentication and cookie based authentication will not be enough. A third option is available to look for tokens inside query string arguments:

http://localhost?access_token=<JWT>

This can be enabled with ``query_string_set=True``. One potential use for this would be authentication of a websocket endpoint where sending headers and cookies may be more challenging due to Javascript limitations.

.. warning::

In most scenarios, it is advisable to **not** use query strings for authentication. One of the biggest reasons is that the tokens may be easily leaked if a URL is copied and pasted, or because the token may end up in server logs. However, the option is available if you need it and you feel comfortable that you can mitigate any risks.


~~~~~~~~~~~~~~~~~~~~~~
Both Header and Cookie
~~~~~~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion sanic_jwt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "1.1.0"
__version__ = "1.1.2"
__author__ = "Adam Hopkins"
__credits__ = "Richard Kuesters"

Expand Down
22 changes: 22 additions & 0 deletions sanic_jwt/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,19 @@ def _get_token_from_headers(self, request, refresh_token):

return token

def _get_token_from_query_string(self, request, refresh_token):
"""
Extract the token if present from the request args.
"""
if refresh_token:
query_string_token_name_key = "query_string_refresh_token_name"
else:
query_string_token_name_key = "query_string_access_token_name"
query_string_token_name = getattr(
self.config, query_string_token_name_key
)
return request.raw_args.get(query_string_token_name(), None)

def _get_token(self, request, refresh_token=False):
"""
Extract a token from a request object.
Expand All @@ -258,6 +271,15 @@ def _get_token(self, request, refresh_token=False):
if self.config.cookie_strict():
raise exceptions.MissingAuthorizationCookie()

if self.config.query_string_set():
token = self._get_token_from_query_string(request, refresh_token)
if token is not None:
return token

else:
if self.config.query_string_strict():
raise exceptions.MissingAuthorizationQueryArg()

token = self._get_token_from_headers(request, refresh_token)
if token is not None:
return token
Expand Down
4 changes: 4 additions & 0 deletions sanic_jwt/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
"path_to_retrieve_user": "/me",
"path_to_verify": "/verify",
"private_key": None,
"query_string_access_token_name": "access_token",
"query_string_refresh_token_name": "refresh_token",
"query_string_set": False,
"query_string_strict": True,
"refresh_token_enabled": False,
"refresh_token_name": "refresh_token",
"scopes_enabled": False,
Expand Down
9 changes: 9 additions & 0 deletions sanic_jwt/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ def __init__(self, message="Authorization cookie not present.", **kwargs):
super().__init__(message, **kwargs)


class MissingAuthorizationQueryArg(SanicJWTException):
status_code = 400

def __init__(
self, message="Authorization query argument not present.", **kwargs
):
super().__init__(message, **kwargs)


class InvalidAuthorizationHeader(SanicJWTException):
status_code = 400

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

setup(
name="sanic-jwt",
version="1.1.1",
version="1.1.2",
description="JWT oauth flow for Sanic",
url="https://github.com/ahopkins/sanic-jwt",
download_url="https://github.com/ahopkins/sanic-jwt/archive/master.zip",
Expand Down
2 changes: 2 additions & 0 deletions tests/test_endpoints_cookies.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ def test_using_token_as_header_strict(
},
)

assert response.status == 400

_, response = sanic_app.test_client.get(
"/protected",
cookies={
Expand Down

0 comments on commit 2ea96d4

Please sign in to comment.