OpenAPI-Specification icon indicating copy to clipboard operation
OpenAPI-Specification copied to clipboard

Mark endpoints as private/hidden

Open mohsen1 opened this issue 8 years ago • 43 comments

With Swagger inflector and Swagger-node it's now more common to have endpoints that we don't want to document but we want to have them in the spec for other uses. There should be a way to mark endpoints as private or hidden so they don't show up in the UIs but can be used with other tools.

mohsen1 avatar Aug 04 '15 23:08 mohsen1

Need more that. What are some use cases where you don't want to document them, you do want them in the spec, but don't want them in the UI (which is sort of a contradiction on its own)?

Just trying to understand here.

webron avatar Aug 04 '15 23:08 webron

Let's say you have an API that has some endpoints that you want only internal users know about it. In case swagger.{json,yaml} is exposed externally the private: true endpoints are stripped down by the server if user doesn't have "internal user security credentials" they won't see those endpoints .

This also can help swagger-node and swagger-inflector return 404 errors for secure endpoints when a request with invalid credential is coming in. GitHub API does this, if you don't have valid credentials you won't know about some secure endpoints at all.

mohsen1 avatar Aug 04 '15 23:08 mohsen1

That's ACL on the Swagger definition which if we choose to add should be handled in a much different way than just adding a private/hidden property to an operation (there are other considerations as well, such as hiding tags and possibly others).

I believe we discussed it for 2.0, and not saying it should be dealt with in future releases, but the filtering may actually be the responsibility of the tools and not really part of the spec itself. I don't know the 'right' answer here.

webron avatar Aug 04 '15 23:08 webron

Right, I think a simple boolean property will not be enough and there could be other scenarios more complex than internal user vs. public.

Swagger can use it's own security system to define what operation is available to view to which credential owner. By default all operations are available to public to see unless the showOnlyTo has the security that you have the credentials of.

For example:

swagger: '2.0'
info:
  version: 1.0.0
  title: Example
securityDefinitions:
  basicAuth:
    type: basic
paths:
  /:
    get:
      security:
        - basicAuth: []
      responses:
        '200':
          description: 'OK'
  /foo:
    get:
      x-showOnlyTo:
        - basicAuth
      security:
        - basicAuth: []
      responses:
        200:
          description: OK

In this Swagger, if I don't have basicAuth credentials I won't see /foo in the documents or swagger.json.

mohsen1 avatar Aug 05 '15 00:08 mohsen1

I'd probably go with a different name, and possibly with a different kind of granularity, but yeah. At least now it can be solved with vendor extensions. We'll need to decide whether it should be part of the actual spec, but it's a legitimate overall use case.

webron avatar Aug 05 '15 00:08 webron

Something like x-visibility or x-doc-visibility, maybe?

theganyo avatar Aug 05 '15 03:08 theganyo

Visibility is a result, but it's not necessarily the only issue. You may want to do something further like explicitly disallow execution based on specific credentials and not just hide it from the documentation. In this situation, the Swagger definition is not necessarily used for documentation purpose only anymore.

x-access, x-acl and so on may be more fitting. The value may not necessarily be a simple string or array either but a complex object (for different access levels and so on, or access groups and so on).

webron avatar Aug 05 '15 13:08 webron

Isn't the "security" section for execution access control?

theganyo avatar Aug 05 '15 16:08 theganyo

The security refers to the requirements to execute the API, but it doesn't mean it should be hidden from the user. It just means the user needs to be aware of what security procedure is required before they an execute a request.

webron avatar Aug 05 '15 17:08 webron

Right. What I'm saying is: The security section is already there for execution. We were talking about visibility. Why are you saying that we need an x-access to also control execution?

theganyo avatar Aug 05 '15 17:08 theganyo

And again the quote "There are only two hard things in Computer Science: cache invalidation and naming things." (Phil Karlton) comes to mind. I get what you're saying regarding the security section and the execution, but I see the restriction as somewhat different in the two cases.

The security is always exposed to the user, but the new property isn't (or is it?). The first is documenting the API, the second is meta documentation. I guess visibility could work, though to me it would mean something slightly different.

webron avatar Aug 05 '15 18:08 webron

Well, I see several domains here:

  1. Expression of an API as documentation
  2. Authorization of access to sections of the API documentation
  3. Expression of an API as executable
  4. Authorization to execute an operation

My confusion is that I'm not sure which tags apply to which domains and how...

theganyo avatar Aug 05 '15 22:08 theganyo

I'm not sure I see the difference between 1 and 3, so would appreciate further explanation.

For 4. - security is meant to cover it. For 2. - this is what I believe we're discussing right now. To be honest, I'm not sure this even belongs in the scope of the spec.

