diff --git a/README.md b/README.md index bba73e4..58c416a 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,52 @@ -# OpenAPI Initiative (OAI) Workflows Special Interest Group - -This is a public repository for managing work around the OAI Workflows Special Interest Group (SIG-Workflows), -providing a single place to manage artifacts, discussions, projects, and other aspects relating to how workflows can be represented using, or in combination with, the OpenAPI specification. - -## Charter / Motivation - -Being able to express specific sequences of calls and articulate the dependencies between them to achieve a particular goal is desirable in the context of an API specification. -Our aim is to propose an enhancement to the current OpenAPI, or accompanying specification (or means), that can define sequences of calls and their dependencies to be expressed in the context of delivering a particular outcome or set of outcomes. - -The creation of the SIG-Workflows group is inspired by the need to store sequences of calls in the context of specific tests, and in order to communicate the particulars of a complex set of security related calls such as when using OAuth2 and the Financial-grade API security profile of OpenID Connect. - -However, such a definition will be useful for understanding how to implement any dependent sequence of functional calls for any user of Open API such as authorization calls, redirects and web hooks in order to achieve a certain technical or functional outcome. - -Optimally, it should be possible to articulate these workflows in a human and machine readable manner, thus improving the capability of API specifications to tell the story of the API in a manner that can improved the consuming developer experience and understanding of an API specified using OpenAPI. - -**Key focus areas** -- **Context** - How to define quickly and easily what goal and key functions of an API are, and how to represent that in a specification -- **Workflows** - Handling key and complex sequences which may involve the reuse of endpoints for multiple uses, like token calls in a FAPI compliant sequence, in both a human and machine readable way, supporting both understanding and automation -- **Tooling** - How to best integrate to tools and provide machine readable context for those tools so that the spec can integrate with the tools used by developers - - - -## Special Interest Group (SIG) - -The current SIG is made up of the following individuals, and feel free to submit an issue requesting to be added. - -### Champions - -- David O'Neill ([CEO, APImetrics](https://www.linkedin.com/in/davidon/)) -- Kin Lane ([Chief Evangelist, Postman](https://www.linkedin.com/in/kinlane/)) - -### Contributors - -- Nick Denny ([VP Engineering, APImetrics](https://www.linkedin.com/in/nickdenny/)) -- Frank Kilcommins ([API Evangelist, SmartBear](https://www.linkedin.com/in/frank-kilcommins)) -- Mike Ralphson ([OpenAPI Specification Lead, Postman](https://www.linkedin.com/in/mikeralphson/)) -- Alessandro Duminuco ([Senior Technical Leader, Cisco](https://www.linkedin.com/in/alessandroduminuco/)) -- Mark Haine ([Founder, Considrd Consulting](https://www.linkedin.com/in/mark-haine/)) -- Phil Sturgeon ([Dev Rel, Stoplight](https://www.linkedin.com/in/philipsturgeon/)) - - -## Getting Involved - -This working group is just getting started, but feel free to get involved via one (or more) of the channels below. - -- [Bi-weekly Call](https://github.com/OAI/sig-workflows/discussions/5) - Wednesdays at 09:00 AM PDT -- [Discussions](https://github.com/OAI/sig-workflows/discussions) - Use the GitHub discussions to ask questions, provide opinions and engage with the group -- [Issues](https://github.com/OAI/sig-workflows/issues) - Feel free to submit a Github issue with any question or comment about the working group -- [Projects](https://github.com/OAI/sig-workflows/projects) - Keep up to speed on the various projects occurring via Github projects for this group -- Slack - if you have access to the OpenAPI slack workspace, then join the `sig-workflows` channel. If you do not have access, please request access by emailing `operations@openapis.org`. +# OpenAPI Initiative (OAI) Workflows Special Interest Group + +This is a public repository for managing work around the OAI Workflows Special Interest Group (SIG-Workflows), +providing a single place to manage artifacts, discussions, projects, and other aspects relating to how workflows can be represented using, or in combination with, the OpenAPI specification. + +## Charter / Motivation + +Being able to express specific sequences of calls and articulate the dependencies between them to achieve a particular goal is desirable in the context of an API specification. +Our aim is to propose an enhancement to the current OpenAPI, or accompanying specification (or means), that can define sequences of calls and their dependencies to be expressed in the context of delivering a particular outcome or set of outcomes. + +The creation of the SIG-Workflows group is inspired by the need to store sequences of calls in the context of specific tests, and in order to communicate the particulars of a complex set of security related calls such as when using OAuth2 and the Financial-grade API security profile of OpenID Connect. + +However, such a definition will be useful for understanding how to implement any dependent sequence of functional calls for any user of Open API such as authorization calls, redirects and web hooks in order to achieve a certain technical or functional outcome. + +Optimally, it should be possible to articulate these workflows in a human and machine readable manner, thus improving the capability of API specifications to tell the story of the API in a manner that can improved the consuming developer experience and understanding of an API specified using OpenAPI. + +**Key focus areas** +- **Context** - How to define quickly and easily what goal and key functions of an API are, and how to represent that in a specification +- **Workflows** - Handling key and complex sequences which may involve the reuse of endpoints for multiple uses, like token calls in a FAPI compliant sequence, in both a human and machine readable way, supporting both understanding and automation +- **Tooling** - How to best integrate to tools and provide machine readable context for those tools so that the spec can integrate with the tools used by developers + + + +## Special Interest Group (SIG) + +The current SIG is made up of the following individuals, and feel free to submit an issue requesting to be added. + +### Champions + +- David O'Neill ([CEO, APImetrics](https://www.linkedin.com/in/davidon/)) +- Kin Lane ([Chief Evangelist, Postman](https://www.linkedin.com/in/kinlane/)) + +### Contributors + +- Nick Denny ([VP Engineering, APImetrics](https://www.linkedin.com/in/nickdenny/)) +- Frank Kilcommins ([API Evangelist, SmartBear](https://www.linkedin.com/in/frank-kilcommins)) +- Mike Ralphson ([OpenAPI Specification Lead, Postman](https://www.linkedin.com/in/mikeralphson/)) +- Alessandro Duminuco ([Senior Technical Leader, Cisco](https://www.linkedin.com/in/alessandroduminuco/)) +- Mark Haine ([Founder, Considrd Consulting](https://www.linkedin.com/in/mark-haine/)) +- Phil Sturgeon ([Dev Rel, Stoplight](https://www.linkedin.com/in/philipsturgeon/)) +- Kevin Duffey ([Tech Lead, Postman](https://www.linkedin.com/in/kmd/)) + + +## Getting Involved + +This working group is just getting started, but feel free to get involved via one (or more) of the channels below. + +- [Bi-weekly Call](https://github.com/OAI/sig-workflows/discussions/5) - Wednesdays at 09:00 AM PDT +- [Discussions](https://github.com/OAI/sig-workflows/discussions) - Use the GitHub discussions to ask questions, provide opinions and engage with the group +- [Issues](https://github.com/OAI/sig-workflows/issues) - Feel free to submit a Github issue with any question or comment about the working group +- [Projects](https://github.com/OAI/sig-workflows/projects) - Keep up to speed on the various projects occurring via Github projects for this group +- Slack - if you have access to the OpenAPI slack workspace, then join the `sig-workflows` channel. If you do not have access, you're welcome to join by clicking [here](https://communityinviter.com/apps/open-api/openapi) diff --git a/examples/1.0.0/FAPI-PAR.openapi.yaml b/examples/1.0.0/FAPI-PAR.openapi.yaml new file mode 100644 index 0000000..7d27c9d --- /dev/null +++ b/examples/1.0.0/FAPI-PAR.openapi.yaml @@ -0,0 +1,639 @@ +openapi: '3.0.0' +info: + version: '1.0.0' + title: 'Authentication API' + description: | + ## OAuth2 and OpenID Connect are used to handle the security flows relating to API access. + + These interfaces are used as part of the PSD2 API journeys there is a + [Getting Started Guide](https://developer.example.com) + and use case focussed developer documentation is available for the following cases: + 1. [Delegated SCA](https://developer.example.com) + 2. [Redirect based Account Access](https://developer.example.com) + 3. [Redirect based Payments](https://developer.example.com) + + The OAuth2 and OpenID interfaces are used in three sequences depending on the particular + requirements of the use cases. + + When the third party app needs to get access without end-user involvement the Token + endpoint is used to get an access token. This is called the "Client Credentials Grant" of + OAuth2. The result of this is an access token than can be used to call some functional APIs. + + When user interaction is required the "Authorization Code" grant is used. In this + implementation it consists of a sequence of calls. + + *how far do we take this? include Create Consent and Init Payment at the start? include account and payment APIs at the end?* + + 1. PAR - Pushed Authorization Request - API Call + 2. Authorize - A web interaction that needs to be passed to a user agent (such as a browser) + 3. Token - An API call requesting the tokens + + ![sequence](https://lh3.googleusercontent.com/fBWv0qA9a-HFCXSpEQrUDyFj-xSSFDw4UmG2ACqnvaC8aClExjE9gmDsdgonSHZBGQ_CZ9T-mYB31w=w3000-h886) + + This sequence of calls returns an Access token, ID_Token and potentially a refresh token. + The access token provided as a result of the authorization code grant can access other APIs. + + The refresh token can be used to request replacement access tokens with the same level of access. + This request is + + ### References + * [RFC6749 OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) + * [RFC6750 The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750) + * [OpenID Connect Core 1.0 incorporating errata set 1](https://openid.net/specs/openid-connect-core-1_0.html) + * [Financial-grade API Security Profile 1.0 - Part 1: Baseline](https://openid.net/specs/openid-financial-api-part-1-1_0.html) + * [Financial-grade API Security Profile 1.0 - Part 2: Advanced](https://openid.net/specs/openid-financial-api-part-2-1_0.html) + * [OAuth 2.0 Pushed Authorization Requests draft-ietf-oauth-par-07](https://tools.ietf.org/html/draft-ietf-oauth-par-07) + * [JOSE Related specs (including JWT, JWT, JWE)](https://datatracker.ietf.org/wg/jose/documents/) + + +servers: + - url: https://api.uat.example.com/ + description: Sandbox - Test Server for registered external parties to use for testing and development + - url: https://api.example.com + description: Production - Live Server providing APIs to registered third parties + +paths: + /.well-known/openid-configuration: + get: + summary: RFC 8414 Well known OAuth 2.0 configuration endpoint + description: | + The standard "OAuth 2.0 Authorization Server Metadata" describing + the configuration including endpoint addresses. The content of this + file is used by clients to confirm details of the configuration of + the OpenID Provider. + Generally speaking the OpenID configuration is not directly required for delivery of use cases. + externalDocs: + url: https://tools.ietf.org/html/rfc8414 + security: [] + operationId: WellKnown + tags: + - OAuth2 + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/WellKnown" + + /public/jwks: + get: + summary: JSON Web Key set + description: | + Retrieve the public server JSON Web Key (JWK) to verify the signature of an issued + token or to encrypt request objects to it. + externalDocs: + url: https://datatracker.ietf.org/doc/rfc7517/ + operationId: JWKS + tags: + - OAuth2 + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/JWKResponse' + 404: + description: Not Found + 500: + description: Internal Server Error + + /as/par.oauth2: + post: + summary: Submits the OAuth 2.0 authorisation request parameters to obtain a request_uri handle for use at the authorisation endpoint. + description: | + A Pushed Authorization request is used to set the parameters for the subsequent Authorization call + + The OAuth2 client sends the signed request object in the POST to the PAR interface to avoid leakage of request parmeters. + + ![PAR](https://lh3.googleusercontent.com/bxiF_yvjeIIDFHxWR8Avae0efhqigSAOPM0t1XzuBihfFWv_yEyZwz1uMCejR7RCl1ytUcvxmFWhVw=w3000-h886) + + This implementation requires PAR to be used. + + **Mutual TLS client authentication is required to access this endpoint** + + As stated in the draft spec : "The pushed authorization request can be composed of any of the parameters + applicable for use at authorization endpoint including those defined + in [RFC6749] as well as all applicable extensions." + + For the purposes of the implementation there are a set of + parameters that will be required for a successful authorization request and + these are listed below in the request object parameter. + + The `consent_id` key in the request body is found in response to the "Init Payment" + or "Create Consent" APIs + externalDocs: + url: https://tools.ietf.org/html/draft-ietf-oauth-par-07 + operationId: Par + tags: + - OAuth2 + parameters: + - name: Content-Type + in: header + schema: + type: string + default: application/x-www-form-urlencoded + enum: + - application/x-www-form-urlencoded + required: true + - name: client_id + in: query + required: true + description: The identifier of the third party provider OAuth client. ClientId is returned during the TPP registration. + schema: + type: string + + - name: client_assertion_type + in: query + required: true + description: Type of assertion be used. In this case it must be "urn:ietf:params:oauth:grant-type:jwt-bearer" + schema: + type: string + default: urn:ietf:params:oauth:grant-type:jwt-bearer + enum: + - urn:ietf:params:oauth:grant-type:jwt-bearer + allowEmptyValue: false + - name: client_assertion + in: query + description: | + Used for PAR client authentication. The assertion contains a JWS, in this an object (base64(JWS)) + signed with JWT signing private key related to the TPP OAuth client. See the Model and the Assertion + object for a detailed description of the content. + required: true + content: + application/json: + schema: + type: object + properties: + iss: + type: string + sub: + type: string + aud: + type: string + exp: + type: string + iat: + type: string + jti: + type: string + requestBody: + description: | + parameters that comprise an authorization request are sent directly to the + pushed authorization request endpoint in the request body + + [PAR Request](https://tools.ietf.org/html/draft-ietf-oauth-par-07#section-2.1) + required: true + content: + application/json: + schema: + type: object + properties: + response_type: + type: string + client_id: + type: string + sub: + type: string + scope: + type: string + prompt: + type: string + code_challenge_method: + type: string + code_challenge: + type: string + state: + type: string + nonce: + type: string + redirect_uri: + type: string + consent_id: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ParResponse' + + links: + PAR_returned_request_uri: + operationId: Authorization + parameters: + request_uri: '$response.body#/request_uri' + description: > + The `request_uri` value returned in the response MUST be used as + the `request_uri` input parameter in `GET /as/authorize.oauth2` when + using the authorization code flow, before it expires. + 400: + description: Bad Request + 401: + description: Unauthorized + 500: + description: Internal Server Error + + /as/authorize.oauth2: + get: + summary: OAuth 2.0 Authorization endpoint + description: | + The OAuth 2.0 authorisation endpoint is where the end-user is redirected to Perform SCA using their browser. + + **This is a Web interface not a REST API** + + This is the standard RFC 6749 authorization endpoint. In this case the request parameters + are pushed in via the PAR endpoint prior to the authorize call and only the request_uri + returned from the PAR request and the client_id is given as input parameters to this call. + The call is normally triggered from the backend via browser based redirect to the + authorization server authorize endpoint. + + ![Authorize](https://lh5.googleusercontent.com/G7vvCF3kSwI5IFleYNjBPBVUB-4tYkfnhHr7FUfsGTL9ffxMr8EzH6CQ_V76YYb1qdfTuZ3-emqnMw=w3000-h886) + + ### External Documentation: + [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html) + + [OAuth2](https://tools.ietf.org/html/rfc6749) + security: [] + operationId: Authorization + tags: + - OAuth2 + parameters: + - name: request_uri + in: query + required: true + description: This parameter is returned by the preceeding /as/par.oauth2 call + schema: + type: string + - name: client_id + in: query + required: true + description: The Client ID issued when the app was registered in the developer portal + schema: + type: string + responses: + 302: + description: | + Redirect to defined redirect uri with the authorization code as a standard OIDC response. + + >**https://**_{your app redirect_uri}_ + + >**?code=**_{Arbirary String}_ + + >**&state=**_{state value from authorization request}_ + + >**&iss=**_https://api.example.com_ + links: + Authorization_Response: + description: > + The `code` value returned in the response MUST be used as + the `request_uri` input parameter in `GET /as/authorize.oauth2` when + using the authorization code flow, before it expires. + operationId: Token + parameters: + code: '$response.path#/code' + 500: + description: Internal Server Error + + /as/token.oauth2: + post: + summary: Token endpoint with client authentication + description: | + There are three different cases where the token endpoint is used + 1. Client Credentials Grant + 2. Authorisation Code Grant + 3. Refresh Grant + + As a result there are different types of token endpoint request and response + There are three request types and two response types. All of these types use the same + interaction but with different request and responses + + ![token](https://lh3.googleusercontent.com/3W6rTo7zGvIj2O0Dm0sTnItr9EDKC6WEn_fN9b8E0hv1vPSNfdyewPzUJBJLuoGMaVNyLnW1PNVA0w=w3000-h886) + + **Mutual TLS client authentication is required to access this endpoint** + + When the **client credentials grant** is being used the Token request has no other calls as pre-requisities. + + When the authorization code grant or refresh grant are being exercised there are dependancies on previous calls. + + In the implementation the **Authorization code flow** depends upon previous calls to: + - /as/par.oauth2 + - /as/authorize.oauth2 + + **The Refresh grant** depends on there being a previous authorization code flow that returned a refresh token. + + operationId: Token + tags: + - OAuth2 + parameters: + - name: Content-Type + in: header + schema: + type: string + default: application/x-www-form-urlencoded + enum: + - application/x-www-form-urlencoded + required: true + - name: client_id + in: query + required: true + description: The identifier of the third party provider OAuth client. ClientId is returned during the TPP registration. + schema: + type: string + - name: client_assertion_type + in: query + required: true + description: Type of assertion be used. In this case it must be "urn:ietf:params:oauth:grant-type:jwt-bearer" + schema: + type: string + default: urn:ietf:params:oauth:grant-type:jwt-bearer + enum: + - urn:ietf:params:oauth:grant-type:jwt-bearer + allowEmptyValue: false + - name: client_assertion + in: query + description: | + Used for PAR client authentication. The assertion contains a JWS, in this an object (base64(JWS)) + signed with JWT signing private key related to the TPP OAuth client. See the Model and the Assertion + object for a detailed description of the content. + required: true + content: + application/json: + schema: + type: object + properties: + iss: + type: string + sub: + type: string + aud: + type: string + exp: + type: string + iat: + type: string + jti: + type: string + requestBody: + description: | + Body of the request made to the Token endpoint - 3 schemas available for different flows + required: true + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/TokenClientCredsRequest' + - $ref: '#/components/schemas/TokenAuthzCodeRequest' + - $ref: '#/components/schemas/TokenRefreshRequest' + responses: + 200: + description: OK + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/TokenClientCredsResponse' + - $ref: '#/components/schemas/TokenAuthzResponse' + 400: + description: Bad Request with a token error code + 401: + description: Unauthorized with a token error code + 500: + description: Internal Server Error + +components: + schemas: + WellKnown: + required: + - issuer + - authorization_endpoint + - token_endpoint + - response_types_supported + properties: + issuer: + type: string + authorization_endpoint: + type: string + token_endpoint: + type: string + revocation_endpoint: + type: string + userinfo_endpoint: + type: string + introspection_endpoint: + type: string + jwks_uri: + type: string + registration_endpoint: + type: string + ping_revoked_sris_endpoint: + type: string + ping_end_session_endpoint: + type: string + device_authorization_endpoint: + type: string + scopes_supported: + type: string + claims_supported: + type: string + response_types_supported: + type: string + response_modes_supported: + type: string + grant_types_supported: + type: string + subject_types_supported: + type: string + id_token_signing_alg_values_supported: + type: string + token_endpoint_auth_methods_supported: + type: string + token_endpoint_auth_signing_alg_values_supported: + type: string + claim_types_supported: + type: string + claims_parameter_supported: + type: string + request_parameter_supported: + type: string + request_uri_parameter_supported: + type: string + request_object_signing_alg_values_supported: + type: string + id_token_encryption_alg_values_supported: + type: string + id_token_encryption_enc_values_supported: + type: string + backchannel_authentication_endpoint: + type: string + backchannel_token_delivery_modes_supported: + type: string + backchannel_authentication_request_signing_alg_values_supported: + type: string + backchannel_user_code_parameter_supported: + type: string + tls_client_certificate_bound_access_tokens: + type: string + mtls_endpoint_aliases: + type: string + + JWKResponse: + description: | + A JSON object containing the server public JWK set in the form of an array of + properties: + keys: + type: array + items: + type: object + properties: + kty: + type: string + use: + type: string + key_ops: + type: string + alg: + type: string + kid: + type: string + x5c: + type: string + x5u: + type: string + x5t: + type: string + x5t#s256: + type: string + + ParResponse: + properties: + expires_in: + type: string + description: The expires in parameter defines the number of seconds when the reference uri expires. + request_uri: + type: string + description: The request uri to the request object in the request to the par endpoint. + + AuthCodeRequest: + required: + - test + properties: + expires_in: + type: string + description: The expires in paremeter defines the number of seconds when the reference uri expires. + request_uri: + type: string + description: The request uri to the request object in the request to the par endpoint. + + AuthCodeResponse1: + properties: + code: + type: string + description: The authorization code that will be used when making the subsequent request to the /as/token.oauth endpoint + state: + type: string + description: The request uri to the request object in the request to the par endpoint. + iss: + type: string + description: The request uri to the request object in the request to the par endpoint. + + TokenClientCredsRequest: + description: Request Schema for the token endpoint in the context of a Client Credentials OAuth2 flow + required: + - grant_type + - scope + properties: + grant_type: + type: string + description: String that defines which OAuth2 grant this request is part of + enum: + - client_credentials + default: client_credentials + scope: + type: string + description: Space delimited list of OAuth2 scopes + + TokenAuthzCodeRequest: + description: Request Schema for the token endpoint in the context of an OAuth2 Authorization code flow + required: + - grant_type + - code + - redirect_uri + - code_verifier + properties: + grant_type: + description: String that defines which OAuth2 grant this request is part of + type: string + default: authorization_code + code: + type: string + description: The authorization code provided as a parameter in the redirect back from the preceeding /as/authorize.oauth2 call + redirect_uri: + type: string + description: The value of the redirect URI that was used in the preceeding /as/authorize.oauth2 call + code_verifier: + type: string + description: The code verifier Proof Key of Code Exchange (PKCE). + + TokenRefreshRequest: + description: Request Schema for the token endpoint in the context of an OAuth2 Refresh flow + required: + - grant_type + - refresh_token + properties: + grant_type: + description: String that defines which OAuth2 grant this request is part of + type: string + enum: + - refresh_token + default: refresh_token + refresh_token: + type: string + description: The refresh_token provided as a parameter in the response from a preceeding /as/token.oauth2 call + scope: + type: string + description: OPTIONAL - space delimited list of scopes that is equal to or a subset of the scopes requested by the preceeding authorization code flow + + TokenClientCredsResponse: + required: + - access_token + - token_type + properties: + access_token: + type: string + description: The access token issued by the server. + token_type: + type: string + description: "bearer" + expires_in: + type: integer + description: The expires in paremeter defines the number of seconds when the access token expires. + scope: + type: string + description: space delimited list of scopes + + TokenAuthzResponse: + required: + - access_token + - token_type + properties: + access_token: + type: string + description: The access token issued by the server. + refresh_token: + type: string + description: The refresh token issued by the server. + token_type: + type: string + description: "bearer" + expires_in: + type: integer + description: The expires in paremeter defines the number of seconds when the access token expires. + scope: + type: string + description: space delimited list of scopes + id_token: + type: string + description: The id token issued by the server. diff --git a/examples/1.0.0/FAPI-PAR.workflow.yaml b/examples/1.0.0/FAPI-PAR.workflow.yaml new file mode 100644 index 0000000..3c5b5bb --- /dev/null +++ b/examples/1.0.0/FAPI-PAR.workflow.yaml @@ -0,0 +1,175 @@ +workflowsSpec: 1.0.0 +info: + title: PAR, Authorization and Token workflow + version: 1.0.0 + description: >- + A workflow describing how to obtain a token from an OAuth2 and OpenID Connect Financial Grade authorization server which can be common for PSD2 API journeys +sources: + - name: auth-api + url: ./FAPI-PAR.openapi.yaml + type: openapi + +workflows: + - workflowId: OIDC-PAR-AuthzCode + summary: PAR, Authorization and Token workflow + description: >- + PAR - Pushed Authorization Request - API Call - https://www.rfc-editor.org/rfc/rfc9126.html + Authorize - A web interaction that needs to be passed to a user agent (such as a browser) https://openid.net/specs/openid-connect-core-1_0.html + Token - An API call requesting the tokens + inputs: + type: object + properties: + client_id: + type: string + description: The identifier of the third party provider OAuth client. ClientId is returned during the TPP registration. + client_assertion: + type: object + description: | + Used for PAR client authentication. The assertion contains a JWS, in this an object `base64(JWS)` + signed with JWT signing private key related to the TPP OAuth client. See the Model and the Assertion + object for a detailed description of the content. + properties: + iss: + type: string + sub: + type: string + aud: + type: string + exp: + type: string + iat: + type: string + jti: + type: string + redirect_uri: + type: string + description: The value of the redirect URI that was used in the previous `/as/authorize.oauth2` call. + code_verifier: + type: string + description: The code verifier Proof Key of Code Exchange (PKCE) + PARrequestBody: + type: object + description: | + Parameters that comprise an authorization request are sent directly to the + pushed authorization request endpoint in the request body + [PAR Request](https://tools.ietf.org/html/draft-ietf-oauth-par-07#section-2.1) + properties: + response_type: + type: string + client_id: + type: string + sub: + type: string + scope: + type: string + prompt: + type: string + code_challenge_method: + type: string + code_challenge: + type: string + state: + type: string + nonce: + type: string + redirect_uri: + type: string + consent_id: + type: string + TokenRequestBody: + type: object + description: Request Schema for the token endpoint in the context of an OAuth2 Authorization code flow (**Note** this is place holder object that will have values replaced dynamically) + properties: + grant_type: + type: string + code: + type: string + redirect_uri: + type: string + code_verifier: + type: string + required: + - grant_type + - code + - redirect_uri + - code_verifier + required: + - PARrequestBody + - TokenRequestBody + steps: + - stepId: PARStep + description: Pushed Authorization Request + operationId: auth-api.PAR + parameters: + - name: client_id + in: query + value: $inputs.client_id + - name: client_assertion_type + in: query + value: 'urn:ietf:params:oauth:grant-type:jwt-bearer' + - name: client_assertion + in: query + value: $inputs.client_assertion + - name: requestBody + in: body + value: $inputs.PARrequestBody + successCriteria: + # assertions to determine step was successful + - $statusCode == 200 + outputs: + request_uri: $response.body.request_uri + + - stepId: AuthzCodeStep + description: OIDC Authorization code request + operationId: auth-api.Authorization + parameters: + - name: request_uri + in: query + value: $steps.PARStep.outputs.request_uri + - name: client_id + in: query + value: $inputs.client_id + successCriteria: + # assertions to determine step was successful + - $statusCode == 302 + outputs: + code: $response.body.code # Not really, this is a query parameter (need a way to represent out-of-band props) + + - stepId: TokenStep + description: Get token from the OIDC Token endpoint + operationId: auth-api.Token + parameters: + - name: client_id + in: query + value: $inputs.client_id + - name: client_assertion_type + in: query + value: 'urn:ietf:params:oauth:grant-type:jwt-bearer' + - name: client_assertion + in: query + value: $inputs.client_assertion + - name: requestBody + in: body + target: '/grant_type' + value: 'authorization_code' + - name: requestBody + in: body + target: '/code' + value: $steps.AuthzCodeStep.outputs.code + - name: requestBody + in: body + target: '/redirect_uri' + value: $inputs.redirect_uri + - name: requestBody + in: body + target: '/code_verifier' + value: $inputs.code_verifier + successCriteria: + # assertions to determine step was successful + - $statusCode == 200 + outputs: + tokenResponse: $response.body + + outputs: + access_token: $steps.TokenStep.outputs.tokenResponse + diff --git a/examples/1.0.0/pet-coupons.openapi.yaml b/examples/1.0.0/pet-coupons.openapi.yaml new file mode 100644 index 0000000..b8cc131 --- /dev/null +++ b/examples/1.0.0/pet-coupons.openapi.yaml @@ -0,0 +1,517 @@ +openapi: 3.0.3 +info: + title: Swagger Petstore - OpenAPI 3.0 + description: Modifies the standard Petstore example to illustrate a workflow in which coupons are discovered and then used in an order. + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: http://swagger.io + - name: store + description: Access to Petstore orders + externalDocs: + description: Find out more about our store + url: http://swagger.io +paths: + /pet: + put: + tags: + - pet + summary: Update an existing pet + description: Update an existing pet by Id + operationId: updatePet + requestBody: + description: Update an existent pet in the store + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Pet' + required: true + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + '405': + description: Validation exception + security: + - petstore_auth: + - write:pets + - read:pets + post: + tags: + - pet + summary: Add a new pet to the store + description: Add a new pet to the store + operationId: addPet + requestBody: + description: Create a new pet in the store + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Pet' + required: true + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + '405': + description: Invalid input + security: + - petstore_auth: + - write:pets + - read:pets + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: false + explode: true + schema: + type: string + default: available + enum: + - available + - pending + - sold + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid status value + security: + - petstore_auth: + - write:pets + - read:pets + /pet/findByTags: + get: + tags: + - pet + summary: Finds Pets by tags + description: Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. + operationId: findPetsByTags + parameters: + - name: tags + in: query + description: Tags to filter by + required: false + explode: true + schema: + type: array + items: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid tag value + security: + - petstore_auth: + - write:pets + - read:pets + /pet/{petId}: + get: + tags: + - pet + summary: Find pet by ID + description: Returns a single pet + operationId: getPetById + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - api_key: [] + - petstore_auth: + - write:pets + - read:pets + post: + tags: + - pet + summary: Updates a pet in the store with form data + description: '' + operationId: updatePetWithForm + parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + schema: + type: integer + format: int64 + - name: name + in: query + description: Name of pet that needs to be updated + schema: + type: string + - name: status + in: query + description: Status of pet that needs to be updated + schema: + type: string + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - write:pets + - read:pets + delete: + tags: + - pet + summary: Deletes a pet + description: delete a pet + operationId: deletePet + parameters: + - name: api_key + in: header + description: '' + required: false + schema: + type: string + - name: petId + in: path + description: Pet id to delete + required: true + schema: + type: integer + format: int64 + responses: + '400': + description: Invalid pet value + security: + - petstore_auth: + - write:pets + - read:pets + /pet/{petId}/coupons: + get: + tags: + - pet + summary: Find a coupon available for a pet + description: Returns a coupon available for the pet, if applicable + operationId: getPetCoupons + parameters: + - name: petId + in: path + description: ID of pet with available coupons + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Coupon' + application/xml: + schema: + $ref: '#/components/schemas/Coupon' + '400': + description: Invalid ID supplied + '404': + description: Pet not found or coupon not available + security: + - api_key: [] + - petstore_auth: + - read:pets + /store/order: + post: + tags: + - store + summary: Place an order for a pet + description: Place a new order in the store + operationId: placeOrder + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Order' + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid input + /store/order/{orderId}: + get: + tags: + - store + summary: Find purchase order by ID + description: For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions. + operationId: getOrderById + parameters: + - name: orderId + in: path + description: ID of order that needs to be fetched + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + application/xml: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid ID supplied + '404': + description: Order not found + delete: + tags: + - store + summary: Delete purchase order by ID + description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + operationId: deleteOrder + parameters: + - name: orderId + in: path + description: ID of the order that needs to be deleted + required: true + schema: + type: integer + format: int64 + responses: + '400': + description: Invalid ID supplied + '404': + description: Order not found +components: + schemas: + Order: + type: object + properties: + id: + type: integer + format: int64 + example: 10 + petId: + type: integer + format: int64 + example: 198772 + quantity: + type: integer + format: int32 + example: 7 + status: + type: string + description: Order Status + example: approved + enum: + - placed + - approved + - delivered + complete: + type: boolean + couponCode: + type: string + example: "SUMMERSALE" + xml: + name: order + Category: + type: object + properties: + id: + type: integer + format: int64 + example: 1 + name: + type: string + example: Dogs + xml: + name: category + Tag: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: tag + Pet: + required: + - name + - price + - photoUrls + type: object + properties: + id: + type: integer + format: int64 + example: 10 + name: + type: string + example: doggie + category: + $ref: '#/components/schemas/Category' + photoUrls: + type: array + xml: + wrapped: true + items: + type: string + xml: + name: photoUrl + price: + type: number + tags: + type: array + xml: + wrapped: true + items: + $ref: '#/components/schemas/Tag' + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold + xml: + name: pet + ApiResponse: + type: object + properties: + code: + type: integer + format: int32 + type: + type: string + message: + type: string + xml: + name: '##default' + Coupon: + type: object + properties: + id: + type: integer + format: int64 + example: 10 + description: + type: string + example: "Summer Sale - 10% off!" + couponCode: + type: string + example: "SUMMERSALE" + xml: + name: coupon + requestBodies: + Pet: + description: Pet object that needs to be added to the store + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: https://petstore3.swagger.io/oauth/authorize + scopes: + write:pets: modify pets in your account + read:pets: read your pets + api_key: + type: apiKey + name: api_key + in: header \ No newline at end of file diff --git a/examples/1.0.0/pet-coupons.workflow.yaml b/examples/1.0.0/pet-coupons.workflow.yaml new file mode 100644 index 0000000..ed099a5 --- /dev/null +++ b/examples/1.0.0/pet-coupons.workflow.yaml @@ -0,0 +1,83 @@ +workflowsSpec: 1.0.0 +info: + title: Petstore - Apply Coupons + version: 1.0.0 + description: >- + Illustrates a workflow whereby a client a) finds a pet in the petstore, + b) finds coupons for that pet, and finally + c) orders the pet while applying the coupons from step b. +sources: + - name: pet-coupons + url: ./pet-coupons.openapi.yaml + type: openapi +workflows: + - workflowId: apply-coupon + summary: Apply a coupon to a pet order. + description: >- + This is how you can find a pet, find an applicable coupon, and apply that coupon in your order. + The workflow concludes by outputting the ID of the placed order. + inputs: + type: object + properties: + my_pet_tags: + type: array + items: + type: string + description: Desired tags to use when searching for a pet, in CSV format: e.g. "puppy, dalmation" + steps: + - stepId: find-pet + operationId: findPetsByTags + parameters: + - name: pet_tags + in: query + value: $inputs.my_pet_tags + successCriteria: + - $statusCode == 200 + outputs: + my_pet_id: $outputs[0].id + # there is some implied selection here - findPetsByTags responds with a list of pets, + # but the client only wants to choose one, and that's what will be provided to the next step. + # not totally sure how to indicate that. + - stepId: find-coupons + description: Find a coupon available for the selected pet. + operationId: getPetCoupons + parameters: + - name: pet_id + in: path + value: $steps.find-pet.outputs.my_pet_id + successCriteria: + - $statusCode == 200 + outputs: + my_coupon_code: $response.body.couponCode + - stepId: place-order + description: Use the coupon to get a discount on the desired pet. + operationId: placeOrder + parameters: + - name: pet_id + in: body + target: $request.body#/petId + value: $steps.find-pet.outputs.my_pet_id + - name: coupon_code + in: body + target: $request.body#/couponCode + value: $steps.find-pet.outputs.my_coupon_code + - name: quantity + in: body + target: $request.body#/quantity + value: 1 + - name: status + in: body + target: $request.body#/status + value: "placed" + - name: complete + in: body + target: $request.body#/complete + value: false + successCriteria: + - $statusCode == 200 + outputs: + my_order_id: $response.body.id + + + outputs: + order_id: $steps.place-order.my_order_id diff --git a/versions/1.0.0.md b/versions/1.0.0.md index ebc8af7..bef7968 100644 --- a/versions/1.0.0.md +++ b/versions/1.0.0.md @@ -391,7 +391,7 @@ Describes a single step parameter. A unique parameter is defined by the combinat Field Name | Type | Description ---|:---:|--- name | string | **REQUIRED**. The name of the parameter. Parameter names are _case sensitive_. - in | string | **REQUIRED**. The name location of the parameter. Possible values are `"path"`, `"query"`, `"header"`, "`cookie`", `"body"`, or `"workflow"`. + in | string | **REQUIRED**. The name location of the parameter. Possible values are `"path"`, `"query"`, `"header"`, `"cookie"`, `"body"`, or `"workflow"`. style | string | Describes how the parameter value will be serialized depending on the location of parameter value. This fixed field is predominately used to express how a _request body_ is to be serialized. For example, when request data (`in` with value `"body"`) is to be serialized as `x-www-form-urlencoded`, the style SHOULD be `"form"`. `in` parameters with values of `"query"`, `"header"`, or "`cookie`" MUST derive their style from the referenced `source` when applicable. target | {JSON Pointer} | A [JSON Pointer](https://tools.ietf.org/html/rfc6901) expression identifying locations to inject the value. Can be useful for targeting specific request body part. value | Any \| {expression} | **REQUIRED**. The value to pass in the parameter. The value can be a constant or an [expression](#runtime-expressions) to be evaluated and passed to the referenced operation or workflow.