Back to Activepieces

Predefined Connection

docs/embedding/predefined-connection.mdx

0.82.17.4 KB
Original Source

Use predefined connections to allow users to access your piece in the embedded app without re-entering authentication credentials.

The high-level steps are:

  • Create a global connection for a project using the API in the platform admin. Only platform admins can edit or delete global connections.
  • (Optional) Hide the connections dropdown in the piece settings.

Prerequisites

Create a Predefined Connection

<Steps> <Step title="Create an API Key"> Go to **Platform Admin → Security → API Keys** and create an API key. Save it for use in the next step. ![Create API Key](/resources/screenshots/create-api-key.png) </Step> <Step title="Create a Global Connection via API"> Add the following snippet to your backend to create a global connection each time you generate the <b>JWT token</b>.
The snippet does the following:
    - Create Project If it doesn't exist.
    - Create a global connection for the project with certain naming convention.
js
const apiKey = 'YOUR_API_KEY';
const instanceUrl = 'https://cloud.activepieces.com';

// The name of the user / organization in your SAAS
const externalProjectId = 'org_1234';
const pieceName = '@activepieces/piece-gelato';
// This will depend on what your piece auth type is, can be one of this ['PLATFORM_OAUTH2','SECRET_TEXT','BASIC_AUTH','CUSTOM_AUTH']
const pieceAuthType = "CUSTOM_AUTH"
const connectionProps = {
    // Fill in the props required by your piece's auth
}
const { id: projectId, externalId } = await getOrCreateProject({
  projectExternalId: externalProjectId,
  apiKey,
  instanceUrl,
});

await createGlobalConnection({
  projectId,
  externalProjectId,
  apiKey,
  instanceUrl,
  pieceName,
  props,
  pieceAuthType
});

Implementation:

js
async function getOrCreateProject({
    projectExternalId,
    apiKey,
    instanceUrl,
}: {
    projectExternalId: string,
    apiKey: string,
    instanceUrl: string
}): Promise<{ id: string, externalId: string }> {

    const projects = await fetch(`${instanceUrl}/api/v1/projects?externalId=${projectExternalId}`, {
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    })
        .then(response => response.json())
        .then(data => data.data)
        .catch(err => {
            console.error('Error fetching projects:', err);
            return [];
        });

    if (projects.length > 0) {
        return {
            id: projects[0].id,
            externalId: projects[0].externalId
        };
    }

    const newProject = await fetch(`${instanceUrl}/api/v1/projects`, {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            displayName: projectExternalId,
            metadata: {},
            externalId: projectExternalId
        })
    })
        .then(response => response.json())
        .catch(err => {
            console.error('Error creating project:', err);
            throw err;
        });

    return {
        id: newProject.id,
        externalId: newProject.externalId
    };
} 

async function createGlobalConnection({
    projectId,
    externalProjectId,
    apiKey,
    instanceUrl,
    pieceName,
    props,
    pieceAuthType
}: {
    projectId: string,
    externalProjectId: string,
    apiKey: string,
    instanceUrl: string,
    pieceName: string,
    props: Record<string, any>,
    pieceAuthType
}) {

    const displayName = 'Gelato Connection';
    const connectionExternalId = 'gelato_' + externalProjectId;

    return fetch(`${instanceUrl}/api/v1/global-connections`, {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            displayName,
            pieceName,
            metadata: {},
            type: pieceAuthType,
            value: {
                type: pieceAuthType,
                props
            },
            scope: 'PLATFORM',
            projectIds: [projectId],
            externalId: connectionExternalId
        })
    });
}
</Step> </Steps>

Hide the Connections Dropdown (Optional)

<Steps> <Step title="Modify Trigger / Action Definition"> Wherever you call `createTrigger` or `createAction` set `requireAuth` to `false`, this will hide the connections dropdown in the piece settings in the builder, next we need to fetch it based on a naming convention. </Step> <Step title="Fetch the connection"> Here is example how you can fetch the connection value based on naming convention, make sure this naming convention is followed when creating a global connection.
js
import {
   ConnectionsManager,
   Property,
   TriggerStrategy
} from "@activepieces/pieces-framework";
import {
   createTrigger
} from "@activepieces/pieces-framework";
import {
   isNil
} from "@activepieces/shared";
// Add this import from the index.ts file, where it contains the definition of the auth object.
import { auth } from '../..';

const fetchConnection = async (
	connections: ConnectionsManager,
	projectExternalId: string | undefined,
): Promise<PiecePropValueSchema<typeof auth>> => {
	if (isNil(projectExternalId)) {
		throw new Error('This project is missing an external id');
	}
	// the naming convention here is gelato_projectExternalId
	const connection = await connections.get(`gelato_${projectExternalId}`);
	if (isNil(connection)) {
		throw new Error(`Connection not found for project ${projectExternalId}`);
	}

	return connection as PiecePropValueSchema<typeof auth>;
};


export const newFlavorCreated = createTrigger({
   requireAuth: false,
   name: 'newFlavorCreated',
   displayName: 'new flavor created',
   description: 'triggers when a new icecream flavor is created.',
   props: {
      dropdown: Property.Dropdown({
         displayName: 'Dropdown',
         required: true,
         refreshers: [],
         options: async (_, {
            connections,
            project
         }) => {
            const connection = await fetchConnection(connections, (await project.externalId()));
            // your logic
            return {
               options: [{
                  label: 'test',
                  value: 'test'
               }]
            }
         }
      })
   },
   sampleData: {},
   type: TriggerStrategy.POLLING,
   async test({connections,project}) {
      const connection = await fetchConnection(connections, (await project.externalId()));
      // use the connection with your own logic
      return []
   },
   async onEnable({connections,project}) {
      const connection = await fetchConnection(connections, (await project.externalId()));
      // use the connection with your own logic
   },

   async onDisable({connections,project}) {
      const connection = await fetchConnection(connections, (await project.externalId()));
      // use the connection with your own logic
   },

   async run({connections,project}) {
    const connection = await fetchConnection(connections, (await project.externalId()));
      // use the connection with your own logic
      return []
   },
});
</Step>
</Steps>