Giter VIP home page Giter VIP logo

sanic-jwt's Introduction

Sanic JWT

Latest PyPI version Python versions Version status MIT License

Build Status Documentation Codacy Badge Test Coverage Code style: black

Sanic JWT adds authentication protection and endpoints to Sanic.

It is both easy to get up and running, and extensible for the developer. It can act to protect endpoints and also provide authentication scoping, all wrapped into a nice JWT.

Read the documentation | View the source code


What do I do?

It's easy: (1) install, (2) initialize, and (3) authenticate.

Install:

pip install sanic-jwt

Initialize:

from sanic import Sanic
from sanic_jwt import Initialize

def my_authenticate(request, *args, **kwargs):
    ...

app = Sanic()
Initialize(
    app,
    authenticate=my_authenticate
)

Authenticate:

http://localhost/auth

Can I customize it?

Definitely! Sanic JWT is made to allow developers to customize the operation to fit their needs. Check out the documentation to learn how.

sanic-jwt's People

Contributors

ahopkins avatar amor71 avatar bastiendonjon avatar cr0hn avatar gbnk0 avatar jiamo avatar kerma avatar lizardwizzard avatar luup2k avatar monosans avatar omphe avatar pyup-bot avatar rahulraina7 avatar rubik avatar schneider8357 avatar sirtelemak avatar stefanm8 avatar vltr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sanic-jwt's Issues

Documentation

The README documentation is getting to be too much. Time to start a proper set of documentation to house on RTD.

Custom responses

In #13, @nullpixel said:

Sanic JWT comes with built in endpoints, but they all have set responses, and cannot be overridden as far as I'm aware. Apologies, I should've made the wording clearer.

Currently that is right, there is no way to modify the endpoints without creating a separate Blueprint and just inheriting from sanic_jwt.

I have not tried this, but something like this should work.

from sanic import Blueprint
from sanic_jwt.blueprint import verify
from json import dumps, loads


custom_bp = Blueprint('custom_bp')

@custom_bp.get('/verify')
async def custom_verify(request, *args, **kwargs):
    response = verify(request, *args, **kwargs)
    raw = loads(response.body)
    raw.update({'foo': 'bar'})
    body = dumps(raw)
    response.body = body
    return response

Again, I have not tried this and am not sure if it would work. Also, it would mean your auth endpoints might need to be on separate base URL paths. Not ideal.

I definitely do see the need for potentially needing to extend the functionality here. But, the question would be to what extent?

Right now, I am leaning towards implementing a methodology similar to the payload. There are built in handlers for both building and extending the payload. These can be overwritten using the settings, and are valid as long as they return the necessary key/values. Similarly, we could abstract the auth responses into handlers, and then validate them to make sure the minimum keys are being returned.

Before implementing, some more thought is needed to see exactly what the use cases for this functionality might require.

Newbie doc question

I'm trying to add authentication to a basic web app and its unclear how this works in the real world.

The flow that I'd like is

/index.html has the main application logic. This needs to be protected, but I'd like to redirect over to /login.html if no auth headers are present - to other username/password perform authentication and then redirect back to index.html.

But as soon as I mark the blueprint handler for 'index.html' as @Protected, the exceptions are thrown that there is no authentication header present - thats down in the sanic_jwt library so I don't get to intercept it.

What am I missing ?

Is there a better/more sanic_jwt to accomplish the task ? I think I'm missing the bigger picture on how to tie the various pieces (public, protected) together...

I guess the 'issue' is that the example could cover a transition case.

Thanks

richard

Passing args kwargs from request into is_authenticated method cause unexpected behaviour

Hello, I have found a case with unexpected behaviour.

The problem appears when you try to use protected decorator with sanic websocket route.

Test code sample

@app.websocket('/feed')
@protected()
async def feed(request, ws):
    await ws.send('Hello from protected websocket route')

