Skip to main content
Connections provide a convenient system to authenticate Attio users to external services and securely store secrets.

How to use connections in your app

  1. Head to the Connections tab in your app’s settings, found in the developer dashboard.
  2. Configure a workspace and/or user connection for your app. Choose the type of connection that best suits the authentication requirements of your external service.
  3. Retrieve the connection value in your server-side app code by calling either getUserConnection or getWorkspaceConnection.
  4. Use the connection value to authenticate to the external service when making HTTP requests.

Workspace vs user connections

Connections may be configured for either a specific user or the entire workspace.
  • Workspace connections provide authentication for the entire workspace. When you call getWorkspaceConnection, you’ll always receive the same shared connection value. Only admins may configure workspace connections.
  • User connections provide authentication for a specific user. When you call getUserConnection, you’ll receive a connection value for the specific user who triggered the current execution. Both admins and non-admins may configure user connections.
It’s possible to enable both a user and a workspace connection in the same app, although most apps only require one or the other.
Which connection type to use depends predominantly on how users authenticate to your service. If users are granted permissions based upon permissions in your service and actions performed with granted tokens are attributed to individual users, you likely want to use a user connection. Conversely, if actions are not attributed to individual users and scopes are granted at the level of an entire workspace or account in your system, it is likely that a workspace connection is a better fit.

Connection types

Attio currently supports the following authentication types:
  • Secret - Stores a string secret, such as an API key.
  • OAuth 2.0 - Stores an OAuth 2.0 access token. Authentication to external services which support the OAuth 2.0 authorization code flow is managed automatically by Attio.

Handling unauthenticated states

If either getUserConnection or getWorkspaceConnection is called when a user is yet to set a connection, Attio will automatically throw an error and prompt the user to authenticate. When writing app code, you do not need to handle missing connection states. Attio will do this for you.
Bad example of handling unauthenticated states
const connection = getUserConnection()

// This check is unnecessary. getUserConnection and getWorkspaceConnection will
// never return null or undefined.
if (!connection) {
  // Handle error
}

// Use connection...
Good example of handling unauthenticated states
const connection = getUserConnection()

// No error handling is required. Attio will handle this for you.

// Use connection...

Example: Authenticating to an external mail sequencing API

Once you have enabled a connection for your app, you can retrieve the connection value in your server functions. We can modify the example from Making HTTP requests to use a connection to authenticate to the external mail sequencing API, instead of using a hardcoded API key.
add-to-sequence.server.ts
// You will need to call the correct function based on the connection type
// you've enabled
import {getUserConnection, getWorkspaceConnection} from "attio/server"

export default async function addToSequence({
  email,
  sequenceId,
  mailboxId,
}: {
  email: string
  sequenceId: number
  mailboxId: number
}): Promise<Record<string, string>> {
  const response = await fetch(
    `https://emailsequencingtool.com/api/v1/sequences`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        // We use a user connection rather than a hardcoded API key
        "Authorization": `Bearer ${getUserConnection().value}`,
      },
      body: JSON.stringify({email, sequenceId, mailboxId}),
    },
  )

  if (!response.ok) {
    throw new Error(
      `Failed to add prospect to sequence: ${await response.text()}`,
    )
  }

  // In production apps, using a tool like Zod to parse the response offers
  // better type safety and error handling than the type cast shown here
  const body = await response.json() as {data: Record<string, string>}

  return body.data
}