Endpoints and Responses

Sanic JWT sets itself up to run as a Sanic Blueprint at the /auth path.

http://localhost:8000/auth

This is can be changed via the url_prefix setting. See settings for more.

Initialize(app, url_prefix='/api/authentication')

All Sanic JWT endpoints will now be available at:

http://localhost:8000/api/authentication

Default Endpoints

By default, there are four endpoints that ship with Sanic JWT. You can change the path that they attach to by following configuration pattern below:

Initialize(
    app,
    path_to_authenticate='/my_authenticate',
    path_to_retrieve_user='/my_retrieve_user',
    path_to_verify='/my_verify',
    path_to_refresh='/my_refresh',
)

Authenticate

Default Path: /auth
Acceptable Methods: POST
Purpose: Generates an access token if the authenticate method is truthy.
Example:

Request

curl -X POST -H "Content-Type: application/json" -d '{"username": "<USERNAME>", "password": "<PASSWORD>"}' http://localhost:8000/auth

Response

200 Response
{
    "access_token": "<JWT>"

Verification

Default Path: /auth/verify
Acceptable Methods: GET
Purpose: Check whether or not a given access token is valid.
Example:

Request

curl -X GET -H "Authorization: Bearer <JWT>" http://localhost:8000/auth/verify

Response

200 Response
{
    "valid": true
}

## or

400 Response
{
    "valid": false,
    "reason": "Signature has expired"
}

Current User Details

Default Path: /auth/me
Acceptable Methods: GET
Purpose: Retrieve information about the currently authenticated user.
Example:

Request

curl -X GET -H "Authorization: Bearer <JWT>" http://localhost:8000/auth/me

Response

200 Response
{
    "user_id": 123456
}

Note

Because this package does not know about you user management layer, you need to have a user object that either is a dict or a python object instance with a to_dict() method. The output of these methods will be used to generate the /me response.

Refresh Token

Default Path: /auth/refresh
Acceptable Methods: POST
Purpose: Ask for a new access token given an existing refresh token
Example:

Request

curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer <JWT>" -d '{"refresh_token": "<REFRESH TOKEN>"}' http://localhost:8000/auth/refresh

Response

{
    "access_token": "<JWT>"
}

Note

Do not forget to supply an existing access_token. Even if it is expired, you must send the token along so that the application can get the user_id from the token’s payload and cross reference it with the refresh_token. Think of it as an additional level of security. To understand why, checkout Issue #52.


Modify Responses

The responses for each of the default endpoints is extendable by subclassing the Responses class, and hooking into the appropriate method. Just make sure you return a dict.

from sanic_jwt import Responses

class MyResponses(Responses):
    @staticmethod
    def extend_authenticate(request,
                            user=None,
                            access_token=None,
                            refresh_token=None):
        return {}

    @staticmethod
    def extend_retrieve_user(request, user=None, payload=None):
        return {}

    @staticmethod
    def extend_verify(request, user=None, payload=None):
        return {}

    @staticmethod
    def extend_refresh(request,
                       user=None,
                       access_token=None,
                       refresh_token=None,
                       purported_token=None,
                       payload=None):
        return {}

Initialize(app, response_class=MyResponses)

Custom Endpoints

Sometimes you may find the need to add another endpoint to your authentication system. You can do this by hooking it up at initialization.

from sanic_jwt import BaseEndpoint

class MyEndpoint(BaseEndpoint):
    ...

my_views = (
    ('/my-view', MyEndpoint),
)

Initialize(app, class_views=my_views)

Example:

What if we wanted a /register endpoint? It could easily be added like this:

from sanic_jwt import BaseEndpoint

class Register(BaseEndpoint):
    async def post(self, request, *args, **kwargs):
        username = request.json.get('username', None)
        email = request.json.get('email', None)

        helper = MyCustomUserAuthHelper()
        user = helper.register_new_user(username, email)

        access_token, output = await self.responses.get_access_token_output(
            request,
            user,
            self.config,
            self.instance)

        refresh_token = await self.instance.auth.get_refresh_token(request, user)
        output.update({
            self.config.refresh_token_name: refresh_token
        })

        response = self.responses.get_token_reponse(
            request,
            access_token,
            output,
            refresh_token=refresh_token,
            config=self.config)


        return response

my_views = (
    ('/register', Register),
)

Initialize(app, class_views=my_views)

You hook up your custom endpoints at initialization by providing Initialize with a class_views argument naming your endpoint and its path.

my_endpoints = (
    ('/path/to/endpoint', MyCustomClassBasedView)
)

Note

It must be a class based view. While it is certainly possible to subclass Sanic’s sanic.views.HTTPMethodView, it is recommended that you subclass sanic_jwt.BaseEndpoint instead so you have access to:

  • self.instance (the current Sanic JWT),
  • self.config (all current configurations), and
  • self.responses (the current response class instance).

Exception Handling

You can customize how Sanic JWT handles responses on an exception by subclassing the Responses class, and overriding exception_response.

from sanic_jwt import Responses

class MyResponses(Responses):
@staticmethod
def exception_response(request, exception):
    exception_message = str(exception)
    return json({
        'error': True,
        'message': f'You encountered an exception: {exception_message}'
    }, status=exception.status_code)

Initialize(app, response_class=MyResponses)