This problem is caused by websocket protocol object which travels in args from is_authenticated method to verify method and is mistaken for return_payload parameter. It has broken my mind when I tried to find a reason for an Unauthorized exception which is raised instead of original ValueError.

Associated case comes up when you decide to call a parameter in usual sanic route return_payload like this

@app.route('/test_jwt/<return_payload>')
@protected()
async def test_jwt(request: Request, return_payload):
    return json({'success': 'ok'})

Same situation here. ValueError is ovelapped by Unauthorized exception.

I see many places where args kwargs are passed but aren't used. I would like to offer removing them from is_authenticated method, maybe from other places too. May I try to do a PR for this?

Issue when passing custom register view

I get this when i use the example provided in the documentation:

missing 1 required positional argument: 'responses' while handling path /auth/register

Misconfiguration from me?

Access User Detail in protected routes

Is there a way to inject user in protected routes? Something like this?

@auth_bp.post("delete_account")
@protected()
async def delete_account(request):
    email = request['user]['email'] #access user details from request object
    logger.info("Deleting Account for {}".format(email))
    resp = auth_service.delete_account(email)
    return resp

Is it possible to add an expiration date to the refresh token?

Hi,

I'm a (very) beginner to the JWT auth mechanism. I use sanic and sanic-jwt. It works very well, thanks!

I read some stuff about the refresh token and other Python implementations, e.g. flask-jwt-extended and I think it's a good idea to have an expiration date for the refresh token (longer than the access token of course).

  • Is it a way to do that with the current code?
  • Can it be a new feature? Add a configuration option, check the date when refreshing, ...

Thanks. Best regards,
Damien G

retrieve_user not async?

Hi!
Is this error:

2017-11-03 02:13:53 - (sanic)[ERROR]: Exception occurred while handling uri: "http://localhost:8000/auth/me"
Traceback (most recent call last):
  File "/Users/garito/Lab/sanic/testRestAPI2/env/lib/python3.6/site-packages/sanic/app.py", line 503, in handle_request
    response = await response
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/coroutines.py", line 109, in __next__
    return self.gen.send(None)
  File "/Users/garito/Lab/sanic/testRestAPI2/env/lib/python3.6/site-packages/sanic_jwt/blueprint.py", line 80, in retrieve_user
    me = user.to_dict() if hasattr(user, 'to_dict') else dict(user)
AssertionError: yield from wasn't used with future

because retrieve_user can't be a coroutine? (async def retrieve_user)

Thanks!

class_based_views doesn't work for me v1.0

I tried to add class_based_views, like in the documentation:

class MyEndpoint(BaseEndpoint):

    def test(self):
        return True

my_views = (
    ('/tests', MyEndpoint)
)


initialize(app, class_based_views=my_views)

I get a 404. Misconfiguration made by me or bug?

Setting Scopes

hi, first of all, thank you for your awesome works
i have a model named scope and a another model named user.

User model:

User: 
    username
    password
    ...

Scope model:

Scope:
    name
    ...

User Scope Model


UserScope:
    user_id
    scope_id

where must I set the scopes in payload?

authenticate must return object or dict, not bool

Docs lie a bit. autheticate must return object with (default) user_id attribute or dict that has user_id key set. Otherwise all hell breaks loose and nothing works.

Minimum workable example would probably be:

def authenticate():
    return dict(user_id='user_1')

Refresh Tokens

I appreciate the work on this project.

Currently any expired access token can be used along with the refresh token, to gain a new access token.

Instead would it make sense to represent the refresh_token as a JWT itself, such that:

  • The user info can be added into the token, instead of having to use an unverified access token.
  • We can add an expiry time to the refresh token (currently lasts forever, unless the application code adds TTL logic in it's store).

Thanks

How to pass args or kwargs to extend_payload

Or, at least, how to get the request object in that function (as in authenticate or retrieve_user)
Would like to add the user's name & roles for instance (which are in the db accesible in request.app.db ready)

Verification doesn't work when using public key encryption

With the master branch:

I'm using the RS256 algorithm, but I expect this will fail when using any of the other asymmetrical algorithms. When accessing /auth/verify with the token, I get the failure:

  File "/usr/local/lib/python3.6/site-packages/sanic/app.py", line 556, in handle_request
    response = await response
  File "/usr/local/lib/python3.6/site-packages/sanic_jwt/blueprint.py", line 102, in verify
    request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/sanic_jwt/authentication.py", line 169, in verify
    payload = self._decode(token, verify=verify)
  File "/usr/local/lib/python3.6/site-packages/sanic_jwt/authentication.py", line 62, in _decode
    **kwargs
  File "/usr/local/lib/python3.6/site-packages/jwt/api_jwt.py", line 78, in decode
    jwt, key=key, algorithms=algorithms, options=options, **kwargs
  File "/usr/local/lib/python3.6/site-packages/jwt/api_jws.py", line 140, in decode
    key, algorithms)
  File "/usr/local/lib/python3.6/site-packages/jwt/api_jws.py", line 206, in _verify_signature
    if not alg_obj.verify(signing_input, key, signature):
  File "/usr/local/lib/python3.6/site-packages/jwt/algorithms.py", line 317, in verify
    key.verify(sig, msg, padding.PKCS1v15(), self.hash_alg())
AttributeError: '_RSAPrivateKey' object has no attribute 'verify'

From my reading, this is because you need to use the public key to verify the token, since it was signed with the private key. But sanic-jwt doesn't have a way to set the public-key. It just has SANIC_JWT_SECRET.

jpadilla/pyjwt#81

Scopes

Create a mechanism for attaching and checking scoped access tokens.

For example:

def get_scopes():
    return [
        'read:messages',
        'write:messages',
    ]

Check init methods for awaitable

Should run a check to make sure the following methods if implemented are awaitable:

store_refresh_token
retrieve_user
retrieve_refresh_token
authenticate

How can I add an expiration time with access token ?

I'm trying to implement a logic on client side to ask for a new token whenever the previous one expires by storing the expiry time on client side. Is it possible to add an expiration time with the /auth end point ?

/auth/me not allowed

Hi!
Did you notice that RetrieveUserEndpoint and VerifyEndpoint haven't options defined?
As result the browser raises 405

Could you add them or justify why this is like it is right now?

Thanks!

Confusing refresh token example

The example given in the README for retrieving a refresh token suggests that the method can be used asynchronously, by adding it as a task to the overarching Sanic app like so:

def retrieve_refresh_token(user_id, *args, **kwargs):
    key = 'refresh_token_{user_id}'.format(user_id=user_id)

    async def retrieve(key):
        return await aredis.get(key)

    app.add_task(retrieve(key))

However -- and I may be missing its purpose -- I don't quite see how sanic-jwt would be able to do anything with the retrieved token afterwards, because add_task() returns nothing, so neither in turn does retrieve_refresh_token(). (Also, typo with key on the last line?)

And if I am missing something and this approach is indeed valid, could it be adapted to an in-the-meantime workaround for #16?

Thanks :)

