> ## Documentation Index
> Fetch the complete documentation index at: https://docs.conductor.is/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect your users via the auth flow

> Enable your users to securely connect their QuickBooks Desktop to your application.

The authentication flow in Conductor is a user interface walkthrough that allows your users to securely connect their QuickBooks Desktop installation to their Conductor account. For an example, check out this [demo of the auth flow](https://connect.conductor.is/qbd/demo).

There are two main approaches to integrating the auth flow with your application:

1. Integrate the auth flow with your backend to manage multiple users and connections.
2. Generate shareable auth links for getting started quickly or one-off connections.

## Integrate the auth flow with your backend

If you are building a multi-user service where each user needs to connect their QuickBooks Desktop account to your application, you'll want to integrate Conductor's QuickBooks Desktop auth flow into your backend.

<Steps>
  <Step title="Create an end-user">
    Consider you have an end-user of your application who needs to connect their QuickBooks Desktop to your application. Begin by creating an end-user for that user and saving their `id` to your database. You will use this `id` to match your users to their corresponding QuickBooks Desktop connection in Conductor.

    <Tip>
      If your database has a `users` table, consider creating a column called `conductor_end_user_id`.
    </Tip>

    <CodeGroup>
      ```ts Node.js theme={"system"}
      import Conductor from "conductor-node";
      const conductor = new Conductor({ apiKey: "{{YOUR_SECRET_KEY}}" });

      // Replace the placeholders with your actual data.
      const endUser = await conductor.endUsers.create({
        companyName: "{{END_USER_COMPANY_NAME}}",
        sourceId: "{{UNIQUE_ID_FROM_YOUR_DB}}",
        email: "{{END_USER_EMAIL}}",
      });

      // Save the end-user ID to your database.
      await db.users.update({
        conductorEndUserId: endUser.id,
      });
      ```

      ```python Python theme={"system"}
      from conductor import Conductor

      conductor = Conductor(api_key="{{YOUR_SECRET_KEY}}")

      # Replace the placeholders with your actual data.
      end_user = conductor.end_users.create(
        company_name="{{END_USER_COMPANY_NAME}}",
        source_id="{{UNIQUE_ID_FROM_YOUR_DB}}",
        email="{{END_USER_EMAIL}}",
      )

      # Save the end-user ID to your database.
      # e.g., update your users table with end_user.id
      ```
    </CodeGroup>
  </Step>

  <Step title="Check if the end-user has an active QuickBooks Desktop connection">
    The next step is to initiate an auth session for your user to connect their QuickBooks Desktop. However, what if they already has an active connection? Or, what if they previously started the auth flow but didn't complete it?

    <Note>
      You must send any request and check the `error.code` to determine the
      appropriate action. The key distinction in error handling is:

      * `INTEGRATION_CONNECTION_NOT_SET_UP`: The user needs to complete the auth
        flow.
      * Other connection errors: The user needs to take a specific action (like
        restarting QuickBooks) but does not need the auth flow.
    </Note>

    Imagine your application has a web app where your users configure the integrations with their application. If you create a section for the QuickBooks Desktop integration, you can use the following approach to track whether an active connection already exists:

    <CodeGroup>
      ```ts Node.js theme={"system"}
      import Conductor, { APIError as ConductorError } from "conductor-node";

      interface IConductorError {
        message: string;
        userFacingMessage: string;
        type: string;
        code: string;
        httpStatusCode: number;
        integrationCode?: string;
        requestId: string;
      }

      const conductor = new Conductor({ apiKey: "{{YOUR_SECRET_KEY}}" });

      try {
        // Check the connection status
        await conductor.qbd.healthCheck({ conductorEndUserId: "{{END_USER_ID}}" });
        updateUI("QuickBooks Desktop is successfully connected!");
      } catch (error) {
        if (error instanceof ConductorError) {
          // Unwrap Conductor error
          const conductorError = error?.error?.error as IConductorError

          if (conductorError.code === "INTEGRATION_CONNECTION_NOT_SET_UP") {
            // This specific error code indicates the user needs to go through the auth
            // flow. Either they never started it, or didn't complete it.
            const authSession = await conductor.authSessions.create({
              publishableKey: "{{YOUR_PUBLISHABLE_KEY}}",
              endUserId: "{{END_USER_ID}}",
            });
            updateUI("Set up your QuickBooks Desktop connection: " + authSession.authFlowUrl);
          } else {
            // Display connection errors for your user to resolve.
            updateUI("An error occurred: " + conductorError.userFacingMessage);
          }
        } else {
          throw error;
        }
      }
      ```

      ```python Python theme={"system"}
      from conductor import Conductor

      conductor = Conductor(api_key="{{YOUR_SECRET_KEY}}")

      try:
        # Check the connection status
        conductor.qbd.health_check(conductor_end_user_id="{{END_USER_ID}}")
        updateUI("QuickBooks Desktop is successfully connected!")
      except Exception as e:
        # If the connection is not yet set up, start an auth session; otherwise show the user-facing message.
        code = getattr(e, "code", None)
        if code == "INTEGRATION_CONNECTION_NOT_SET_UP":
          auth_session = conductor.auth_sessions.create(
            publishable_key="{{YOUR_PUBLISHABLE_KEY}}",
            end_user_id="{{END_USER_ID}}",
          )
          updateUI("Set up your QuickBooks Desktop connection: " + auth_session.auth_flow_url)
        else:
          user_message = getattr(e, "user_facing_message", str(e))
          updateUI("An error occurred: " + user_message)
      ```
    </CodeGroup>

    ***Note:** Replace `updateUI()` with your actual code that updates your application's UI based on the status or errors received.*
  </Step>
</Steps>

## Create a shareable auth flow link

For a quick start, particularly useful for pilot deployments or small-scale operations, generate a secure, shareable link for the QuickBooks Desktop auth flow:

<Steps>
  <Step title="Create an end-user">
    If you haven't already done so, create an end-user and save their `id`. You will use this `id` to authenticate future requests.

    <CodeGroup>
      ```ts Node.js theme={"system"}
      import Conductor from "conductor-node";
      const conductor = new Conductor({ apiKey: "{{YOUR_SECRET_KEY}}" });

      // Replace these placeholders with your own values.
      const endUser = await conductor.endUsers.create({
        companyName: "{{END_USER_COMPANY_NAME}}",
        sourceId: "{{UNIQUE_ID_FROM_YOUR_DB}}",
        email: "{{END_USER_EMAIL}}",
      });
      console.log("Save this end-user ID to auth future requests:", endUser.id);
      ```

      ```python Python theme={"system"}
      from conductor import Conductor

      conductor = Conductor(api_key="{{YOUR_SECRET_KEY}}")

      # Replace these placeholders with your own values.
      end_user = conductor.end_users.create(
        company_name="{{END_USER_COMPANY_NAME}}",
        source_id="{{UNIQUE_ID_FROM_YOUR_DB}}",
        email="{{END_USER_EMAIL}}",
      )
      print("Save this end-user ID to auth future requests:", end_user.id)
      ```

      ```sh cURL theme={"system"}
      curl -X POST https://api.conductor.is/v1/end-users \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer {{YOUR_SECRET_KEY}}" \
        -d '{
              "companyName": "{{END_USER_COMPANY_NAME}}",
              "sourceId": "{{UNIQUE_ID_FROM_YOUR_DB}}",
              "email": "{{END_USER_EMAIL}}"
            }'
      ```
    </CodeGroup>
  </Step>

  <Step title="Create an auth session">
    Using the end-user's ID, create an auth session with an extended link expiry time if needed:

    <CodeGroup>
      ```ts Node.js theme={"system"}
      import Conductor from "conductor-node";
      const conductor = new Conductor({ apiKey: "{{YOUR_SECRET_KEY}}" });

      const authSession = await conductor.authSessions.create({
        publishableKey: "{{YOUR_PUBLISHABLE_KEY}}",
        endUserId: "{{END_USER_ID}}",
        linkExpiryMins: 60 * 24, // 24 hours
      });
      console.log("Send this link to your customer to complete the auth flow:", authSession.authFlowUrl);
      ```

      ```python Python theme={"system"}
      from conductor import Conductor

      conductor = Conductor(api_key="{{YOUR_SECRET_KEY}}")

      auth_session = conductor.auth_sessions.create(
        publishable_key="{{YOUR_PUBLISHABLE_KEY}}",
        end_user_id="{{END_USER_ID}}",
        link_expiry_mins=60 * 24,  # 24 hours
      )
      print("Send this link to your customer to complete the auth flow:", auth_session.auth_flow_url)
      ```

      ```sh cURL theme={"system"}
      curl -X POST https://api.conductor.is/v1/auth-sessions \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer {{YOUR_SECRET_KEY}}" \
        -d '{
              "publishableKey": "{{YOUR_PUBLISHABLE_KEY}}",
              "endUserId": "{{END_USER_ID}}",
              "linkExpiryMins": 1440
            }'
      ```
    </CodeGroup>
  </Step>

  <Step title="Share the auth flow link">
    Share the generated `authFlowUrl` with your end-user to direct them to the auth flow to connect their QuickBooks Desktop instance to your application.

    The link will resemble this mock example:

    ```
    https://connect.conductor.is/qbd/auth_sess_client_secret_1234567abcdefg?key={{YOUR_PUBLISHABLE_KEY}}
    ```
  </Step>
</Steps>
