Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Injectable security constructs that fill security and securityScheme #3203

Open
tuukkamustonen opened this issue Mar 14, 2024 · 0 comments
Labels
Enhancement This is a new feature or request

Comments

@tuukkamustonen
Copy link
Contributor

tuukkamustonen commented Mar 14, 2024

Summary

There are 4 ways to authenticate/authorize requests:

  1. AbstractAuthenticationMiddleware middleware
  2. AbstractSecurityConfig middleware
  3. Usual DI logic
  4. Guards

There are certain shortcomings:

  1. AbstractAuthenticationMiddleware does not add security and securityScheme (but you can define it per layer)

  2. AbstractSecurityConfig injects security and securityScheme globally instead of per operation (Bug: AbstractSecurityConfig sets security for all paths, even those excluded #3013). Also, you can only define it per application, not per layer (ie. routers, controllers, handlers). Even if Bug: AbstractSecurityConfig sets security for all paths, even those excluded #3013 gets fixed, it's inconvenient having to exclude routes per path (string values) and not being able to define this per layer.

  3. Usual DI logic works just fine, but if you don't actually need the value it injects, linters may nag you and IDEs render the parameter as grayed out (because it's not used). Plus, it's not possible to adjust the security / securityScheme via it (at least not without hacks).

  4. Guards don't support DI, and cannot alter security / securityScheme

What's needed is a mechanism that:

  • Supports DI
  • Allows to inject security per layer and securityScheme (when needed, to the global level)
  • Can be used with either returning value or not returning value

Basic Example

scheme = SecurityScheme(type="apiKey", description="...", ...)

async def callable_auth(
    scheme: Annotated[Any, scheme],
):
    ...  # the usual auth checks

# Or maybe
class ClassAuth(Security):  # Security being some Litestar provided base class
    security_scheme = scheme

    async def __call__(self):
        ...  # the usual auth checks

@get()
async def handler1(auth1: User) -> str: ...

@get(guards=["auth2"])
async def handler2() -> str: ...

app = Litestar(
    [handler1, handler2],
    dependencies={
        "auth1": Provide(callable_auth),
        "auth2": Provide(ClassAuth),
    },
)

So, with the idea that:

  • DI would work
  • security and securityScheme are filled automatically and only where needed
  • You can choose between needing the return value (usual DI) and not needing (guard)

Something like that?

Drawbacks and Impact

No response

Unresolved questions

No response


Note

While we are open for sponsoring on GitHub Sponsors and
OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.

Check out all issues funded or available for funding on our Polar.sh dashboard

  • If you would like to see an issue prioritized, make a pledge towards it!
  • We receive the pledge once the issue is completed & verified
  • This, along with engagement in the community, helps us know which features are a priority to our users.
Fund with Polar
@tuukkamustonen tuukkamustonen added the Enhancement This is a new feature or request label Mar 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement This is a new feature or request
Projects
None yet
Development

No branches or pull requests

1 participant