(EDIT: Closed/reopened by accident, my bad.)

Thoughts on how to refresh

Right now, you are required to send the access token and the refresh token.

Why? Well, it seems like a good idea to facilitate the lookup of refresh tokens by knowing against which user you are trying to look up. It seems like another layer (albeit thin) of security. The alternative is to lookup the user by refresh token alone.

In the current operation, there is NO verification of the JWT at this stage while refreshing, it is used ONLY to pass the payload and get the intended user_id.

I think this is probably the best method, but I am open to thoughts on whether this should change. Perhaps it could be configurable.

AttributeError: 'function' object has no attribute 'output' on @protected routes

Hello,
ever since upgrading sanic_jwt to the most recent version (1.0.2.1 through pypi) I've been getting a strange bug when attempting to access @Protected routes (from the sanic log):

[2018-04-02 17:11:40 +0300] [3156] [ERROR] Invalid response object for url b'/test', Expected Type: HTTPResponse, Actual Type: <class 'function'>
[2018-04-02 17:11:40 +0300] [3156] [ERROR] Traceback (most recent call last):
File "C:\Users\User1\AppData\Local\Programs\Python\Python36-32\lib\site-packages\sanic\server.py", line 342, in write_response
response.output(
AttributeError: 'function' object has no attribute 'output'

I'm trying to access this by making a simple GET request to the URL, with a valid authentication header containing a previously generated JWT access token.

This is the code I'm using for the server-side (vastly simplified for the sake of reproducability):

import sanic_jwt
from sanic import Sanic, response
from sanic_jwt import protected

app = Sanic()


@app.route("/test")
@protected
async def test(request):
    return response.json('hello!')

if __name__ == "__main__":
    sanic_jwt.Initialize(app, authenticate=lambda x: True)
    app.run(host="127.0.0.1", port=8000, debug=True)

Note that if I comment out the @Protected decorator, everything works fine.

I'm using ver. 0.7.0 on Python 3.6 and getting the same result both on Windows and Linux (different machines).
Will be happy to provide any other info that's missing.

Thanks in advance!

Custom JSON response

Add an ability to change how Sanic JWT responds to endpoints, and authentication failures.

Decorators on Initialize instance

In v1, decorators are in their own module.

from sanic_jwt.decorators import protected, scoped

In order to protect a route that was initialized on a Blueprint, you need to pass the instance.

@protected(my_blueprint)
async def some_view(request, *args, **kwargs):
   ...

I would like to move away from this methodology, and instead have the decorator be a method on the sanic_jwt.Initialize instance. Why?

Well, for one thing, it is an easier syntax, with less likelihood that the developer will forget to pass the right instance.

sanicjwt = Initialize(...)

@sanicjwt.protected
async def some_view(request, *args, **kwargs):
   ...

But, an even better solution is that it could be used to really localize configuration for a single endpoint. Perhaps, even at run time.

sanicjwt = Initialize(expiration_delta=60)

@sanicjwt.protected(expiration_delta=20)
async def some_view(request, *args, **kwargs):
   ...

@sanicjwt.protected(expiration_delta=lambda: 5)
async def some_other_view(request, *args, **kwargs):
   ...

How do i mount /auth on subroute

I would like to mount /auth at /api/auth route. I see no setting in blueprint to achieve this

bp = Blueprint('auth_bp')

Is there a way to achieve this?

is_authenticated raises unauthorized

Hi!
I've noticed that is_authenticated raises unauthorized instead of returning False
To me, is_authenticated will be useful before check the payload and retrieve the user giving the fact that extract_payload also raises 400 when the call is anonymous

am I correct or misunderstanding something?

Protect class based views?

I'm not sure if you can protect the views with the existing decorator, I tried using it and it throws an error:
is_authorized = request.app.auth.is_authenticated(request, *args, **kwargs) AttributeError: 'ClassBasedView' object has no attribute 'app'

Getting TypeError: Object of type 'bytes' is not JSON serializable on requests to /auth

Hi, I'm getting TypeError while trying to authenticate using either my own custom authentication method or this basic method taken from the example:

async def authenticate(request):
    return dict(user_id='some_id')
app = Sanic()
initialize(app, authenticate)

...

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000, debug=False)

