swagger: '2.0'
info:
  title: FunnelFlux Authentication API
  description: |-
    FunnelFlux Pro uses short-lived access tokens for API authentication. Most API requests should include an `Authorization: Bearer ACCESS_TOKEN` header.

    Use the access token validation endpoint to check whether an access token is still valid and to refresh it when required. Access tokens expire after 72 hours. When an access token expires, submit the expired access token together with a valid refresh token to receive a new access token and expiry time.

    Store the updated access token returned by the validation endpoint and use it for future API requests. Do not rely on a single long-lived access token.

    Refresh tokens are currently issued through Auth0. Due to Auth0 limitations and tenant policy, a refresh token may eventually expire or become invalid, requiring a new refresh token to be generated from the FunnelFlux Pro user interface. This should be uncommon, but integrations should handle this case and prompt for reauthorization when token refresh fails.

    FunnelFlux Pro will migrate to a new authentication provider in the near future. Authentication APIs and token handling will change during that migration, and API clients using these endpoints will need to migrate.
  version: 1.0.0
  contact:
    name: FunnelFlux Support
    url: 'mailto:support@funnelflux.pro'
    email: support@funnelflux.pro
  termsOfService: 'https://funnelflux.com/pro/terms-and-conditions/'
host: api.funnelflux.pro
basePath: /v1
schemes:
  - https
consumes:
  - application/json
produces:
  - application/json
securityDefinitions:
  Bearer:
    type: apiKey
    name: Authorization
    in: header
    description: 'All requests must pass a valid header of `Authorization: Bearer TOKEN`'
security:
  - Bearer: []
tags:
  - name: Authentication
    description: Access token validation and legacy password login.
