Swagger same path specified twice - swagger

Is it possible to have same path appear more than once in one API spec which is being rendered by Swagger-UI?
Should I create separate api specs and load two instances of Swagger-UI? What is the best way to handle this?
For ex. I have endpoint called /oauth/token which I want to document with one set of parameters for OAuth Authorization Code flow and the same endpoint /oauth/token documents for client_credentials flow with different set of parameters.
/oauth/token:
post:
summary: token endpoint for authorization_code flow
parameters:
- name: code
type: string
description: Required for Authorization Code Flow
in: formData
required: true
- name: grant_type
type: string
description: Grant Type should be specified as authorization_code
in: formData
required: true
default: authorization_code
enum:
- authorization_code
- client_credentials
- name: client_id
type: string
description: Consumer Key
in: formData
required: true
- name: client_secret
type: string
description: Consumer Secret
in: formData
required: true
- name: endOtherSessions
in: formData
type: boolean
required: false
default: false
description: Optional parameter. Default is false - do not allow concurrent login. Send true to end any other user sessions.
tags:
- OAuth2 Authorization Code
Same endpoint for client_credentials flow
/oauth/token2:
post:
summary: token for client credentials
parameters:
- name: grant_type
type: string
description: Grant Type should be specified as client_credentials
in: formData
required: true
default: client_credentials
enum:
- authorization_code
- client_credentials
- name: client_id
type: string
description: Consumer Key
in: formData
required: true
- name: client_secret
type: string
description: Consumer Secret
in: formData
required: true
tags:
- OAuth2 Client Credentials

Since the question is about OAuth2 rather than a single endpoint with different parameters, then the solution is actually different.
Swagger has a specific way to document authorization methods, including the 4 common OAuth2 flows.
These are described using the Security Definitions Object which is located at the top Swagger object.
Within it, you can define one or more OAuth2 flows. The spec itself provides a sample for the implicit flow, but others follow a similar structure. The difference is by which fields are provided, namely authorizationUrl and tokenUrl (depending on the flow type).
Once you have that, you can specify which security schemes are required. You can specify it for all the operations at the Swagger object or at the Operation level.
The spec allows you to define that a set of security methods are required together, or that the user can choose between given sets.

Related

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

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: {}

role based token authentication with apikey security in openapi swagger connexion