I'm making a POST request from a simple tests script like so:
r = requests.post('http://localhost:8000/auth')
The client script receives error 500; the server throws this error:

  File "C:\Users\Saar\AppData\Local\Programs\Python\Python36-32\lib\site-packages\sanic\app.py", line 569, in handle_request
    response = await response
  File "C:\Users\Saar\AppData\Local\Programs\Python\Python36-32\lib\site-packages\sanic_jwt\blueprint.py", line 65, in authenticate
    response = get_token_reponse(request, access_token, output, refresh_token)
  File "C:\Users\Saar\AppData\Local\Programs\Python\Python36-32\lib\site-packages\sanic_jwt\blueprint.py", line 18, in get_token_reponse
    response = json(output)
  File "C:\Users\Saar\AppData\Local\Programs\Python\Python36-32\lib\site-packages\sanic\response.py", line 242, in json
    return HTTPResponse(dumps(body, **kwargs), headers=headers,
  File "C:\Users\Saar\AppData\Local\Programs\Python\Python36-32\lib\json\__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "C:\Users\Saar\AppData\Local\Programs\Python\Python36-32\lib\json\encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\Users\Saar\AppData\Local\Programs\Python\Python36-32\lib\json\encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "C:\Users\Saar\AppData\Local\Programs\Python\Python36-32\lib\json\encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'bytes' is not JSON serializable

The problem seems to be that the access_token that's generated within the blueprint is being returned as bytes rather than string, so that the Python JSON module is not able to convert the dict to json.

I was able to fix it with some monkey patching, adding the following line at the start of the get_token_reponse (typo here btw) method in blueprint.py:
output['access_token'] = output['access_token'].decode('ascii')

If this is indeed a bug, I could probably make a pull request and fix it in a better manner. Thing is, the fact that I seem to be the only one who has this issue makes me think that I may just be doing something wrong.

I'm running the latest version of sanic and sanic_jwt (cloned from the repo) on Python 3.6.1 on Windows.

Websocket support

The @protected decorator does not support websockets. We need to explore the possibility of protecting routes like this:

@app.websocket('/feed')
@protected()
async def feed(request, ws):
    await ws.send('Hello from protected websocket route')

"Mixed" auth methods - headers and cookies

Reading the docs and code, I saw that SANIC_JWT_COOKIE_SET is indeed a switch between using a cookie or a http header to authorize the request. Since I would like to use the same endpoint for browsers (that can use cookies) and other consumers (that doesn't use cookies, like a simple cURL call), is there a way to accomplish this "mixed" behavior? I can help with PRs, if needed.

Dynamic scopes

Say I have a resource that I want to protect for particular users, each to a different resource. How do I accomplish that?

I have user1. He needs to be able to have access to Client:1. Therefore, the scopes property in the @scoped decorator needs to be able to handle dynamic scoping. Something like this:

def some_handler(*args, **kwargs):
    pass

@scoped(some_handler)
@protected
def get_client(request, *args, **kwargs):
    ...

Add more testing to blueprints

Add tests to the following scenarios:

  • two different blueprints with their own sanic_jwt configuration and check if they do not override one another;
  • do the same for both an app and a Blueprint.

Helper methods

When creating custom endpoints, it is somewhat complicated to get all the information needed. For example, if I wanted a custom registration endpoint:

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 = 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_based_views=my_views)           

A much better API would be 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)

        return self.responses.get_token_response(user, include_refresh_token=True)

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