paths:
  /auth/validate:
    post:
      tags:
        - Authentication
      description: |-
        This endpoint will validate your current access token and reissue if it has expired (provided a refresh token is present).

        - A valid access token must be passed in the Bearer Authorization header (an expired access token is still *valid*)
        - Access tokens have an automatic expiry of 72 hours. Refresh tokens may expire or become invalid due to Auth0 limitations and tenant policy, and excessive refresh token issuing can invalidate older tokens.
        - If the access token is still valid, the response will return the current details and expiry
        - If the access token has expired and no refresh token is provided, the API will return 401
        - If receiving a 401 for an expired access token, pass `refresh_token` and the API will return an updated access token and expiry when the refresh token is still valid. If refresh fails, prompt for reauthorization.
        - It is your responsibility to programmatically store and update your temporary access tokens. Long-lived access tokens are not issued for security purposes
      summary: Access token validation
      responses:
        '200':
          description: |-
            Response will be a JSON object containing an access token and refresh token. You can ignore any other information in the response as this is not necessary for API usage.

            #### Example response for valid access token:
            ```
            {
                "tokens":
                {
                    "access_token": "value_here",
                    "expires_at": 1656045319
                },
                "user":
                {
                    "user_id": "auth0|XXX",
                    "permissions": [
                        "lumetric:access"
                    ]
                }
            }

            ```
            #### Example response for expired access token + valid refresh token -> issues new access token
            ```
            {
                "tokens": {
                    "access_token": "UPDATED_VALUE",
                    "refresh_token": "VALUE", //not changed
                    "expires_at": 1656091322 //new access token expiry
                },
                "user": {
                    ...
                }
            }
            ```
            #### Example response for expired access token with no refresh token passed in body
            This will not give a 200 response -- will return a 400 bad request error.
            ```
            {
                "error": "token is expired"
            }
            ```
          schema:
            type: object
            properties:
              tokens:
                type: object
                properties:
                  access_token:
                    type: string
                  id_token:
                    type: string
                  refresh_token:
                    type: string
                  expires_at:
                    type: string
              user:
                type: object
                properties:
                  user_id:
                    type: string
                  permissions:
                    type: string
                  email:
                    type: string
                  email_verified:
                    type: string
                  name:
                    type: string
                  nickname:
                    type: string
                  picture_url:
                    type: string
                  updated_at:
                    type: string
            x-examples:
              example-1:
                tokens:
                  access_token: string
                  id_token: string
                  refresh_token: string
                  expires_at: number
                user:
                  user_id: string
                  permissions: 'string[]'
                  email: string
                  email_verified: boolean
                  name: string
                  nickname: string
                  picture_url: string
                  updated_at: number
        '400':
          description: |-
            ### Bad Request. Possible errors:
            #### Access Token is expired:
            ```
            {
                "error": "token is expired"
            }
            ```
            #### Access Token is mangled
            ```
            {
                "error": "JWT parse error",
                "error_description": "crypto/rsa: verification error"
            }
            ```
            #### Access Token is of incorrect length
            ```
            {
                "error": "JWT parse error",
                "error_description": "token contains an invalid number of segments"
            }
            ```
          schema:
            type: object
            properties: {}
        '401':
          description: |-
            #### No or invalid access token passed:
            ```
            {
                "error": "access_token_required",
                "error_description": "access token is required"
            }
            ```
        default:
          description: Unexpected error
          schema:
            type: object
            properties: {}
      parameters:
        - in: body
          name: body
          schema:
            type: object
            x-examples:
              example-1:
                refresh_token: string
            properties:
              refresh_token:
                type: string
                description: Refresh Token. Only needed when a token is expired.
                example: xzjQT79U85k92jhE0CZjm....
          description:  Refresh token should be passed in the body of the request. If the access token from the auth header is expired, a new one will be returned. Without the refresh token, the endpoint will not update your access token if it has expired.
      operationId: authValidateAccessToken
    parameters: []
  /auth/login:
    post:
      tags:
        - Authentication
      description: '**NOTE:** Avoid using this method. Rather, please log in normally and retrieve an access and refresh token via our UI. Only use this endpoint if you need to programmatically generate a new access/refresh token and do not currently have one, and for some reason cannot log in via the UI.'
      summary: Password-based login (legacy)
      responses:
        '200':
          description: |-
            Response will be a JSON object containing an access token and refresh token. You can ignore any other information in the response as this is not necessary for API usage.

            #### Example response for valid login
            ```
            {
                "tokens": {
                    "access_token": "VALUE",
                    "id_token": "VALUE", //ignore, not used for API requests
                    "refresh_token": "VALUE",
                    "expires_at": 1656091322 //access token expiry
                },
                "user": {
                    "user_id": "auth0|XXXXXX", //your user ID in our system
                    "permissions": [
                        "lumetric:access"
                    ],
                    "email": "test@funnelflux.com",
                    "email_verified": true,
                    "name": "FunnelFlux Test User",
                    "nickname": "test",
                    "picture_url": "SOME_URL",
                    "updated_at": 1655832122
                }
            }
            ```
          schema:
            type: object
            properties:
              tokens:
                type: object
                properties:
                  access_token:
                    type: string
                  id_token:
                    type: string
                  refresh_token:
                    type: string
                  expires_at:
                    type: string
              user:
                type: object
                properties:
                  user_id:
                    type: string
                  permissions:
                    type: string
                  email:
                    type: string
                  email_verified:
                    type: string
                  name:
                    type: string
                  nickname:
                    type: string
                  picture_url:
                    type: string
                  updated_at:
                    type: string
            x-examples:
              example-1:
                tokens:
                  access_token: string
                  id_token: string
                  refresh_token: string
                  expires_at: number
                user:
                  user_id: string
                  permissions: 'string[]'
                  email: string
                  email_verified: boolean
                  name: string
                  nickname: string
                  picture_url: string
                  updated_at: number
        '400':
          description: |
            This endpoint may return a 400 error if the payload is invalid.

            For example:
          schema:
            type: object
            properties: {}
        '403':
          description: |-
            #### If wrong username/password provided:
            ```
            {
            "error_description":"Wrong email or password.",
            "error":"invalid_grant"
            }
            ```
          schema:
            type: object
            properties:
              error:
                type: string
              error_description:
                type: string
            x-examples:
              example-1:
                error: JWT parse error
                error_description: 'crypto/rsa: verification error'
        default:
          description: Unexpected error
          schema:
            type: object
            properties: {}
      parameters:
        - in: body
          name: body
          schema:
            type: object
            x-examples:
              example-1:
                username: string
                password: string
                issue_refresh_token: boolean
            properties:
              username:
                type: string
                example: bob@smith.com
                description: Your login username
              password:
                type: string
                example: s0me_super_un1que_pa$$word
                description: Your password
              issue_refresh_token:
                type: boolean
                default: true
                description: Optional flag to return a refresh token in response
            required:
              - username
              - password
              - issue_refresh_token
          description: Pass username and password. Set issue_refresh_token to true when using this auth method to retrieve a new access/refresh token.
      operationId: authLoginByPassword