Describing the problem
I was struggeling the last few days to figure out how to use apikey security in openapi, swagger, connexion for role based token authentication. The following OpenAPI 3.0 endpoint definition:
/lab/samples/list:
get:
tags:
- lab
summary: get a list of all registered samples
operationId: list_samples
responses:
"200":
description: successfully returned all available samples and their notification status
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Sample-For-Lab'
x-content-type: application/json
"400":
description: invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/inline_response'
security:
- bearerAuth: ['labuser']
with the corresponding security definition
securitySchemes:
bearerAuth:
type: apiKey
name: Authorization
in: header
x-apikeyInfoFunc: swagger_server.controllers.authorization_controller.check_bearerAuth
So far so good. I built the corresponding server stubs using swagger-codegen, which follow the connexion security model and provide two fields api_key i.e. the bearer token and 'required_scopes' i.e. which should contain 'labuser'. When accessing the endpoint, the controller function is called:
def check_adminuserAuth(api_key, required_scopes):
return {'sample_key' : 'sample_value}
While the bearer token is properly passed, required_scopes is None. So there's no way of actually validating if credentials and permissions shown in the provided token actually match the endpoint's required scope of labuser in the authorization controller. I thought about handling validation in the called endpoints list_systemusers() but the token is no passed on by connexion.
Not supported in OpenAPI 3.0
After doing some digging, I found out that OpenAPI 3.0 provides apiKey validation on a global API level (i.e. authenticated or not), but does not offer support for individual scopes per endpoint. If you want individual scopes, you need to switch to OAuth security. However support for security scopes through apiKey security is coming in OpenAPI 3.1
Workaround
So for now the only way of making bearer token security with individual scopes work, is to actually define a security scheme for every scope e.g.
securitySchemes:
adminuserAuth:
type: apiKey
description: Provide your bearer token in the format **Bearer <token>**
name: Authorization
in: header
x-apikeyInfoFunc: swagger_server.controllers.authorization_controller.check_adminuserAuth
statsuserAuth:
type: apiKey
description: Provide your bearer token in the format **Bearer <token>**
name: Authorization
in: header
x-apikeyInfoFunc: swagger_server.controllers.authorization_controller.check_statsuserAuth
labuserAuth:
type: apiKey
description: Provide your bearer token in the format **Bearer <token>**
name: Authorization
in: header
x-apikeyInfoFunc: swagger_server.controllers.authorization_controller.check_labuserAuth
and on the path definition then add your required security authentication schemes
security:
- labuserAuth: []
- adminuserAuth: []
x-openapi-router-controller: swagger_server.controllers.lab_controller
Now I know by which authorization controller method is called the required scope a user needs to show and therefore can validate it against the ones shown in the token.

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

Should auto generated swagger.json from swashbuckle be valid in swagger editor?

I have a .NET core 2.1 web API which uses Swashbuckle.AspNetCore v3.0.0 to generate the swagger documentation. I can access the swagger UI from the API which works perfectly and I don't receive any errors when using it from the API. I cannot, however, use the swagger.json to publish this API to Azure API Management. When I load the swagger.json in the swagger editor for validation, it complains about a bunch of errors (same errors that Azure complains about). Since the swagger.json is generated from the swagger configured in my API (it's a link right at the top of the swagger UI within my API), why can't it be successfully loaded into the swagger editor or to Azure?
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = settings.AppSettings.ApplicationName + " API", Version = "v1" });
var commentPath = String.Format(#"{0}\{1}.xml", AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.FriendlyName);
c.IncludeXmlComments(commentPath);
});
{"swagger":"2.0","info":{"version":"v1","title":"Route Manager API"},"paths":{"/api/account/Register":{"post":{"tags":["Account"],"summary":"Allows for registering a customer or vendor.","operationId":"ApiAccountRegisterPost","consumes":[],"produces":["text/plain","application/json","text/json","application/xml","text/xml"],"parameters":[{"name":"UserName","in":"query","description":"Unique name of user being registered.","required":true,"type":"string"},{"name":"Password","in":"query","description":"Password for new user.","required":true,"type":"string"},{"name":"ConfirmPassword","in":"query","description":"Confirmation of password that must match.","required":true,"type":"string"},{"name":"Email","in":"query","description":"Email address of registring user.","required":true,"type":"string"}],"responses":{"200":{"description":"Successfully registered customer or vendor.","schema":{"$ref":"#/definitions/IdentityResult"}},"400":{"description":"The RegisterUserDto model was invalid.","schema":{"$ref":"#/definitions/RegisterUserDto"}}}}},"/api/account/ChangePassword":{"post":{"tags":["Account"],"summary":"Allows for changing the users password.","operationId":"ApiAccountChangePasswordPost","consumes":[],"produces":["text/plain","application/json","text/json","application/xml","text/xml"],"parameters":[{"name":"OldPassword","in":"query","required":true,"type":"string","format":"password"},{"name":"NewPassword","in":"query","required":true,"type":"string","format":"password","maxLength":100,"minLength":6},{"name":"ConfirmPassword","in":"query","required":true,"type":"string","format":"password"},{"name":"StatusMessage","in":"query","required":false,"type":"string"}],"responses":{"400":{"description":"The ChangePasswordDto model was invalid.","schema":{"$ref":"#/definitions/ChangePasswordDto"}},"200":{"description":"Password successfully changed"}}}},"/api/account/Logout":{"post":{"tags":["Account"],"summary":"Logs the current user out of the system.","operationId":"ApiAccountLogoutPost","consumes":[],"produces":[],"parameters":[],"responses":{"200":{"description":"Logout successfully performed"}}}},"/api/account/ExternalLogin":{"get":{"tags":["Account"],"summary":"Initiates the external login process for the specified authentication provider.","description":"When an external login is not already associated with a local account, an attempt is made to find one local account with the same email \r\naddress. If one is found, an account is created and associated with the external login. If an account is not found, this method will \r\nreturn the external login email to the caller so they can decide if they want to present an option for the user to provide an \r\nexisting email account or create a new one based off the external login email. If we always created a new account with the external \r\nemail then that would mean we could only associate external logins that have the same email address of an account stored in our system\r\nwhich would essentially allow duplicate accounts to be created for the same physical person.","operationId":"ApiAccountExternalLoginGet","consumes":[],"produces":["text/plain","application/json","text/json","application/xml","text/xml"],"parameters":[{"name":"provider","in":"query","description":"The code for the external login provider that is being used to login.","required":false,"type":"string"},{"name":"returnUrl","in":"query","description":"The return URL that will be called upon a successfully external login.","required":false,"type":"string"}],"responses":{"400":{"description":"Error occured during the external login process. Response should contain error description.","schema":{"$ref":"#/definitions/ExternalLoginConfirmationDto"}},"200":{"description":"Indicate a token was issued and the user has been signed in."},"202":{"description":"Indicates the user was successfully signed in but an account does not exist in our system in which case the email \r\n of the external login is returned in a ExternalLoginModel that should be used to call the ExternalLoginConfirmation action method."}}}},"/api/account/ExternalLoginCallback":{"get":{"tags":["Account"],"summary":"Attempts to sign in a user based on an external sign-in attempt.","description":"This action is called from an external login provider after a client calls ExternalLogin. The results of this call are \r\ndocumented in the ExternalLogin method since the client never calls this method directly.","operationId":"ApiAccountExternalLoginCallbackGet","consumes":[],"produces":["text/plain","application/json","text/json","application/xml","text/xml"],"parameters":[{"name":"returnUrl","in":"query","required":false,"type":"string"},{"name":"remoteError","in":"query","required":false,"type":"string"}],"responses":{"202":{"description":"Indicates the user was successfully signed in but an account does not exist in our system in which case the email \r\n of the external login is returned in a ExternalLoginModel that should be used to call the ExternalLoginConfirmation action method.","schema":{"$ref":"#/definitions/ExternalLoginConfirmationDto"}},"400":{"description":"Error occured during the external login process. Response should contain error description.","schema":{"$ref":"#/definitions/ExternalLoginConfirmationDto"}},"200":{"description":"Indicate a token was issued and the user has been signed in."}}}},"/api/account/ExternalLoginConfirmation":{"post":{"tags":["Account"],"summary":"Associates an external login with an existing user or new user.","description":"In order to successfully associate an email for an existing user to an external credentials such as \r\n facebook, the user must already be authenticated via the external login provider.","operationId":"ApiAccountExternalLoginConfirmationPost","consumes":[],"produces":["text/plain","application/json","text/json","application/xml","text/xml"],"parameters":[{"name":"Email","in":"query","description":"The external email address associated with the external provider login.","required":true,"type":"string"},{"name":"LoginProvider","in":"query","description":"The external provider that was used to authenticate.","required":false,"type":"string"},{"name":"ReturnUrl","in":"query","description":"The return URL that was provided by the client application when requesting an external login request.","required":false,"type":"string"}],"responses":{"400":{"description":"The model was found to be invalid. Response should contain model errors.","schema":{"$ref":"#/definitions/ExternalLoginConfirmationDto"}},"200":{"description":"Successfully associates the account to the external login and redirects to the client return URL."}}}},"/connect/authorize":{"get":{"tags":["Authorization"],"summary":"Provides the authorization endpoint for supporting openid connect code flow","operationId":"ConnectAuthorizeGet","consumes":[],"produces":["text/plain","application/json","text/json"],"parameters":[{"name":"AccessToken","in":"query","required":false,"type":"string"},{"name":"AcrValues","in":"query","required":false,"type":"string"},{"name":"Assertion","in":"query","required":false,"type":"string"},{"name":"Claims","in":"query","required":false,"type":"object"},{"name":"ClaimsLocales","in":"query","required":false,"type":"string"},{"name":"ClientAssertion","in":"query","required":false,"type":"string"},{"name":"ClientAssertionType","in":"query","required":false,"type":"string"},{"name":"ClientId","in":"query","required":false,"type":"string"},{"name":"ClientSecret","in":"query","required":false,"type":"string"},{"name":"Code","in":"query","required":false,"type":"string"},{"name":"CodeChallenge","in":"query","required":false,"type":"string"},{"name":"CodeChallengeMethod","in":"query","required":false,"type":"string"},{"name":"CodeVerifier","in":"query","required":false,"type":"string"},{"name":"Display","in":"query","required":false,"type":"string"},{"name":"GrantType","in":"query","required":false,"type":"string"},{"name":"IdentityProvider","in":"query","required":false,"type":"string"},{"name":"IdTokenHint","in":"query","required":false,"type":"string"},{"name":"LoginHint","in":"query","required":false,"type":"string"},{"name":"MaxAge","in":"query","required":false,"type":"integer","format":"int64"},{"name":"Nonce","in":"query","required":false,"type":"string"},{"name":"Password","in":"query","required":false,"type":"string"},{"name":"PostLogoutRedirectUri","in":"query","required":false,"type":"string"},{"name":"Prompt","in":"query","required":false,"type":"string"},{"name":"RedirectUri","in":"query","required":false,"type":"string"},{"name":"RefreshToken","in":"query","required":false,"type":"string"},{"name":"Request","in":"query","required":false,"type":"string"},{"name":"RequestId","in":"query","required":false,"type":"string"},{"name":"RequestUri","in":"query","required":false,"type":"string"},{"name":"Resource","in":"query","required":false,"type":"string"},{"name":"ResponseMode","in":"query","required":false,"type":"string"},{"name":"ResponseType","in":"query","required":false,"type":"string"},{"name":"Scope","in":"query","required":false,"type":"string"},{"name":"State","in":"query","required":false,"type":"string"},{"name":"Token","in":"query","required":false,"type":"string"},{"name":"TokenTypeHint","in":"query","required":false,"type":"string"},{"name":"Registration","in":"query","required":false,"type":"object"},{"name":"UiLocales","in":"query","required":false,"type":"string"},{"name":"Username","in":"query","required":false,"type":"string"}],"responses":{"200":{"description":"Successfully authenticated via the authorize flow and returns the appropriate access/identity tokens.","schema":{"$ref":"#/definitions/SignInResult"}},"400":{"description":"Indicates the user was authenticated, but the user manager was unable to obtain the user due to a server error."},"403":{"description":"Indicates the authorization request is not allowed because the user is not authenticated."}}}},"/connect/token":{"post":{"tags":["Authorization"],"summary":"Provides the token endpoint for supporting openidconnect token generation.","operationId":"ConnectTokenPost","consumes":[],"produces":["text/plain","application/json","text/json","application/xml","text/xml"],"parameters":[{"name":"AccessToken","in":"query","required":false,"type":"string"},{"name":"AcrValues","in":"query","required":false,"type":"string"},{"name":"Assertion","in":"query","required":false,"type":"string"},{"name":"Claims","in":"query","required":false,"type":"object"},{"name":"ClaimsLocales","in":"query","required":false,"type":"string"},{"name":"ClientAssertion","in":"query","required":false,"type":"string"},{"name":"ClientAssertionType","in":"query","required":false,"type":"string"},{"name":"ClientId","in":"query","required":false,"type":"string"},{"name":"ClientSecret","in":"query","required":false,"type":"string"},{"name":"Code","in":"query","required":false,"type":"string"},{"name":"CodeChallenge","in":"query","required":false,"type":"string"},{"name":"CodeChallengeMethod","in":"query","required":false,"type":"string"},{"name":"CodeVerifier","in":"query","required":false,"type":"string"},{"name":"Display","in":"query","required":false,"type":"string"},{"name":"GrantType","in":"query","required":false,"type":"string"},{"name":"IdentityProvider","in":"query","required":false,"type":"string"},{"name":"IdTokenHint","in":"query","required":false,"type":"string"},{"name":"LoginHint","in":"query","required":false,"type":"string"},{"name":"MaxAge","in":"query","required":false,"type":"integer","format":"int64"},{"name":"Nonce","in":"query","required":false,"type":"string"},{"name":"Password","in":"query","required":false,"type":"string"},{"name":"PostLogoutRedirectUri","in":"query","required":false,"type":"string"},{"name":"Prompt","in":"query","required":false,"type":"string"},{"name":"RedirectUri","in":"query","required":false,"type":"string"},{"name":"RefreshToken","in":"query","required":false,"type":"string"},{"name":"Request","in":"query","required":false,"type":"string"},{"name":"RequestId","in":"query","required":false,"type":"string"},{"name":"RequestUri","in":"query","required":false,"type":"string"},{"name":"Resource","in":"query","required":false,"type":"string"},{"name":"ResponseMode","in":"query","required":false,"type":"string"},{"name":"ResponseType","in":"query","required":false,"type":"string"},{"name":"Scope","in":"query","required":false,"type":"string"},{"name":"State","in":"query","required":false,"type":"string"},{"name":"Token","in":"query","required":false,"type":"string"},{"name":"TokenTypeHint","in":"query","required":false,"type":"string"},{"name":"Registration","in":"query","required":false,"type":"object"},{"name":"UiLocales","in":"query","required":false,"type":"string"},{"name":"Username","in":"query","required":false,"type":"string"}],"responses":{"200":{"description":"Successfully generates the appropriate access/identity tokens.","schema":{"$ref":"#/definitions/SignInResult"}},"400":{"description":"Indicates an error while attempting to generate an authentication token.","schema":{"$ref":"#/definitions/OpenIdConnectResponse"}},"403":{"description":"Indicates the authorization request is not allowed because the user is not authenticated."}}}},"/api/EntityActions":{"get":{"tags":["EntityAction"],"summary":"List endpoints for all enabled entity actions.","operationId":"ApiEntityActionsGet","consumes":[],"produces":[],"parameters":[],"responses":{"200":{"description":"Success"}}}},"/api/Environments":{"get":{"tags":["Environments"],"summary":"Returns all available environments.","description":"This method return all public environments. If the caller has been authenticated, additional environments configured\r\nfor the identity will also be returned.","operationId":"ApiEnvironmentsGet","consumes":[],"produces":["text/plain","application/json","text/json","application/xml","text/xml"],"parameters":[],"responses":{"200":{"description":"Environments successfully returned","schema":{"uniqueItems":false,"type":"array","items":{"$ref":"#/definitions/ApplicationEnvironmentDto"}}},"500":{"description":"Unexpected error while retrieving available environments"}}}},"/api/Environments/{clientID}":{"get":{"tags":["Environments"],"summary":"Returns the set of environment configured for a given clientID","description":"This method return all public environments. If the caller has been authenticated, additional environments configured\r\nfor the identity will also be returned.","operationId":"ApiEnvironmentsByClientIDGet","consumes":[],"produces":["text/plain","application/json","text/json","application/xml","text/xml"],"parameters":[{"name":"clientID","in":"path","description":"The clientID assigned to the application requesting environments.","required":true,"type":"string"}],"responses":{"200":{"description":"Environments successfully returned","schema":{"uniqueItems":false,"type":"array","items":{"$ref":"#/definitions/ApplicationEnvironmentDto"}}},"400":{"description":"The client ID was not provided."},"500":{"description":"Unexpected error while retrieving available environments"}}}}},"definitions":{"IdentityResult":{"type":"object","properties":{"succeeded":{"type":"boolean","readOnly":true},"errors":{"uniqueItems":false,"type":"array","items":{"$ref":"#/definitions/IdentityError"},"readOnly":true}}},"IdentityError":{"type":"object","properties":{"code":{"type":"string"},"description":{"type":"string"}}},"RegisterUserDto":{"required":["userName","password","confirmPassword","email"],"type":"object","properties":{"userName":{"description":"Unique name of user being registered.","type":"string"},"password":{"description":"Password for new user.","type":"string"},"confirmPassword":{"description":"Confirmation of password that must match.","type":"string"},"email":{"description":"Email address of registring user.","type":"string"}}},"ChangePasswordDto":{"required":["oldPassword","newPassword","confirmPassword"],"type":"object","properties":{"oldPassword":{"format":"password","type":"string"},"newPassword":{"format":"password","maxLength":100,"minLength":6,"type":"string"},"confirmPassword":{"format":"password","type":"string"},"statusMessage":{"type":"string"}}},"ExternalLoginConfirmationDto":{"required":["email"],"type":"object","properties":{"email":{"description":"The external email address associated with the external provider login.","type":"string"},"loginProvider":{"description":"The external provider that was used to authenticate.","type":"string"},"returnUrl":{"description":"The return URL that was provided by the client application when requesting an external login request.","type":"string"}}},"SignInResult":{"type":"object","properties":{"succeeded":{"type":"boolean","readOnly":true},"isLockedOut":{"type":"boolean","readOnly":true},"isNotAllowed":{"type":"boolean","readOnly":true},"requiresTwoFactor":{"type":"boolean","readOnly":true}}},"OpenIdConnectResponse":{"type":"object","properties":{"accessToken":{"type":"string"},"code":{"type":"string"},"error":{"type":"string"},"errorDescription":{"type":"string"},"errorUri":{"type":"string"},"expiresIn":{"format":"int64","type":"integer"},"idToken":{"type":"string"},"refreshToken":{"type":"string"},"resource":{"type":"string"},"scope":{"type":"string"},"state":{"type":"string"},"tokenType":{"type":"string"}}},"ApplicationEnvironmentDto":{"type":"object","properties":{"applicationDisplayName":{"type":"string"},"environmentName":{"type":"string"},"baseUrl":{"type":"string"}}}}}
Here is an example function where the swagger is breaking down the properties of the Openiddict type within this function.
[HttpPost("~/connect/token")]
[ProducesResponseType(typeof(Microsoft.AspNetCore.Identity.SignInResult), 200)]
[ProducesResponseType(typeof(OpenIdConnectResponse), 400)]
public async Task<IActionResult> Exchange(OpenIdConnectRequest request)
{
return Ok(null);
}
That function generates the following swagger.json from swashbuckle
/connect/token:
post:
tags:
- Authorization
summary: Provides the token endpoint for supporting openidconnect token generation.
operationId: ConnectTokenPost
consumes: []
produces:
- text/plain
- application/json
- text/json
- application/xml
- text/xml
parameters:
- name: AccessToken
in: query
required: false
type: string
- name: AcrValues
in: query
required: false
type: string
- name: Assertion
in: query
required: false
type: string
- name: Claims
in: query
required: false
type: object
- name: ClaimsLocales
in: query
required: false
type: string
- name: ClientAssertion
in: query
required: false
type: string
- name: ClientAssertionType
in: query
required: false
type: string
- name: ClientId
in: query
required: false
type: string
- name: ClientSecret
in: query
required: false
type: string
- name: Code
in: query
required: false
type: string
- name: CodeChallenge
in: query
required: false
type: string
- name: CodeChallengeMethod
in: query
required: false
type: string
- name: CodeVerifier
in: query
required: false
type: string
- name: Display
in: query
required: false
type: string
- name: GrantType
in: query
required: false
type: string
- name: IdentityProvider
in: query
required: false
type: string
- name: IdTokenHint
in: query
required: false
type: string
- name: LoginHint
in: query
required: false
type: string
- name: MaxAge
in: query
required: false
type: integer
format: int64
- name: Nonce
in: query
required: false
type: string
- name: Password
in: query
required: false
type: string
- name: PostLogoutRedirectUri
in: query
required: false
type: string
- name: Prompt
in: query
required: false
type: string
- name: RedirectUri
in: query
required: false
type: string
- name: RefreshToken
in: query
required: false
type: string
- name: Request
in: query
required: false
type: string
- name: RequestId
in: query
required: false
type: string
- name: RequestUri
in: query
required: false
type: string
- name: Resource
in: query
required: false
type: string
- name: ResponseMode
in: query
required: false
type: string
- name: ResponseType
in: query
required: false
type: string
- name: Scope
in: query
required: false
type: string
- name: State
in: query
required: false
type: string
- name: Token
in: query
required: false
type: string
- name: TokenTypeHint
in: query
required: false
type: string
- name: Registration
in: query
required: false
type: object
- name: UiLocales
in: query
required: false
type: string
- name: Username
in: query
required: false
type: string
responses:
'200':
description: Successfully generates the appropriate access/identity tokens.
schema:
$ref: '#/definitions/SignInResult'
'400':
description: Indicates an error while attempting to generate an authentication token.
schema:
$ref: '#/definitions/OpenIdConnectResponse'
'403':
description: Indicates the authorization request is not allowed because the user is not authenticated.
[HttpGet("~/connect/authorize")]
[ProducesResponseType(typeof(Microsoft.AspNetCore.Identity.SignInResult), 200)]
public async Task<IActionResult> Authorize(OpenIdConnectRequest request)
{
return Ok(null);
}
Here is what I can tell you from the code you shared:
{
"name": "Claims",
"in": "query",
"required": false,
"type": "object"
}
That does not follow the Open Api Specification:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields-7
If in is any value other than "body"...
Since the parameter is not located at the request body, it is limited to simple types (that is, not an object). The value MUST be one of "string", "number", "integer", "boolean", "array" or "file".
If you manually change those "type": "object" to "type": "string" in the editor the errors will go away.
Change your action to include FromBody:
public async Task<IActionResult> Exchange([FromBody] OpenIdConnectRequest request)
Somehow swashbuckle is getting confused and thinking that is a query param when that should be in the body

auth0, getting Schema error at securityDefinitions.auth0

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

Resources