Initialize(app, class_based_views=my_views)    

This would require redoing the existing Responses.get_token_response or moving it to another method.

Configuration getter

One of the new ways in Version 1 to create settings is with the setter function on the Configuration class.

from sanic_jwt import Configuration

class MyConfiguration(Configuration):
    def set_access_token_name(self):
        return 'jwt'

Initialize(
    app,
    configuration_class=MyConfiguration)

Then, the Initialization class goes and installs all the various config settings on a config object.

>>> print(config.access_token_name)
'jwt'

I propose that we change the way that config is used throughout the backend to make it a callable. Instead of doing config.access_token_name it would become config.get('access_token_name').

Why?

Then, we can not only have dynamic attributes set at initialization, but also when called.

class MyConfiguration(Configuration):
    async def get_access_token_name(self):
        return await some_fancy_function()

Custom exceptions conflict with sanic's

>>> import sanic, sanic_jwt
>>> sanic.exceptions.abort(401)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/app/src/sanic/sanic/exceptions.py", line 288, in abort
    raise sanic_exception(message=message, status_code=status_code)
TypeError: __init__() got an unexpected keyword argument 'status_code'

Printing out the exception before this problem line shows that it's attempting to raise sanic_jwt.exceptions.AuthenticationFailed rather than sanic.exceptions.Unauthorized. Looks like the @add_status_code(...) deco just puts status_code/cls as key/value in a dict, so adding the same status code more than once overwrites its previous value.

