Swagger supports security of api key, but that seems to be limited to a single parameter.
Is there a way to define a set of parameters (key and secret) that are expected as parameters in a request?
Or is the only way just to skip the security scheme, and just add those parameters to every request?
Yes, OpenAPI (Swagger) 2.0 and 3.0 let you define multiple security definitions and mark an operation as requiring multiple securities, such as a pair of API keys.
In the following example, I'm defining two API keys, Key and SecretKey, both of which should be present in the headers of each request in order to get authenticated.
swagger: '2.0'
info:
version: 0.0.0
title: Simple API
securityDefinitions:
key:
type: apiKey
in: header
name: Key
secret_key:
type: apiKey
in: header
name: SecretKey
# Or if you use OpenAPI 3.0:
# components:
# securitySchemes:
# key:
# type: apiKey
# in: header
# name: Key
# secret_key:
# type: apiKey
# in: header
# name: SecretKey
paths:
/:
get:
# Both 'Key' and 'SecretKey' must be used together
security:
- key: []
secret_key: []
responses:
200:
description: OK
Note that this is different from
security:
- key: []
- secret_key: [] # <-- Note the leading dash here
which means the endpoint expects either Key or SecretKey, but not both.
Related
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: {}
Running latest (and now old due to the switchover to flask REST-X) flask RESTPlus using the authorization functionality for the swagger interface with a Bearer token as follows:
authorizations = {
'apikey': {
'type': 'apiKey',
'in': 'header',
'name': 'Bearer '
}
But although the "Authorise" box comes up in the swagger interface, and I can put a token in there, it doesn't get added to the requests coming out or the curl format that swagger provides, so we can see clearly it's not being picked up. What's going on here and how do I fix it?
Make sure the code also has annotations that would add security to individual operations or globally. This is needed to actually attach the Authorization header to operations.
In other words, the generated OpenAPI definition should contain the following.
If using OpenAPI 2.0:
swagger: '2.0'
securityDefinitions:
apikey:
type: apiKey
in: header
name: Authorization
security:
- apiKey: []
If using OpenAPI 3.0:
openapi: 3.0.0
components:
securitySchemes:
apikey:
type: apiKey
in: header
name: Authorization
# or using OAS3 Bearer auth scheme
# apiKey:
# type: http
# scheme: bearer
security:
- apiKey: []
i get this error on swagger editor when using the auth0
Schema error at securityDefinitions.auth0
is not exactly one from <#/definitions/basicAuthenticationSecurity>,<#/definitions/apiKeySecurity>,<#/definitions/oauth2ImplicitSecurity>,<#/definitions/oauth2PasswordSecurity>,<#/definitions/oauth2ApplicationSecurity>,<#/definitions/oauth2AccessCodeSecurity>
Jump to line 67
where my .yaml file is like:
securityDefinitions:
auth0:
type: oauth2
authorizationUrl: https://domain.auth0.com/authorize
flow: implicit
tokenName: id_token
scopes:
openid: Grant access to user
apiKey:
type: apiKey
name: api-key
in: query
apiKey1:
type: apiKey
name: api-key
in: header
what am i missing?
Remove tokenName - it's not a supported field.
Check the specification to see which fields are allowed in securityDefinitions:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#securitySchemeObject
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.
I'm preparing my API documentation by doing it per hand and not auto generated. There I have headers that should be sent to all APIs and don't know if it is possible to define parameters globally for the whole API or not?
Some of these headers are static and some has to be set when call to API is made, but they are all the same in all APIs, I don't want to copy and paste parameters for each API and each method as this will not be maintainable in the future.
I saw the static headers by API definition but there is no single document for how somebody can set them or use them.
Is this possible at all or not?
It depends on what kind of parameters they are.
The examples below are in YAML (for readability), but you can use http://www.json2yaml.com to convert them to JSON.
Security-related parameters: Authorization header, API keys, etc.
Parameters used for authentication and authorization, such as the Authorization header, API key, pair of API keys, etc. should be defined as security schemes rather than parameters.
In your example, the X-ACCOUNT looks like an API key, so you can use:
swagger: "2.0"
...
securityDefinitions:
accountId:
type: apiKey
in: header
name: X-ACCOUNT
description: All requests must include the `X-ACCOUNT` header containing your account ID.
# Apply the "X-ACCOUNT" header globally to all paths and operations
security:
- accountId: []
or in OpenAPI 3.0:
openapi: 3.0.0
...
components:
securitySchemes:
accountId:
type: apiKey
in: header
name: X-ACCOUNT
description: All requests must include the `X-ACCOUNT` header containing your account ID.
# Apply the "X-ACCOUNT" header globally to all paths and operations
security:
- accountId: []
Tools may handle security schemes parameters differently than generic parameters. For example, Swagger UI won't list API keys among operation parameters; instead, it will display the "Authorize" button where your users can enter their API key.
Generic parameters: offset, limit, resource IDs, etc.
OpenAPI 2.0 and 3.0 do not have a concept of global parameters. There are existing feature requests:
Allow for responses and parameters shared across all endpoints
Group multiple parameter definitions for better maintainability
The most you can do is define these parameters in the global parameters section (in OpenAPI 2.0) or the components/parameters section (in OpenAPI 3.0) and then $ref all parameters explicitly in each operation. The drawback is that you need to duplicate the $refs in each operation.
swagger: "2.0"
...
paths:
/users:
get:
parameters:
- $ref: '#/parameters/offset'
- $ref: '#/parameters/limit'
...
/organizations:
get:
parameters:
- $ref: '#/parameters/offset'
- $ref: '#/parameters/limit'
...
parameters:
offset:
in: query
name: offset
type: integer
minimum: 0
limit:
in: query
name: limit
type: integer
minimum: 1
maximum: 50
To reduce code duplication somewhat, parameters that apply to all operations on a path can be defined on the path level rather than inside operations.
paths:
/foo:
# These parameters apply to both GET and POST
parameters:
- $ref: '#/parameters/some_param'
- $ref: '#/parameters/another_param'
get:
...
post:
...
If you're talking about header parameters sent by consumer when calling the API...
You can at least define them once and for all in parameters sections then only reference them when needed.
In the example below:
CommonPathParameterHeader, ReusableParameterHeader and AnotherReusableParameterHeader are defined once and for all in parameterson the root of the document and can be used in any parameters list
CommonPathParameterHeaderis referenced in parameters section of /resources and /other-resources paths, meaning that ALL operation of these paths need this header
ReusableParameterHeader is referenced in get /resources meaning that it's needed on this operation
Same thing for AnotherReusableParameterHeader in get /other-resources
Example:
swagger: '2.0'
info:
version: 1.0.0
title: Header API
description: A simple API to learn how you can define headers
parameters:
CommonPathParameterHeader:
name: COMMON-PARAMETER-HEADER
type: string
in: header
required: true
ReusableParameterHeader:
name: REUSABLE-PARAMETER-HEADER
type: string
in: header
required: true
AnotherReusableParameterHeader:
name: ANOTHER-REUSABLE-PARAMETER-HEADER
type: string
in: header
required: true
paths:
/resources:
parameters:
- $ref: '#/parameters/CommonPathParameterHeader'
get:
parameters:
- $ref: '#/parameters/ReusableParameterHeader'
responses:
'200':
description: gets some resources
/other-resources:
parameters:
- $ref: '#/parameters/CommonPathParameterHeader'
get:
parameters:
- $ref: '#/parameters/AnotherReusableParameterHeader'
responses:
'200':
description: gets some other resources
post:
responses:
'204':
description: Succesfully created.
If you're talking about header sent with each API response...
Unfortunately you cannot define reusable response headers.
But at least you can define a reusable response containing these headers for common HTTP responses such as a 500 error.
Example:
swagger: '2.0'
info:
version: 1.0.0
title: Header API
description: A simple API to learn how you can define headers
parameters:
CommonPathParameterHeader:
name: COMMON-PARAMETER-HEADER
type: string
in: header
required: true
ReusableParameterHeader:
name: REUSABLE-PARAMETER-HEADER
type: string
in: header
required: true
AnotherReusableParameterHeader:
name: ANOTHER-REUSABLE-PARAMETER-HEADER
type: string
in: header
required: true
paths:
/resources:
parameters:
- $ref: '#/parameters/CommonPathParameterHeader'
get:
parameters:
- $ref: '#/parameters/ReusableParameterHeader'
responses:
'200':
description: gets some resources
headers:
X-Rate-Limit-Remaining:
type: integer
X-Rate-Limit-Reset:
type: string
format: date-time
/other-resources:
parameters:
- $ref: '#/parameters/CommonPathParameterHeader'
get:
parameters:
- $ref: '#/parameters/AnotherReusableParameterHeader'
responses:
'200':
description: gets some other resources
headers:
X-Rate-Limit-Remaining:
type: integer
X-Rate-Limit-Reset:
type: string
format: date-time
post:
responses:
'204':
description: Succesfully created.
headers:
X-Rate-Limit-Remaining:
type: integer
X-Rate-Limit-Reset:
type: string
format: date-time
'500':
$ref: '#/responses/Standard500ErrorResponse'
responses:
Standard500ErrorResponse:
description: An unexpected error occured.
headers:
X-Rate-Limit-Remaining:
type: integer
X-Rate-Limit-Reset:
type: string
format: date-time
About OpenAPI (fka. Swagger) Next version
The OpenAPI spec (fka. Swagger) will evolve and include the definition of reusable response headers among other things (cf. https://github.com/OAI/OpenAPI-Specification/issues/563).
As per this Swagger issue comment, support for global parameters (including header parameters) is not planned in foreseeable future, but to limit the repetition you should use parameters references as in #Arnaud's answer (parameters: - $ref: '#/parameters/paramX').
also wish some global variables, can be used anywhere.
( even in some examples, so can change common settings globally in ui ).
something like
"hello ${var1}" in shell or javascript.
searched docs many times, not found solution yet.
: (