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¶
/auth
POST
authenticate
method is truthy.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¶
/auth/verify
GET
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¶
/auth/me
GET
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¶
/auth/refresh
POST
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), andself.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)