This occurs both in pre-1.0 and in the current dev branch. Would it be ameliorable on sanic_jwt's end?

Object user can't be used in 'await' expression

Using the code from the documentation :

`
def authenticate(request, *args, **kwargs):
username = request.json.get('username', None)
password = request.json.get('password', None)

if not username or not password:
    raise exceptions.AuthenticationFailed("Missing username or password.")

user = username_table.get(username, None)
if user is None:
    raise exceptions.AuthenticationFailed("User not found.")

if password != user.password:
    raise exceptions.AuthenticationFailed("Password is incorrect.")

return user

`

I get an internal server error while trying to get a access_token with the following command
curl -d '{"username":"user1","password":"abcxyz"}' 127.0.0.1:8000/auth

the error I get is
2017-10-19 14:26:05 - (network)[INFO][127.0.0.1:46704]: POST http://127.0.0.1:8000/auth 500 144 2017-10-19 14:26:08 - (sanic)[ERROR]: Traceback (most recent call last): File "/home/noone/Development/Projects/PushGroupBackEnd/env/lib/python3.5/site-packages/sanic/app.py", line 503, in handle_request response = await response File "/home/noone/Development/Projects/PushGroupBackEnd/env/lib/python3.5/site-packages/sanic_jwt/blueprint.py", line 21, in authenticate raise e File "/home/noone/Development/Projects/PushGroupBackEnd/env/lib/python3.5/site-packages/sanic_jwt/blueprint.py", line 19, in authenticate user = await request.app.auth.authenticate(request, *args, **kwargs) TypeError: object User can't be used in 'await' expression

Verification handlers

What? Custom handlers for before and after a token is verified.
Why? To enable the implementation of custom claims.

Decoupling for microservice architectures

Currently, the sanic-jwt model is not ideal for microservice architecture. The module requires that it be able to authenticate a user and that has the /auth endpoints setup. However, in a microservice setup, likely there will only be one service that needs this functionality. The rest would need to have only the @protected and @scoped decorators.

Therefore, we should introduce a new configuration to enable this. Something like this:

Initialize(app, auth_mode=False)

If auth_mode is off, I do not get an error for forgetting to pass authenticate.

sanic_jwt.exceptions.AuthenticateNotImplemented: Sanic JWT initialized without providing an authenticate method.

And, it does not instantiate the blueprint, so that instance does not get any of the /auth endpoints.

Roadmap to v 1.1

  • Add hooks and helper methods - #67, #70, #71
  • Move decorators to Initialize instance - #68
  • Configuration getters - #72
  • Optional user instance in extend_payload - #81
  • Cleanup and remove deprecated code - #84
  • Refactor "confusing" methods, eg is_authenticated - #86
  • User injection into protected routes - #87
  • Decoupling for microservice architectures - #90
  • Documentation needs some updates - #91
  • Test subclasses on initialize - #92
  • Fix bug with exceptions when using abort - #93
  • Format code using black - #94
  • Implement your own endpoints - #97

Check backwards compatibility

Check if everything is working using initialize or Initialize, duplicating (or scrambling) some of the unit tests. Perhaps give some special attention to scopes ?

How to return json response on authenticate?

Hi,
Sorry for this other question, bu i used the authenticate function provided in the example.

How modify the authenticate response to return something like this (application/json):

{"status": "incorrect_password"}

For example.

Thanks

Add hooks

There should be hooks to make it easier to add functionality instead of having to subclass, including:

  • payloads
  • responses

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.