Open diamondburned opened 2 years ago
cc @zacharyburkett
We could inject security related middlewares as middlewares required on function calls by codegen.
Such that, having
{
"security": [
{
"BearerAuth": [],
}
]
}
Would be similar to
x-go-middlewares: ["bearer-auth", existing-middlewares...]
In essence, those could be simply set by the user directly in the middleware section, just like how 99% of the people using the stdlib does authorization and validation.
We could inject security related middlewares as middlewares required on function calls by codegen.
I think this issue is effectively suggesting that:
r.Group(func(r chi.Router) {
r.Use(handleBearerAuth) // !!!
r.Use(options.SecurityMiddleware) // !!!
There's a slight difference between this and just letting the user inject the middleware manually: the idea is for goapi-gen
to also generate OAuth library code that abstracts checks for the users wherever possible. In this case, goapi-gen
can generate a code that validates that the header is a valid Bearer
header.
Problem
goapi-gen currently does not autogenerate anything for
security
. Instead, the user is supposed to use a long-winded way of adding a middleware which also doesn't support dependency injection viacontext.Context
s.The current method also requires the user to manually verify authorization information by reading the
*http.Request
instance within the authentication callback.Below is an example of such code for
BearerAuth
:This code is then used like so:
This abstraction by itself isn't any easier than just using a regular middleware, except for the fact that it's still not possible to inject any value into later handlers. For comparison, such a middleware would look something like this:
Clearly, goapi-gen isn't generating much at all when it comes to
security
.Proposal
A possible way to improve this situation would be to make goapi-gen generate middlewares that inject the related security information for the user to check from a middleware.
For example, given the following JSON (with all routes and schemas omitted):
goapi-gen can generate code that handles checking for a valid security scheme and validating the
Authorization: Bearer
header. It can then generate the above callbacks, which can be tucked inside the autogeneratedServerOptions
.For the above example, that would look like this:
The user can then inject the middleware like so:
A few important notes:
writeError
callback.r.Group
is required here because the user'sSecurityMiddleware
must be called after our security middleware handlers (handleBearerAuth
in this case) are called. Because of this, the user cannot arbitrarily add a middleware.SecurityMiddleware
is a runtime error, not a compile-time error.error
in theirErrorHandlerFunc
for the server to possibly respond with a correct status code.handleBearerAuth
not callErrorHandlerFunc
and instead write its own code, like so:A very important note regarding the above snippet: there is no way for the user to change how the error is written if they feed the backend an invalid header. That is, unfortunately, on par with what
OapiRequestValidatorWithOptions
is currently doing, which is a terrible idea!Alternatives
I've considered alternatives to injecting into
context.Context
, including having a callback that the user implements specifically for authenticating. Something like this:This API, while slightly more declarative (in that it doesn't require pulling an instance from the blackbox that is
context.Context
), it has other annoying flaws: the firstBearerAuth
does no parsing at all, while the secondBearerAuth
has a generally very weird method signature.