Authentication and settings


#1

The authentication system seems not to be part of the project for #400.
Will it move to third party ? so maybe the community should take care of that ?

About Settings component : I think it’s missing now, and a “common settings objects” is something useful for third party app.
a apistar-settings.py file would give to every one the same way to do things.

Jimmy


#2

Global settings go away in 0.4, yes.

Instead we make sure that you’re able to configure components and/or event hooks at the point they’re instantiated. I’m much happier with that.

It’s very possible that we might end up wanting a general purpose settings object, but we’d need to figure out what sort of cases that’s preferable for vs. more localized configuration.


#3

With regards to the authentication system, what is the expected outcome with that?

The documentation has an example of what one might be able to do to enforce authentication via an event hook, but there’s no clear indication of what one should do if we were using apistar.interfaces.Auth or apistart.authentication in 0.3.9.


#4

I upgraded a medium sized (~1.5k LOC) app to 0.4 yesterday (roughly a couple hours of work) and ended up introducing my own auth component to replace the old Auth stuff.

I have an authentication component that generates an Account object from request data inside resolve() and I have an AuthenticationHooks class that hooks into on_request and blocks unauthenticated requests, very much like the example in the docs.

class AuthenticationHooks:
    def __init__(self, handler_whitelist=None) -> None:
        self.handler_whitelist = set(handler_whitelist or [])

    def on_request(self, route: Route, account: Account = None) -> None:
        if getattr(route.handler, "no_auth", False) or route.handler in self.handler_whitelist:
            return

        if not account:
            raise exceptions.Forbidden({
                "message": "invalid api key",
            })

# ...
from apistar.server.handlers import serve_schema

event_hooks = [
    PrometheusHooks(),
    AuthenticationHooks(handler_whitelist={
        apistar_prometheus.expose_metrics,
        serve_schema,
    }),
]

One thing I ended up missing was the old Environment object so I rolled my own: https://github.com/Bogdanp/apistar_settings


#5

That’s is awesome.

So far, I’ve just used the User / UserComponent example from the DependencyInjection example, but I’m now at a point where I need to place my usage of @annotate(permissions=[IsAuthenticated()]) in almost every handler.

Using an authentication hook that takes a user and running it through a whitelist of allowed handlers is the way I will go.


#6

I’m flipping out right now about this:

I didn’t realise that attributes could be attached to functions. Pop this in a decorator, and I can use that and save the whitelist for handlers that I don’t have control over.

Double likes!


#7

Very cool, slightly modified that for my JWT package:

class AuthRequiredHook():
    def __init__(self, whitelist=None) -> None:
        self.whitelist = set(whitelist or [])

    def on_request(self, route: Route, user: JWTUser=None) -> None:
        if getattr(route.handler, 'authenticated', False) or route.handler in self.whitelist:
            return
        if not user:
            raise exception.Forbidden({'message': 'Invalid token'})