webron avatar Aug 06 '15 15:08 webron

If ACL is not defined in the spec so the server can determine which endpoints to show programmatically the only alternative is to have multiple subsets of your spec served to different credential holders. Having multiple swagger specs for an API is not optimal IMO.

mohsen1 avatar Aug 06 '15 16:08 mohsen1

It's not the only way. Nothing prohibits you from adding your own vendor extensions to perform it. In swagger-core we allow definition filtering based on information available from the code. There are a few ways to solve it. Not every vendor extension should make it into the spec eventually. It could also be a separate file describing it, as it is meta documentation.

For now I'm just throwing ideas around, no concrete opinion yet.

webron avatar Aug 06 '15 17:08 webron

See #569

fehguy avatar Feb 17 '16 15:02 fehguy

Alternative: Serve different variations of the schema depending on the authentication context. That'll allow you to present differing sets of information to different clients.

tomchristie avatar Feb 18 '16 12:02 tomchristie

Came here looking for this possibility. I'm totally new to Swagger, but here's my two cents: I believe @webron 's idea on vendor extensions allows for the most flexibility. It would allow the server to decide not to show something based on who is looking (anonmyous, paying customer, premium customer,...), but also other options we can't think of, e.g. only/don't show it after a certain date, etc.

petermorlion avatar Sep 08 '16 10:09 petermorlion

Yes, this is done in several OSS tools, such as swagger-inflector and swagger-core. Probably best not in the spec, though.

fehguy avatar Sep 08 '16 18:09 fehguy

@fehguy without supporting this in the spec, it won't make it upstream into all the consumers of OpenAPI. For example, I use google cloud endpoints and they don't support private endpoints as it's not really a thing. This means I don't have a way to publish endpoints with them and keep them out of documentation. Private endpoints are going to happen in almost any large API deployment. It seems like supporting this at the spec level would help define private and allow it to push out to the ecosystem. Not supporting it means that you're going to get many different implementations of private which are likely incompatible which is kind of anti-spec.

dkoston avatar Jun 20 '18 16:06 dkoston

Hey everyone,

what i did was define a tag called 'hidden' and then used custom css to hide it:

app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, { //hide the internal api endpoints customCss: 'div[id^="operations-hidden"]{display:none} #operations-tag-hidden{display:none}' }));

jgomes94 avatar Aug 16 '18 17:08 jgomes94

But that only hides it visually. It's still there in the source, right? That wouldn't be secure enough for a lot of my clients.

petermorlion avatar Aug 16 '18 17:08 petermorlion

Yes you are right @petermorlion, it can still be visible with some DOM manipulation

jgomes94 avatar Aug 17 '18 14:08 jgomes94

@dkoston @petermorlion my personal take is that this is functionality which belongs in a pre-processing tool, not within the OAS itself. That way you can guarantee no leaks of internal endpoints etc between your varying audiences. One such tool is openapi-filter. I understand that if your API management tool generates documentation from the same OAS document as the implementation then this won't help.

It is, perhaps, another pointer that properly secured endpoints with appropriate access-controls are preferable to security-by-obscurity.

MikeRalphson avatar Aug 24 '18 11:08 MikeRalphson

@MikeRalphson the attempt here is not security by obscurity. If people aren't defining security for endpoints they want to have hidden from documentation/tools, that's a huge mistake and could cause major headaches for them.

The thought behind this request is that there are common patterns that will be relegated to custom code/solutions if they are not supported by the spec.

Sure, tens of thousands of people can use something like openapi-filter to achieve the same results, or possibly not hear of it and create their own solution.

Thinking about this again, I do believe it would be a mistake to put something that only supports "hidden/private" in the spec. The real issue is that there are properties of some routes that make it so they should be treated differently. For example: I want to have different versions of my API docs depending on what type of user you are (why send you a bunch of endpoints you don't have access to?).

What's likely a good solution at the moment is to use "tags" on your Operation Object. However, without some formalization of what tag to use, I may choose "private", you may choose "hidden", others may choose to use "x-internal" at the top level of the Operation.

I believe this may just be a philosophy issue.

I personally believe that setting a standard without ambiguity leads to a small set of well maintained tools which allow newcomers to an ecosystem to use and have success with without spending hours/days researching and customizing to get to a common solution.

Alternatively, one can have a very open ecosystem with tons of tools and extensions where some are maintained, some are high quality, and others are not.

The fact that this thread has gone on for years without someone being like "Hey, this pattern can easily be solved by X", means that the OpenAPI ecosystem has some issue (documentation, lack of tooling for this pattern, or something else).

Perhaps a short term solution would be for the team to list well maintained extensions here: https://swagger.io/docs/specification/openapi-extensions/

I'm not sure what the communities' policies are around the concept of "when does something become so common that its part of the spec" and that's the main goal of this request.

The idea is that a large portion of the OpenAPI community deals with hidden/internal/private/segemented endpoints. Adding something formal to the spec would allow tooling to be built that conforms to the spec rather than introducing a new "meta-spec" for each tool.

dkoston avatar Aug 24 '18 14:08 dkoston

The real issue is that there are properties of some routes that make it so they should be treated differently

Unless there is some consensus on what "treated differently" means, by the tooling providers, I think this idea is so vaguely-defined as to be unlikely to be adopted by the spec itself, over other existing mechanisms like specification-extensions.

Though this issue has been open a while, it hasn't garnered that many comments or up-votes compared to others being considered.

There is a plan to create a registry of common / standardised specification-extensions, see #1351

MikeRalphson avatar Aug 24 '18 14:08 MikeRalphson

Unless there is some consensus on what "treated differently" means, by the tooling providers, I think this idea is so vaguely-defined as to be unlikely to be adopted by the spec itself, over other existing mechanisms like specification-extensions. I was purposefully being in-specific as "hidden/internal" is not the only property I think could be valid here.

I didn't want to dictate to the community what properties I think are important but just to note that changing the spec to add "hidden: true" seems like a lot of work to capture a single use case and something that captures multiple use cases may be a better solution. Maybe there are too many use cases and it's best to just add a single property as suggested above.

I'm totally fine if the project says "we aren't going to do this", that's up to the project.

However, we're getting mixed feedback. @webron thought this idea may have merit and @fehguy opened an issue relating to a solution. A third member (yourself) said it can be handled via extensions.

I think we're just looking for some clarity on what to do when we come across endpoints that should be treated differently. It seems like the 2018 solution is to use extensions but we haven't gotten a definitive: "the project suggests that you handle that use case this way"

People look to the maintainers and contributors of a project for solutions as they have the most experience with the ecosystem. If we're left to go hunt down solutions on our own, we only have so much time and energy to invest as a single person with the problem. Whereas, it's likely that the community has come across this scenario many times and can provide at least a good starting point.

There is a plan to create a registry of common / standardised specification-extensions, see #1351

Great, that's a good step, glad to hear it.

Having some documentation that talks about use cases for the project and how they can be accomplished could really help out those trying to use the project as well.

A good example of this is the design recipes from FoundationDB. FoundationDB chooses not to maintain all those features in its core but they know that there are common use cases their customers have and by pointing users in the right direction, adoption will likely increase in velocity.

dkoston avatar Aug 24 '18 14:08 dkoston

To make things easier (not really), I'm not really sure it belongs in the spec. It's my (personal) belief that we should encourage API definitions to be public and not just used as a way to automate processes. If that's the case, then having a way to 'hide' something from the documentation won't really help.

@dkoston wrote:

For example: I want to have different versions of my API docs depending on what type of user you are (why send you a bunch of endpoints you don't have access to?).

That's really a classic use case for pre-processing as @MikeRalphson mentioned.

I understand the desire to have us give an official statement as to how it should or shouldn't work, but at the end of the day, we can't address everything. The fact that since the ticket was created there hasn't formed a commonly-used solution also suggests that it doesn't hurt people enough to push this through.

With all that said, soon (🤞) we'll have the Overlays feature implemented, and that would allow you to separate the public and private APIs into different layers and expose the user only with the intended information. This will not cover dynamic cases as much, but should still address many issues. To make this extra sweet, by adding overlays, pre-processing will end up being a must.

webron avatar Aug 25 '18 00:08 webron

@webron Thanks for the clarity. Seems like pre-processing and/or Overlays is the approach to take when features aren't supported by the core spec.

dkoston avatar Aug 27 '18 15:08 dkoston

I was looking at the HTML generated by swaggerui, and in principle you might be able to hide entries via CSS styling (which is actually what I want - just to make the documentation more readable for third parties. Internally I only use the raw swagger output for generating/updating clients etc.). However, for instance I'm seeing:

<div class="opblock-tag-section is-open">
    <h4 class="opblock-tag no-desc" id="operations-tag-MyPrivateOps">
    <a class="nostyle"><span>My Private Operations</span></a>                       
...
</div>

And as of late 2019 there's still no way of styling an element based on some property of its children (or conversely, having a selector control the styling of the parents of matching elements), so I can't readily hide the whole opblock-tag-section div (actually I probably want to hide the span above that too).

For the time being I can cope with something that just hides the key elements ([id*=\"MyPrivateOps\"]{display:none !important}) but it's definitely not ideal. And yes, it would be better if the HTML weren't generated at all.

wizofaus avatar Oct 10 '19 10:10 wizofaus