Swagger-ui: Documenting POST endpoint using base64 encoding

Created on 13 Nov 2018  ·  16Comments  ·  Source: swagger-api/swagger-ui

Hi, I am trying to document an enpoint that encodes 2 variables.
Is it possible to use base64?
I know how to do it under security definitions, but we need to have it fully documented as a standalone POST/.

POST: /v1/url HTTP/1.1
Host: host.api
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(*CLIENT_ID_VALUE* + “:” + *CLIENT_SECRET_VALUE*)

grant_type=client_credentials

Thanks!

lock-bot question

All 16 comments

The Authorization header here is standard Basic authentication using client ID as a username and client secret as a password. Basic authentication can be described using securityDefinitions + security, just like other supported authentication types.

Yes Helen, I know this and I have it working, but I do need to document the endpoint by itself. Something like this (ignore the lock). Thanks

screen shot 2018-11-14 at 7 50 09 am

Here's how you can document it:

paths:
  /v1/oauth/token:
    post:
      security:
        - TokenRequestBasicAuth: []
      consumes:
        - application/x-www-form-urlencoded
      parameters:
        - .....
      responses:
        ...

securityDefinitions:
  TokenRequestBasicAuth:
    type: basic
    description: Use client ID as the username and client secret as the password.

Is this for the authorize button or to get the post working by itself? In this case, I am trying to get the post working not the authorization.

It's for both because the OAuth 2.0 RFC says the token request "MUST authenticate with the authorization server". In this case the "Authorize" button is used to enter the client ID (username) and client secret (password) for the token request.

But I don't want it in the authorize, the authorize is working as it is supposed to be. I am trying to have an additional endpoint documented with the post process. So when I click on try it out I will be able to get the token back in the call. If you see the screenshot, it is missing Basic base64(client_id...)
screen shot 2018-11-14 at 9 15 49 am

Hmm...

@hkosova's right, you should be using our Authorization features for this - but @Yaima I do see where you're coming from in terms of documenting the token-granting endpoint itself.

_Perhaps_ it should be possible to document a base64-encoded parameter like this:

swagger: "2.0"
paths:
  /:
    post:
      consumes: 
      - multipart/form-data
      parameters:
      - name: client_id
        in: formData
        type: string
        format: base64 # <-----
      responses:
        200:
          description: ok

As of now, we're treating this parameter as plain text, though.

Follow-up: @Yaima, as I understand it, your parameters are in the right place, your only problem is that they're plaintext instead of base64-encoded?

If you want base64 in your formData body... we can dig into that. What we _can't_ do is allow you to create a header that controls Authorization - OpenAPI doesn't allow that (see https://github.com/swagger-api/swagger-js/issues/1405).

Yes, I am trying to document the Authorization process by itself for the API users.
Adding format - base64 doesn't change anything.

parameters:
        - type: string
          x-go-name: ClientID
          description: (string) The client_id from your Neustar SiteProtect API Token.
          name: client_id
          in: formData
          format: base64
          required: true
        - type: string
          x-go-name: ClientSecret
          description: (string) The client_secret from your Neustar SiteProtect API Token.
          name: client_secret
          in: formData
          format: base64
          required: true

curl -X POST "https://api.neusec.biz/v1/oauth/token" -H "accept: application/json" -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=abc&client_secret=def"

So pretty much when the user click on Execute, the curl command should look like:

We are covering the api Authorization via the Authorization button and this works just fine, but we need to additionally document the POST endpoint maybe calling to this: authActions.authorizeApplication(auth)?

screen shot 2018-11-14 at 1 00 09 pm

The generated curl should look like:

curl -X POST \
https://api.qa.com/v1/oauth/token \
-H 'Authorization: Basic d1FxV0xDd3IzMlFqcmhhSDFic3pRVTBaczRPWVJERXA6U3BHaHpoNUlhWWZtMlBCWGF3cVVLbEwtbFNubEI5Y0RYWXVEcVZ1ZC1uZ1ZoRDA4ODhoM2FydW9tNWczandhbQ==' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'cache-control: no-cache'

@Yaima ok, one more question - in the cURL example you provided, where in the Swagger document are you expecting the Authorization header value to come from?

Maybe a different data type for parameters that when specify it will generate a curl command following the already existing authorization code ie:(authActions.authorizeApplication(auth), something like basicFormData.
If this type of parameter is specified, then the program knows that the user is trying to document an endpoint for authorization and so on.

Maybe something like this adding the base64 encoding and the auth to it?

export const buildFormData = (data) => {
  let formArr = []

  for (let name in data) {
    let val = data[name]
    if (val !== undefined && val !== "") {
      formArr.push([name, "=", encodeURIComponent(val).replace(/%20/g,"+")].join(""))
    }
  }
  return formArr.join("&")
}

How about creating a new value
const VALID_IN_VALUES = ["path", "query", "header", "body", "formData", "**encodeData**"]
and if in == encodeData then we callauthActions.authorizeApplication(auth)

@Yaima In this scenario, client ID and client secret cannot (and should not) be described as parameters. Authorization: Basic base64(value1:value2) request header is handled by security definitions instead. Here's a more detailed example:

paths:
  /v1/oauth/token:
    post:
      summary: Get access token
      description: >-
        Token request must be authenticated using Basic authentication, with the client ID
        as the username and client secret as the password. That is, the token request must
        include the following header:

            Authorization: Basic base64(client_id:client_secret)

        **When testing the API call in Swagger UI, click the lock icon to specify
        the client ID and secret for authentication.**
      security:
        - TokenRequestBasicAuth: []
      consumes:
        - application/x-www-form-urlencoded
      parameters:
        - in: formData
          name: grant_type
          required: true
          type: string
          enum: [client_credentials]
      responses:
        200:
          description: OK

securityDefinitions:
  TokenRequestBasicAuth:
    type: basic
    description: >-
      Authentication for the OAuth 2 token request (`/v1/oauth/token`).
      Use client ID as the username and client secret as the password.

To test the API call in Swagger UI, click the authorize button and enter the client ID and secret in the authorization dialog. They send the request. The request will be sent with the properly encoded Authorization header. The security definition (TokenRequestBasicAuth) is responsible for constructing the Authorization header.

This is how it can be done using standard OpenAPI syntax and vanilla Swagger UI.

If you mean you want to display client_id and client_secret in the Parameters list instead (along with grant_type), then you'll need to implement custom logic in your Swagger UI. For example, you could use extension properties (x-...) to describe the client ID and secret, like so:

parameters:
  - in: formData
    name: grant_type
    required: true
    type: string
    enum: [client_credentials]
x-parameters:  # <---------
  - client_id
  - client_secret

and add code that would display them and then build the Authorization header based on their values. @shockey might have more ideas about how such customization could be implemented.

Thanks for the detailed walkthrough @hkosova. My swagger doc has security and securityDefinitions defined. I was trying to document the /post for the token request outside the pop-up window, in details.
For now, I ended up removing the Try Out button from it, to still keep the endpoint documentation visible but hiding any working logic around it, so if someone is exploring the API docs and they don't want to try them, they can still read the /post logic outside the Authorize pop-up.

Closing due to inactivity.

This is simply to keep our issue tracker clean - feel free to comment if there are any further thoughts or concerns, and we'll be happy to reopen this issue.

In closing: @Yaima, you can document your /token endpoint the way you're describing, but you won't be able to take advantage of the built-in encoding+request flow that Swagger UI has. Effectively, that means you'll have to do your base64-encoding by hand for now.

Was this page helpful?
0 / 5 - 0 ratings