openapi, springdoc with Swagger Annotations splitting free form application/x-www-form-urlencoded request body into individual characters - swagger-ui

I'm trying to migrate from Springfox to springdoc for our Swagger page, and there is one endpoint that I am having a hard time getting working with springdoc. It is mimicking a OAuth2 token endpoint, taking in an application/x-www-form-urlencoded request body with different grant types allowed. I have the generated openapi documentation below. According to the Swagger page, the free form data should be allowed when using schema of type object. However, when I pass in the example values that worked on Springfox and swagger 2 (grant_type=authorization_code&code=xxxxxxxxxx&client_id=xxxxxxxxxx), the request is built out like this (note the body):
curl -X 'POST' \
'http://localhost:8080/v1/token' \
-H 'accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d '0=g&1=r&2=a&3=n&4=t&5=_&6=t&7=y&8=p&9=e&10=%3D&11=a&12=u&13=t&14=h&15=o&16=r&17=i&18=z&19=a&20=t&21=i&22=o&23=n&24=_&25=c&26=o&27=d&28=e&29=%26&30=c&31=o&32=d&33=e&34=%3D&35=x&36=x&37=x&38=x&39=x&40=x&41=x&42=x&43=x&44=x&45=%26&46=c&47=l&48=i&49=e&50=n&51=t&52=_&53=i&54=d&55=%3D&56=x&57=x&58=x&59=x&60=x&61=x&62=x&63=x&64=x&65=x'
Is there something that I am doing wrong in the openapi yaml, or am I putting the request body in incorrectly on the swagger page?
Swagger documentation:
OpenAPI YAML to be used at https://editor.swagger.io/
openapi: 3.0.1
info:
title: Test API
description: Testing
version: "1.0"
servers:
- url: http://localhost:8080
description: Generated server url
security:
- api: []
paths:
/v1/token:
post:
tags:
- token-controller
description: Oauth 2 Access Token.
operationId: getOauthAccessToken
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
examples:
authorization_code grant type:
description: authorization_code grant type
value: grant_type=authorization_code&code=xxxxxxxxxx&client_id=xxxxxxxxxx
client_credentials grant type:
description: client_credentials grant type
value: grant_type=client_credentials&client_id=xxxxxxxxxx&client_secret=xxxxxxxxxx
refresh_token grant type:
description: refresh_token grant type
value: grant_type=refresh_token&refresh_token=xxxxxxxxxx
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/OauthAccessTokenResponseView_V1'
components:
schemas:
OauthAccessTokenResponseView_V1:
type: object
properties:
scope:
type: string
access_token:
type: string
refresh_token:
type: string
token_type:
type: string
expires_in:
type: integer
format: int64
description: 'The Oauth 2 Access Token response: https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/'
securitySchemes:
api:
type: http
scheme: bearer

Your definition looks fine. This is a bug (or limitation?) in Swagger UI related to OpenAPI 3 examples keyword and form data. Please report it in the issue tracker: https://github.com/swagger-api/swagger-ui/issues
I could not find a working way to provide multiple examples for form data.
From the documentation point of view, I would recommend updating the request body schema to define the exact expected properties. Below is one possible variant that uses oneOf and property-level example values. But unfortunately there are other known issues with the rendering and "try it out" for form data with oneOf.
requestBody:
content:
application/x-www-form-urlencoded:
schema:
oneOf:
- $ref: '#/components/schemas/AuthorizationCodeTokenRequest'
- $ref: '#/components/schemas/ClientCredentialsTokenRequest'
- $ref: '#/components/schemas/RefreshTokenRequest'
...
components:
schemas:
AuthorizationCodeTokenRequest:
type: object
required:
- grant_type
- code
- client_id
properties:
grant_type:
type: string
enum: [authorization_code]
code:
type: string
example: xxxxxxxxxx
client_id:
type: string
example: xxxxxxxxxx
ClientCredentialsTokenRequest:
type: object
required:
- grant_type
- client_id
- client_secret
properties:
grant_type:
type: string
enum: [client_credentials]
client_id:
type: string
example: xxxxxxxxxx
client_secret:
type: string
format: password
example: xxxxxxxxxx
RefreshTokenRequest:
type: object
required:
- grant_type
- refresh_token
properties:
grant_type:
type: string
enum: [refresh_token]
refresh_token:
type: string
format: password
example: xxxxxxxxxx
Do you actually need to document the payload for the token endpoint? If it's a standard OAuth 2.0 token endpoint as per RFC 6749, you could define it in securitySchemes instead:
paths:
/something:
get:
description: One of the endpoints that require OAuth Bearer token.
security:
- oauth2: [] # <-----
responses:
...
components:
securitySchemes:
oauth2: # <-----
type: oauth2
flows:
authorizationCode:
authorizationUrl: '???' # TODO
tokenUrl: /v1/token
refreshUrl: '???' # TODO
scopes: {}
clientCredentials:
tokenUrl: /v1/token
refreshUrl: '???' # TODO
scopes: {}

