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

OpenAPI security fields #515

Closed
tiangolo opened this Issue May 7, 2018 · 3 comments

Comments

Projects
None yet
2 participants
@tiangolo

tiangolo commented May 7, 2018

I'm really liking apistar, thanks for creating it!

I would like to be able to declare "security" fields in the OpenAPI "schema". That would let me use Swagger-UI directly with its integrated authorization functionality as I'm doing for example in this project generator (using Flask and Flask-apispec, Docker based): https://github.com/tiangolo/full-stack

I'm not talking about integrated authentication / authorization within API Star, I would still expect to develop the functionality in each individual app or with external plug-ins, as apistar-jwt.

But with the current code it's not possible to modify or add more data to the OpenAPI schema. So, it's not possible to add the "security" fields that would be required for that.


I just read the full OpenAPI spec yesterday to check in the code if it was actually possible with the current code, but I see there are some changes required.

And very recently I read the full spec of OAuth2, to implement all that in my Flask APIs with Swagger 2.0. But I would love to use API Star.

I'm willing to help, but I would like to first know if there is any plan with respect to that and if that would be something desirable for the project (I certainly hope so).

Some of the changes I think that are neede are:

In apistar/openapi.py:

  • This line ('security', validators.Ref('SecurityRequirement')), needs to be validators.Array(validators.Ref('SecurityRequirement'))) as used below in other section. In OpenAPI
  • This line should be updated to be one security requirement and not an Array, although I'm still not completely sure what is the role of the additional_properties compared to the properties, so I might be misunderstanding it.
  • Components should be able to also contain securitySchemes and not only schemas. In OpenAPI.
  • There should be a definition for a SecurityScheme that would be referenced in Components and possibly in the operators (get, post in each route). In OpenAPI.

There should be a way to pass the SecuritySchemes to App, probably on instantiation, to be put beside the schemas, under Components.

There should be a way to pass a security field referencing the name of one of the SecuritySchemes to each route-method pair. Probably as a keyword argument in Route().


Again, I don't expect API Star to handle security iself, authentication and authorization, etc. At most validation of fields. The rest would be handled in each app specific code or with plug-ins, but that would provide a way to declare in OpenAPI the security definitions that could then be used with an integrated UI like Swagger-UI.

BTW, Swagger-UI could be used as a separate front-end app (e.g. in a separate Docker container) or integrated into API Star. Here's an example of how it looks like: http://petstore.swagger.io/ . And it's already built, and API Star is already almost completely compatible with it.

The "Authorize" button allows you to authenticate with the API and use the documented endpoints without having to copy and paste tokens or passwords for each request.

That's what I do with https://github.com/tiangolo/full-stack, but it is based on Flask, and I would love to be able to take advantage of all the new Python typing functionality as with API Star.


What are your thoughts on all this?

@tomchristie

This comment has been minimized.

Member

tomchristie commented May 24, 2018

Thanks for the detailed and well thought through issue!

So there's a whole bunch of different fields that OpenAPI doesn't generate - the security ones being one of them. (Something like "callbacks" being an example of another.) We could find way to include these from the codebase - eg. include them from the Route. However we end up in a position of having to eventually expand to handling the entire OpenAPI spec from within API Star codebases. I'd rather that we instead consider something like dumping out the schema, and allowing developers to include additional annotations in there, and then keep the schema in-sync as the project develops.

@tiangolo

This comment has been minimized.

tiangolo commented May 25, 2018

Thanks for your response and considerations @tomchristie !

Actually, I see there are very little pieces from OpenAPI missing in API Star, at least from the schema validation.


Thinking about parsing and modifying the full schema dump.

Do you see a way an API Star "Component" could modify something in the complete OpenAPI schema? For the security global field and the securitySchemes in the components.

At the same time, do you see how that same API Star "Component" could modify something in the specific schema for each route it is being used in? For each specific path securitySchemes field.

For example, in apistar-jwt.

I'm trying to figure out how that would be implemented, as it seems to me it would be quite non-trivial to only use the full schema dump and modify it after it is generated.


Here's an idea, what if most of the OpenAPI schema is included in the validation (almost as it is right now), and whatever is too complex to be included, or too unrelated to the core project's objectives (let's say, the "callbacks"), is just declared as any, so that developers can use it without having validation problems, but is up to the developers to use and create those sections correctly.

And then, in the code that ends up generating parts of the schema, for example the Route, or Components, there's a way to declare other fields of the schema section they modify. Those sections are not checked to be valid, to reference whatever they should be referencing, etc. It's all up to the developers.

But that would give a greater fexibility and simplicity for developers to add whatever custom code they need to include additional OpenAPI generated schema parts, without having to parse the full dumped schema and finding for the sections that have to be modified, etc.


That's more or less how Flask-apispec works, it is not documented anywhere how to use the security fields, but there's a way to add any additional schema field required.

Note: these examples are with Swagger 2.0, not 3.0 (OpenAPI).

You can configure a Flask app with:

security_definitions = {
    'bearer': {
        'type': 'oauth2',
        'flow': 'password',
        'tokenUrl': f'{config.API_V1_STR}/login/access-token',
    }
}

app.config.update({
    'APISPEC_SPEC':
    APISpec(
        title='Example Project',
        version='v1',
        plugins=('apispec.ext.marshmallow', ),
        securityDefinitions=security_definitions),
    'APISPEC_SWAGGER_URL':
    f'{config.API_V1_STR}/swagger/'
})

The important part is here:

APISpec(
        
        securityDefinitions=security_definitions
)

...the securityDefinitions passed to APISpec is not even declared as a parameter, is just part of the "Optional top-level keys", like a **kwargs.

That modifies the global level schema fields.

And then in each route that uses security you can do something like:

@docs.register
@doc(description='Test access token', tags=['login'], security=security_params)
@app.route(f'{config.API_V1_STR}/login/test-token', methods=['POST'])
@use_kwargs({'test': fields.Str(required=True)})
@marshal_with(UserSchema())
@jwt_required
def route_test_token(test):
    current_user = get_current_user()
    if current_user:
        return current_user
    else:
        abort(400, 'No user')
    return current_user

The important part is here:

@doc(                  security=security_params)

... the security parameter is not declared in the doc definition, is just passed directly to the schema generation.

That modifies each route level schema section.

That way, although Flask-apispec and Apispec are not designed to "support" OpenAPI (Swagger) security, it's very easy to add it in an app using them.


Do you think that having some very simple way to extend the schema generated by each API Star part, in a similar way to what is done in Apispec, would be possible / feasible?

Of course, I would love to help as much as possible with PRs, as I really want to use API Star, but I would first like to make sure any proposed change is aligned with the project's goals.

@tomchristie

This comment has been minimized.

Member

tomchristie commented Sep 25, 2018

Closing this off given that 0.6 is moving to a framework-agnostic suite of API tools, and will no longer include the server. See https://discuss.apistar.org/t/api-star-as-a-framework-independant-tool/614 and #624.

It's possible that we'll end up having a support for generating OpenAPI specs from a range of different frameworks, but if we do it'll more be based on writing directly to an OpenAPI spec, than the API Star approach of having a document model. (The document model is still there at the moment, but it's not really exposed in the API anymore, and we might be able to make it disappear.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment