openapi: 3.0.2
info:
  description: >
    This is the specification of the bLink 'consent-flow' module API.
    (as implemented by SIX and used by clients (e.g. third party providers)) 
    <hr/>
    
    <b>PLEASE NOTE:</b>
    The work of this initiative has been transferred to SFTI.
    
    See current status at [ca-security](https://github.com/swissfintechinnovations/ca-security/wiki)

  version: "0.1.0-alpha"

  title: "bLink API - consent flow module"
  contact:
    name: SIX BBS AG
    url: 'https://www.six-group.com/en/products-services/banking-services/blink.html'

servers:
  - url: https://api.six-group.com/api/bankingservices/b-link/consent-flow/v3 #SCOPE(SIX_CAAS)
  - url: https://api.six-group.com/api/bankingservices/b-link-consent-3/consent-flow/v3 #SCOPE(SIX,FI)
  - url: https://api.six-group.com/api/consent-flow/v3 #SCOPE(SIX_INTERNAL,SIX_CAAS_INTERNAL)

tags:
  - name: oauth
    description: |
      **oauth**
      OAuth endpoint
  - name: permissions
    description: |
      **Permissions**
      Permissions endpoint

paths:

  '/oauth/par':
    post:
      tags:
        - oauth
      summary: Pushed Authorization Request (PAR)
      description: |
        Initiates a Pushed Authorization Request as defined in [RFC 9126](https://datatracker.ietf.org/doc/html/rfc9126).
        The client pushes the authorization request payload directly to the authorization server,
        receiving a `request_uri` that can be used in a subsequent authorization request.
        This endpoint requires PKCE (RFC 7636) with S256 challenge method.
        This is an OAuth 2.0 endpoint requiring client authentication as appropriate for the client type.
      operationId: pushedAuthorizationRequest
      parameters:
        - $ref: '#/components/parameters/correlation_in_header'
        - $ref: '#/components/parameters/agent_in_header'
        - $ref: '#/components/parameters/targetid_in_header'
        - $ref: '#/components/parameters/psu_ip_in_header'
        - $ref: '#/components/parameters/psu_user_agent_in_header'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/pushedAuthorizationRequest'
      responses:
        '201':
          description: Successfully created pushed authorization request
          headers:
            Cache-Control:
              $ref: '#/components/headers/Cache-Control'
            Pragma:
              $ref: '#/components/headers/Pragma'
            X-Correlation-ID:
              $ref: '#/components/headers/X-Correlation-ID'
            X-CorAPI-Source:
              $ref: '#/components/headers/X-CorAPI-Source'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/parResponse'
        '400':
          $ref: '#/components/responses/oauthError400'
        '401':
          $ref: '#/components/responses/oauthError401'
        '403':
          $ref: '#/components/responses/oauthError403'
        '405':
          $ref: '#/components/responses/oauthError405'
        '406':
          $ref: '#/components/responses/oauthError406'
        '413':
          $ref: '#/components/responses/oauthError413'
        '415':
          $ref: '#/components/responses/oauthError415'
        '429':
          $ref: '#/components/responses/oauthError429'
        '500':
          $ref: '#/components/responses/oauthError500'
        '502':
           $ref: '#/components/responses/oauthError502'
        '504':
          $ref: '#/components/responses/oauthError504'
  '/oauth/token':
    post:
      tags:
        - oauth
      summary: Get the OAuth access and refresh token
      description: |
        Returns the OAuth access and refresh token for the specified client and target.
      operationId: oauthToken
      parameters:
        - $ref: '#/components/parameters/correlation_in_header'
        - $ref: '#/components/parameters/agent_in_header'
        - $ref: '#/components/parameters/targetid_in_header'
        - $ref: '#/components/parameters/psu_ip_in_header'
        - $ref: '#/components/parameters/psu_user_agent_in_header'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/tokenRequest'

      responses:
        '200':
          description: OAuth token response
          headers:
            X-Correlation-ID:
              $ref: '#/components/headers/X-Correlation-ID'
            X-CorAPI-Source:
              $ref: '#/components/headers/X-CorAPI-Source'
            Cache-Control:
              $ref: '#/components/headers/Cache-Control'
            Pragma:
              $ref: '#/components/headers/Pragma'
          content:
            application/json;charset=utf-8:
              schema:
                $ref: '#/components/schemas/oAuthTokenResponse'
        '400':
          $ref: '#/components/responses/oauthError400'
        '401':
          $ref: '#/components/responses/oauthError401'
        '403':
          $ref: '#/components/responses/oauthError403'
        '405':
          $ref: '#/components/responses/oauthError405'
        '406':
          $ref: '#/components/responses/oauthError406'
        '415':
          $ref: '#/components/responses/oauthError415'
        '500':
          $ref: '#/components/responses/oauthError500'
        '502':
          $ref: '#/components/responses/oauthError502'
        '504':
          $ref: '#/components/responses/oauthError504'


  '/oauth/revoke':
    post:
      tags:
        - oauth
      summary: Revoke an OAuth token (access or refresh)
      description: |
        Revokes the specified OAuth token (must be done separately for access token and refresh token)
      operationId: oauthRevoke
      parameters:
        - $ref: '#/components/parameters/correlation_in_header'
        - $ref: '#/components/parameters/agent_in_header'
        - $ref: '#/components/parameters/targetid_in_header'
        - $ref: '#/components/parameters/psu_ip_in_header'
        - $ref: '#/components/parameters/psu_user_agent_in_header'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              required:
                - token
              properties:
                token:
                  type: string
                  description: token to be revoked
                token_type_hint:
                  type: string
                  description: either access_token or refresh_token
                  enum:
                    - access_token
                    - refresh_token
      responses:
        '200':
          description: OAuth token revocation success
          headers:
            X-Correlation-ID:
              $ref: '#/components/headers/X-Correlation-ID'
            X-CorAPI-Source:
              $ref: '#/components/headers/X-CorAPI-Source'
            Cache-Control:
              $ref: '#/components/headers/Cache-Control'
            Pragma:
              $ref: '#/components/headers/Pragma'
        '400':
          $ref: '#/components/responses/oauthError400'
        '401':
          $ref: '#/components/responses/oauthError401'
        '403':
          $ref: '#/components/responses/oauthError403'
        '405':
          $ref: '#/components/responses/oauthError405'
        '406':
          $ref: '#/components/responses/oauthError406'
        '415':
          $ref: '#/components/responses/oauthError415'
        '500':
          $ref: '#/components/responses/oauthError500'
        '502':
          $ref: '#/components/responses/oauthError502'
        '504':
          $ref: '#/components/responses/oauthError504'

  '/permissions/{permissionId}/tokens/exchange':
    post:
      tags:
        - permissions
      summary: Exchange Permission for Token pair
      description: |
        Allows to exchange a permission for an OAuth token pair.
      operationId: exchangePermissionForOauthToken
      parameters:
        - $ref: '#/components/parameters/correlation_in_header'
        - $ref: '#/components/parameters/permission_id_in_header'
        - $ref: '#/components/parameters/agent_in_header'
        - $ref: '#/components/parameters/targetid_in_header'
        - $ref: '#/components/parameters/psu_user_agent_in_header'
      responses:
        '200':
          description: Oauth Token response
          headers:
            X-Correlation-ID:
              $ref: '#/components/headers/X-Correlation-ID'
            X-CorAPI-Source:
              $ref: '#/components/headers/X-CorAPI-Source'
            Cache-Control:
              $ref: '#/components/headers/Cache-Control'
            Pragma:
              $ref: '#/components/headers/Pragma'
          content:
            application/json;charset=utf-8:
              schema:
                $ref: '#/components/schemas/oAuthTokenResponse'
        '400':
          $ref: '#/components/responses/oauthError400'
        '401':
          $ref: '#/components/responses/oauthError401'
        '403':
          $ref: '#/components/responses/oauthError403'
        '405':
          $ref: '#/components/responses/oauthError405'
        '406':
          $ref: '#/components/responses/oauthError406'
        '413':
          $ref: '#/components/responses/oauthError413'
        '415':
          $ref: '#/components/responses/oauthError415'
        '429':
          $ref: '#/components/responses/oauthError429'
        '500':
          $ref: '#/components/responses/oauthError500'
        '502':
          $ref: '#/components/responses/oauthError502'
        '504':
          $ref: '#/components/responses/oauthError504'

components:
  parameters:
    # bLink specific parameters
    path_providerId:
      name: providerId
      in: path
      description: id of the provider
      required: true
      schema:
        maxLength: 30
        type: string
    path_userId:
      name: userId
      in: path
      description: >
        <p>
        The Service User can choose the User-ID value freely. It is allowed to assign multiple User-ID values to the same Customer.  
        The only requirement is that each User-ID can be traced back to the correct end-user unambiguously.
        <p>
        For a specific User-ID value and Provider ID combination, there can only be one valid Permission at a time. As soon as a new permission 
        is initiated using the same User-ID and Provider ID, the bLink CaaS Service will revoke any previously valid permission of the 
        same User-ID and Provider ID.
        <p>
        Please note: Even when using different User-IDs to create multiple valid permissions, it could still happen
        that the Service Provider doesn't allow multiple valid Access Tokens in parallel for the same E-Banking Access, 
        which will result in previous permissions being invalidated as soon as they are used in an API-call.
      required: true
      schema:
        type: string
        pattern: "^([a-zA-Z0-9\\-.]{1,250})$"
    targetid_in_header:
      name: X-CorAPI-Target-ID
      in: header
      description: 'ID that identifies the provider (e.g., a financial institution). (SCOPE: SIX required)'
      required: true
      schema:
        type: string
    psu_ip_in_header:
      name: X-PSU-IP-Address
      in: header
      description: 'IP address of the user initiating the operation or AUTO for system triggered processes (SCOPE: SIX required)'
      required: true
      schema:
        type: string
    psu_user_agent_in_header:
      name: X-PSU-User-Agent
      in: header
      description: 'User agent of the user initiating the operation or AUTO for system triggered processes (SCOPE: SIX required)'
      required: true
      schema:
        type: string
    correlation_in_header:
      name: X-Correlation-ID
      in: header
      description: Unique ID (defined by the caller) which will be reflected back in the response.
      required: true
      schema:
        type: string
        maxLength: 64
    agent_in_header:
      name: User-Agent
      in: header
      description: Name and version of the of the Client software
      required: true
      schema:
        type: string
    permission_id_in_header:
      name: permissionId
      in: path
      description: permission ID
      required: true
      schema:
        type: string

  headers:
    Cache-Control:
      description: 'must include: no-store'
      schema:
        type: string
        default: 'no-store'
    Content-Language:
      description: 'always en'
      schema:
        type: string
    Content-Type:
      description: 'application/problem+json; charset=utf-8 according to RFC7807'
      schema:
        type: string
    Pragma:
      description: 'must be: no-cache'
      schema:
        type: string
        default: 'no-cache'
    X-Correlation-ID:
      description: Client defined ID from request to correlate HTTP requests between a client and a server
      schema:
        type: string
        maxLength: 64
        example: f058ebd6-02f7-4d3f-942e-904344e8cde5
    X-CorAPI-Source:
      description: |
        Indicates whether the response was created by the bLink platform or by the provider.
      schema:
        type: string
        enum:
          - PLATFORM
          - PROVIDER
    Retry-After:
      description: Indicates how long the client should wait before making a follow-up request.
      schema:
        type: string
        example: 'Wed, 21 Oct 2022 07:28:00 GMT'
        description: A date after which to retry.
  #          - type: integer
  #            minimum: 0
  #            example: 120
  #            description: 'The seconds to delay after the response is received.'

  schemas:
    ## /oauth
    pushedAuthorizationRequest:
      title: Pushed Authorization Request
      example: |
        response_type=codedfdf
        &client_id=654321
        &redirect_uri=https://api.client.example.com/oauth/cb
        &scope=urn:blink:xs2a:ais urn:blink:xs2a:pss:write
        &state=d60dbae3-b1b2-419c-bc72-1054fab294ec
        &code_challenge=JPaMZZhWRl4uceYCpN4QV9RFOHV4tlrD-lCUqDUsEh4
        &code_challenge_method=S256
        &provider_id=IIDP99999
        &username=john.doe@acme.com
        &grant_management_action=create
      required:
        - response_type
        - client_id
        - redirect_uri
        - scope
        - state
        - code_challenge
        - code_challenge_method
        - provider_id
        - username
        - grant_management_action
      properties:
        response_type:
          type: string
          description: OAuth 2.0 response type. Must be 'code' for authorization code flow.
          enum:
            - code
        client_id:
          type: string
          description: The client identifier issued during registration.
        redirect_uri:
          type: string
          format: uri
          description: URI to redirect the user-agent after authorization.
        scope:
          type: string
          maxLength: 256
          description: Space-delimited list of requested scopes.
        state:
          type: string
          maxLength: 256
          description: Opaque value for maintaining state between request and callback (CSRF protection).
        code_challenge:
          type: string
          description: PKCE code challenge derived from the code verifier (RFC 7636).
        code_challenge_method:
          type: string
          enum:
            - S256
          description: PKCE code challenge method. Only S256 is supported.
        provider_id:
          type: string
          description: Identifier of the target financial institution/provider.
        username:
          type: string
          maxLength: 64
          description: Username of the resource owner.
        grant_management_action:
          type: string
          description: Action for grant management. Must be 'create' for initial consent.
          enum:
            - create
            - merge
            - replace
        grant_id:
          type: string
          maxLength: 64
          description: >
            Value identifying an individual grant managed by a particular authorization server 
            for a certain client and a certain resource owner. 
            Required if `grant_management_action` is 'merge' or 'replace'.

    tokenRequest:
      title: OAuth Token Request
      example: |
        grant_type=authorization_code
        &code=SplxlOBeZQQYbYS6WxSbIA
        &redirect_uri=https://api.client.example.com/oauth/cb
        &client_id=654321
        &code_verifier=JPaMZZhWRl4uceYCpN4QV9RFOHV4tlrD-lCUqDUsEh4
      required:
        - grant_type
        - code
        - redirect_uri
        - client_id
        - code_verifier
      properties:
        grant_type:
          type: string
          description: either authorization_code or refresh_token
          enum:
            - authorization_code
            - refresh_token
        code:
          type: string
          description: authorization code if applicable
        refresh_token:
          type: string
          description: refresh token if applicable
        redirect_uri:
          type: string
          description: original redirect uri if applicable
        client_id:
          type: string
          description: client id
        code_verifier:
          type: string
          description: 'PKCE code verifier (RFC 7636) (43-128 chars of [a-zA-Z0-9-._~])'
#      oneOf:
#        - required: [ grant_type, code, redirect_uri, code_verifier, client_id]
#        - required: [ grant_type, refresh_token ]

    parResponse:
      title: PAR Response
      required:
        - request_uri
        - expires_in
      properties:
        request_uri:
          type: string
          format: uri
          description: |
            The request URI corresponding to the authorization request posted.
            Used as the `request_uri` parameter in the subsequent authorization request.
          example: urn:ietf:params:oauth:request_uri:OsL1Z3VqIxAT9R77wB7KCw
        expires_in:
          type: integer
          minimum: 1
          description: Lifetime of the request URI in seconds.
          example: 60

    oAuthTokenResponse:
      title: OAuth Token Response
      required:
        - access_token
        - token_type
        - expires_in
      properties:
        access_token:
          type: string
          description: OAuth 2.0 access token
          example: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.abc123
        token_type:
          type: string
          description: Token type as defined in RFC 6749 (typically "Bearer")
          example: Bearer
        expires_in:
          type: integer
          format: int32
          description: Lifetime of the access token in seconds
          example: 3600
        refresh_token:
          type: string
          description: OAuth 2.0 refresh token (optional)
          example: dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4=
        scope:
          type: string
          description: Space‑delimited scopes assigned to the token (optional)
          example: "urn:blink:xs2a:ais urn:blink:xs2a:pss:write"
        grant_id:
          type: string
          description: >
            Identifier for the grant as defined by FAPI Grant Management.
            Optional, only returned if the authorization server supports GM.
          example: "3f5dd8a4-7e3a-47af-92e8-2e2bc5bcd011"
    commonErrorResponse:
      title: Common Error Response
      type: object
      properties:
        type:
          $ref: '#/components/schemas/commonErrorType'
        title:
          type: string
          example: This is the general problem description
        detail:
          type: string
          example: Detailed problem description with respect to the current request, e.g., invalid account number format
        instance:
          type: string
          example: path/to/corresponding/resource

    commonErrorType:
      title: Common Error Type
      type: string
      description: Error Types for commonErrorResponse. See Appendix for detailed information.
      example: /problems/TECHNICAL_ERROR
      enum:
        - /problems/INVALID_PAYLOAD
        - /problems/MALFORMED_PAYLOAD
        - /problems/INVALID_TOKEN
        - /problems/EXPIRED_TOKEN
        - /problems/INSUFFICIENT_PRIVILEGES
        - /problems/NO_ACCESS_TO_RESOURCE
        - /problems/RESOURCE_DOES_NOT_EXIST
        - /problems/RESOURCE_NOT_READY
        - /problems/RESOURCE_TOO_LARGE
        - /problems/WRONG_METHOD
        - /problems/OPERATION_NOT_ALLOWED
        - /problems/TECHNICAL_ERROR
        - /problems/NOT_IMPLEMENTED
    oauthErrorResponse:
      title: OAuth 2.0 Error Response for the Token Endpoint and Pushed Authorization Endpoint
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Error codes for oauthErrorResponse. For further details see the "Error Handling" section of the "Consent Management 2.0" documentation and the section 5.2 of the OAuth 2.0 Specification (RFC6749).
          example: invalid_request
        error_description:
          type: string
          description: Human-readable ASCII [USASCII] text providing additional information, used to assist the client developer in understanding the error that occurred.
          example: Invalid authorization code
        error_uri:
          type: string
          description: A URI identifying a human-readable web page with information about the error, used to provide the client developer with additional information about the error.

  responses:
    oauthError400:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
      description: Bad Request - The format of the request was invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError401:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
      description: Unauthorized - Client authentication failed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError403:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
      description: Forbidden - Access to endpoint denied.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError405:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
      description: Method Not Allowed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError406:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
      description: Not Acceptable
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError413:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      description: Content Too Large
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError415:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
      description: Unsupported Media Type
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError429:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      description: Too Many Requests
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError500:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError502:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
      description: Bad Gateway
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'

    oauthError504:
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
        Content-Language:
          $ref: '#/components/headers/Content-Language'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-CorAPI-Source:
          $ref: '#/components/headers/X-CorAPI-Source'
      description: Gateway Timeout - The service provider did not answer in the required time.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/oauthErrorResponse'