Related

How to keep access_token parameter from login for next post requests

In swagger With api 3 version I have login described as :
/login:
post:
tags:
- user login
summary: User login
responses:
'200':
description: Successful login
content:
application/json:
schema:
$ref: '#/components/schemas/UserLogin'
'400':
description: Invalid login
operationId: postLogin
requestBody:
description: Login user fields
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
email:
type: string
default: admin#site.com
password:
type: string
default: 111111
required:
- email
- password
and if login is successfull amonth returned data I have access_token field.
With schema described as :
components:
schemas:
UserLogin:
properties:
access_token:
type: string
user:
$ref: '#/components/schemas/UserLogin'
token_type:
type: string
user_avatar_path:
type: string
usersGroups:
type: array
expires_in:
type: integer
I need to use this access_token value for next post requests to get access to authorized pages.
How can I do this in swagger. Seems I can not copypaste access_token value from login requeest for
my post requests, asthey do not access_token parameter ?
MODIFIED BLOCK:
I found how to copypaste access_token from login : https://prnt.sc/rs3ck6
/personal/profile url to read profile data has no in params in qiuery, so I defined access_token as :
securitySchemes:
ApiKeyAuth: # arbitrary name for the security scheme
type: apiKey
in: header # I suppose it must be "header"
name: access_token
But how to add access_token to header of my /personal/profile ?
I see : https://prnt.sc/rs3i90
and clciking on button with Lock sign I see modal dialog “Available authorizations”, which is empty.
I suppose I have to select access_token from it?
Thanks!
What is in my mind is API Keys authentication. This will reduce times you need to copy paste your access_token.
Assume you need to pass access_token via query string on each POST request, then you could set up authentication globally in swagger like this:
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
name: access_token
in: header
security:
- ApiKeyAuth: []
or, if you are using Bearer authentication:
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
security:
- bearerAuth: []
After you get an access_token from /login call, you could click Authorize button under API information, and set it there. Then all the subsequent calls made via Swagger UI should automatically have access_token in the query string like this:
https://petstore.swagger.io/v2/login?access_token=1234

Swagger how to link operation return value as authorization

