Skip to content

Setting up Auth Connections

Auth connections enable your application to authenticate with external OAuth2 providers (such as Google, Microsoft 365, or QuickBooks) on behalf of itself, not on behalf of a user. Functions, executors, and workflows can then access those provider APIs at runtime using a managed access token.

This tutorial manages the connection through SDK config (defineAuth()), which is one of two supported approaches. You can instead create, authorize, and manage a connection entirely from the Console with tailor-sdk authconnection open — see Setup Flow in the AuthConnection guide for both options and why a given connection should only be managed by one of them.

What you'll build

A connection to Google's API that your resolvers and functions can use to call Google services without managing OAuth2 tokens manually.

Tutorial Steps

  1. Configure the connection in defineAuth()
  2. Deploy the connection
  3. Authorize the connection
  4. Use the connection token at runtime
  5. Manage connections via CLI

1. Configure the Connection

Add a connections block to your defineAuth() in tailor.config.ts:

typescript
import { defineAuth } from "@tailor-platform/sdk";
import { idp } from "./idp";

export const auth = defineAuth("my-auth", {
  userProfile: {
    type: user,
    usernameField: "email",
  },
  idProvider: idp.provider("my-provider", "my-client"),
  connections: {
    "google-connection": {
      type: "oauth2",
      providerUrl: "https://accounts.google.com",
      issuerUrl: "https://accounts.google.com",
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
  },
});

Connection config fields:

FieldRequiredDescription
typeYesConnection type. Currently only "oauth2".
providerUrlYesOAuth2 provider base URL.
issuerUrlYesOAuth2 issuer URL for JWT validation.
clientIdYesYour OAuth2 app's client ID.
clientSecretYesYour OAuth2 app's client secret.
authUrlNoOverride the authorization endpoint.
tokenUrlNoOverride the token endpoint.

Store GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in your .env file or CI secrets. Never commit them.

2. Deploy the Connection

Run tailor-sdk deploy to register the connection with the platform:

bash
tailor-sdk deploy

This creates the connection record. The connection exists but is not yet authorized (it has no tokens yet).

In-place updates

Redeploying updates an existing connection in-place, preserving the OAuth token. If a change requires re-authorization (for example, the provider URL or client ID changed), deploy will warn you to run authconnection authorize again.

3. Authorize the Connection

Run the authorize command to complete the OAuth2 flow:

bash
tailor-sdk authconnection authorize --name google-connection \
  --scopes "openid,profile,email"

This opens a browser tab for the OAuth2 consent screen. After you approve, the platform exchanges the authorization code for tokens and stores them securely. Your app code never handles the tokens directly.

You can also run tailor-sdk authconnection open to authorize from the Console instead of the local CLI flow:

bash
tailor-sdk authconnection open

Verify the connection is authorized:

bash
tailor-sdk authconnection list

4. Use the Connection Token at Runtime

Use authconnection.getConnectionToken() from @tailor-platform/sdk/runtime in a resolver, executor, or workflow to retrieve the current access token:

typescript
// resolvers/fetch-google-profile.ts
import { createResolver, t } from "@tailor-platform/sdk";
import { authconnection } from "@tailor-platform/sdk/runtime";

export default createResolver({
  name: "fetchGoogleProfile",
  operation: "query",
  input: {},
  output: t.object({
    email: t.string(),
    name: t.string(),
  }),
  body: async () => {
    const tokens = await authconnection.getConnectionToken("google-connection");

    const response = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
      headers: {
        Authorization: `Bearer ${tokens.access_token}`,
      },
    });

    const profile = await response.json();
    return { email: profile.email, name: profile.name };
  },
});

The connection name is type-checked against the connections defined in defineAuth(). If you rename or remove a connection, TypeScript will flag any call sites immediately.

typescript
// authconnection.getConnectionToken("unknown-connection"); // ❌ TypeScript error

Type narrowing comes from the generated tailor.d.ts. Run tailor-sdk generate (or deploy) after adding or renaming connections to refresh it.

5. Manage Connections via CLI

bash
# List all connections and their status
tailor-sdk authconnection list

# Re-authorize a connection (e.g. token expired or scopes changed)
tailor-sdk authconnection authorize --name google-connection \
  --scopes "openid,profile,email,https://www.googleapis.com/auth/calendar"

# Revoke a connection
tailor-sdk authconnection revoke --name google-connection

Complete Example: Calling an External API from an Executor

Here's a full executor that calls the Google Calendar API whenever a meeting record is created:

typescript
// executor/sync-to-google-calendar.ts
import { createExecutor, recordCreatedTrigger } from "@tailor-platform/sdk";
import { authconnection } from "@tailor-platform/sdk/runtime";
import { meeting } from "../db/meeting";

export default createExecutor({
  name: "sync-to-google-calendar",
  description: "Create a Google Calendar event when a meeting is scheduled",
  trigger: recordCreatedTrigger({ type: meeting }),
  operation: {
    kind: "function",
    body: async ({ newRecord }) => {
      const tokens = await authconnection.getConnectionToken("google-connection");

      await fetch("https://www.googleapis.com/calendar/v3/calendars/primary/events", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${tokens.access_token}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          summary: newRecord.title,
          start: { dateTime: newRecord.startTime },
          end: { dateTime: newRecord.endTime },
        }),
      });
    },
  },
});

Next Steps