tfranzel / drf-spectacular

Sane and flexible OpenAPI 3 schema generation for Django REST framework.
https://drf-spectacular.readthedocs.io
BSD 3-Clause "New" or "Revised" License
2.38k stars 264 forks source link

How to define a security scheme involving 2 cookie parameters? #722

Closed bluelight773 closed 2 years ago

bluelight773 commented 2 years ago

I'd like the SessionScheme corresponding to rest_framework.authentication.SessionAuthentication to use 2 cookie parameters instead of one.

What I've tried but doesn't work (the security scheme isn't even shown as an option when I click Authorize in SwaggerUI). If I only include one cookie parameter, then this works, but I need it to work for 2 cookie parameters.

from drf_spectacular.authentication import SessionScheme

def get_security_definition(self, auto_schema):
    return [
        {
            "type": "apiKey",
            "in": "cookie",
            "name": "cookie_param1",
        },
        {
            "type": "apiKey",
            "in": "cookie",
            "name": "cookie_param2",
        },
    ]

SessionScheme.get_security_definition = get_security_definition
SessionScheme.name = "TwoCookieParamAuth"

https://github.com/swagger-api/swagger-ui/issues/4218#issuecomment-656688147 suggests I may be able to define the desired security scheme with something along the following lines. However, I'm not sure how to define such a scheme with drf-spectacular.

get:
    summary: Test endpoint
    parameters:
        - name: authCookie
          schema:
            type: object
            properties:
              cookie1:
                type: string
              cookie2:
                type: string                  
          in: cookie
          explode: true
          style: matrix

Any ideas on how to define a 2-cookie-parameter security scheme with drf-spectacular?

Thanks!

tfranzel commented 2 years ago

to override default SessionScheme behavior, you need to write a small extension. Here is an example on how to set multiple params

https://github.com/tfranzel/drf-spectacular/blob/d0dfdb4000fbce38e7694823c579212e476401ea/tests/test_extensions.py#L126-L135

make sure you have the proper target_class and also set priority to >1 (due to replacing the original session extension). Also pay attention to the name list. It has the match the parameter names.

bluelight773 commented 2 years ago

Thanks for the quick response. I just tried that. It gets close but not quite.

As seems to be discussed here: https://github.com/swagger-api/swagger-ui/issues/4218, the solution you suggested ends up producing the following in the curl command (when using SwaggerUI): -H 'Cookie: cookie_param1=somevalue1&cookie_param2=somevalue2'

However, I need it to be like this: -H 'Cookie: cookie_param1=somevalue1; cookie_param2=somevalue2'

Is there some way to ensure the second format is used?

tfranzel commented 2 years ago

I see. However, I think your ask is not possible out of the box. The security scheme object does not allow for multiple parameters and thus same goes for extra modifiers like style and explode. All we can do is to say your require 2 auth methods and by that 2 parameters. that is the limit of what we can do here with OpenAPI.

https://github.com/swagger-api/swagger-ui/issues/4218 does make use of those modifiers by way of using normal parameters instead of the actual auth parameters. You can do that here too with @extend_schema(parameters=...), but it is a hack.

tfranzel commented 2 years ago

I will close this issue as there is nothing we can do about this. At the end of the day it is a limitation of OpenAPI that we cannot give a more detailed auth specification with the available spec objects. If at all sensible, swagger-ui might interpret multiple cookie auth params differently, but that is beyond our reach and scope.