I'm writing the swagger under OAS 3.0.2 specification. And wondering if it is possible to set the authorization value (BearerAuth) through the operation return value.
Now I need to call the api/login first and then copy return token and paste to authorize panel. Is there have better way to auto link the value between operation and security?
I've tried to use Links, but I am not sure that support on security. (The official document do not mention the way to implement on security)
paths:
/login:
post:
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
account:
type: string
password:
type: string
responses:
'200':
description: data.apiToken
content:
application/json:
schema:
type: object
properties:
data:
type: object
description: data
properties:
apiToken:
type: string
description: I need this as authorization value
links:
ApiToken:
operationId: apiToken
parameters:
apiToken: '$response.body#/data.apiToken'
The login was success, and response body like:
{
"data":{
"apiToken": "xxxxxx"
}
}
But next step I have no idea how to do. The response is 401 because token not being sent in headers (...I'm not surprise).
/someapi:
get:
summary: This API need auth to get data
operationId: apiToken
security:
- BearerAuth: [apiToken]
responses:
'401':
description: Not work
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
If I copy/paste manually, it could be authorized successfully. Is there any way to solve this issue or just not support this feature right now? Thank you so much.

How to define different responses for same HTTP status code in OpenAPI (Swagger)?

I'm writing an OpenAPI spec for an existing API. This API returns status 200 for both success and failure, but with a different response structure.
For example, in the signup API, if the user signed up successfully, the API sends status 200 with the following JSON:
{
"result": true,
"token": RANDOM_STRING
}
And if there is a duplicated user, the API also sends status 200, but with the following JSON:
{
"result": false,
"errorCode": "00002", // this code is duplicated error
"errorMsg": "duplicated account already exist"
}
In this case, how to define the response?
This is possible in OpenAPI 3.0 but not in 2.0.
OpenAPI 3.0 supports oneOf for specifying alternate schemas for the response. You can also add multiple response examples, such as successful and failed responses. Swagger UI supports multiple examples since v. 3.23.0.
openapi: 3.0.0
...
paths:
/something:
get:
responses:
'200':
description: Result
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/ApiResultOk'
- $ref: '#/components/schemas/ApiResultError'
examples:
success:
summary: Example of a successful response
value:
result: true
token: abcde12345
error:
summary: Example of an error response
value:
result: false
errorCode: "00002"
errorMsg: "duplicated account already exist"
components:
schemas:
ApiResultOk:
type: object
properties:
result:
type: boolean
enum: [true]
token:
type: string
required:
- result
- token
ApiResultError:
type: object
properties:
result:
type: boolean
enum: [false]
errorCode:
type: string
example: "00002"
errorMsg:
type: string
example: "duplicated account already exist"
In OpenAPI/Swagger 2.0, you can only use a single schema per response code, so the most you can do is define the varying fields as optional and document their usage in the model description or operation description.
swagger: "2.0"
...
definitions:
ApiResult:
type: object
properties:
result:
type: boolean
token:
type: string
errorCode:
type: string
errorMsg:
type: string
required:
- result

Not a valid securityDefinitions definition - swagger for Auth0

I have the following spec.yaml file
swagger: '2.0'
info:
title: Store API
version: "0.3.5"
host: SELF_URL_REPLACED_BY_APP
schemes:
- https
basePath: /
produces:
- application/json
tags:
- name: account
- name: transcripts
security:
- auth0:
- openid
- apiKey: []
securityDefinitions:
auth0:
type: oauth2
authorizationUrl: https://store.auth0.com/authorize
flow: implicit
tokenName: id_token
scopes:
openid: Grant access to user
apiKey:
type: apiKey
name: Authorization
in: header
I get this error when i try to validate it in http://editor.swagger.io/:
✖ Swagger Error
Not a valid securityDefinitions definition
Jump to line 19
Details
Object
code: "ONE_OF_MISSING"
params: Array [0]
message: "Not a valid securityDefinitions definition"
path: Array [2]
schemaId: "http://swagger.io/v2/schema.json#"
inner: Array [6]
level: 900
type: "Swagger Error"
description: "Not a valid securityDefinitions definition"
lineNumber: 19
What am I missing? I am able to login using Auth0 and everything seems to work fine.
Any advice is much appreciated.
tokenName is not a valid property of the SecurityDefinitions object.
However your Swagger definition has other errors - such as no paths - which may cause it to give incorrect validation errors about securityDefinitions as you're editing.
The following for instance should validate fine:
swagger: '2.0'
info:
title: Store API
version: "0.3.5"
host: SELF_URL_REPLACED_BY_APP
schemes:
- https
basePath: /
produces:
- application/json
tags:
- name: account
- name: transcripts
paths:
/pets:
get:
description: Returns all pets from the system that the user has access to
produces:
- application/json
responses:
'200':
description: A list of pets.
schema:
type: array
items:
type: string
security:
- auth0:
- openid
- apiKey: []
securityDefinitions:
auth0:
type: oauth2
authorizationUrl: https://store.auth0.com/authorize
flow: implicit
scopes:
openid: Grant access to user
apiKey:
type: apiKey
name: Authorization
in: header
Also the security section does not belong at the top level, but should be placed under each API method (see above definition for an example) to specify which security definitions should be applied to that API.

Swagger UI watch security specifications

I am documenting an API with Swagger, is the first time I use Swagger. When I am using the swagger editor I am able to document and see what I want to see. However, when I put the same yaml file in the swagger ui, I am not able to see my security definitions. Could be that I am doing something wrong? or is just not possible?
securityDefinitions:
clientId:
type: apiKey
name: x_client_id
in: header
accessToken:
type: apiKey
name: access_token
in: header
security:
- clientId: []
- accessToken: []
And an example where I use
/auth/signup:
post:
description: register a user
security:
- accessToken: []
parameters:
- name: User
in: body
required: true
schema:
$ref: '#/definitions/UserRequest'
responses:
200:
description: SuccessfulResponse
schema:
$ref: '#/definitions/AuthSuccessfulResponse'
400:
description: Error
schema:
$ref: '#/definitions/BadRequest'
thank you
Currently yes, the security definitions are not enforced dynamically. This will be resolved in a day or so when https://github.com/swagger-api/swagger-ui/pull/2014 is merged.

Resources