Skip to main content

Connector Flows

The Ave embed library provides advanced connector flows for resource authorization and protected browser execution. These are separate from standard sign-in flows and enable more complex delegation scenarios.

Connector Authorization

Use openAveConnectorSheet() to authorize access to specific resources outside of the main authentication flow.

Basic Usage

import { openAveConnectorSheet } from "@ave-id/embed";

openAveConnectorSheet({
  clientId: "YOUR_CLIENT_ID",
  redirectUri: "https://yourapp.com/callback",
  resource: "target:resource",
  scope: "resource.access",
  mode: "user_present", // or "background"
  onSuccess: ({ redirectUrl }) => {
    window.location.href = redirectUrl;
  },
});

Configuration Options

OptionTypeRequiredDefaultDescription
clientIdstringYes-Your Ave client ID
redirectUristringYes-OAuth redirect URI
resourcestringYes-Target resource identifier
scopestringYes-Resource-specific scopes
modestringNo"user_present"Authorization mode: "user_present" or "background"
issuerstringNo"https://aveid.net"Ave issuer URL
onSuccessfunctionNo-Success callback
onErrorfunctionNo-Error callback
onClosefunctionNo-Close callback

Authorization Modes

user_present

Requires the user to actively approve the authorization:
import { openAveConnectorSheet } from "@ave-id/embed";

openAveConnectorSheet({
  clientId: "YOUR_CLIENT_ID",
  redirectUri: "https://yourapp.com/callback",
  resource: "calendar:google",
  scope: "calendar.read calendar.write",
  mode: "user_present",
  onSuccess: ({ redirectUrl }) => {
    window.location.href = redirectUrl;
  },
});

background

Attempts silent authorization without user interaction:
import { openAveConnectorSheet } from "@ave-id/embed";

openAveConnectorSheet({
  clientId: "YOUR_CLIENT_ID",
  redirectUri: "https://yourapp.com/callback",
  resource: "calendar:google",
  scope: "calendar.read",
  mode: "background",
  onSuccess: ({ redirectUrl }) => {
    window.location.href = redirectUrl;
  },
  onError: (error) => {
    // Background auth failed, fall back to user_present mode
    console.error("Silent authorization failed:", error);
  },
});
Background mode authorization may fail if the user hasn’t previously granted consent. Always provide a fallback to user_present mode.

Examples

Authorize Third-Party API Access

import { openAveConnectorSheet } from "@ave-id/embed";

function authorizeGoogleCalendar() {
  openAveConnectorSheet({
    clientId: "YOUR_CLIENT_ID",
    redirectUri: "https://yourapp.com/connector/callback",
    resource: "calendar:google",
    scope: "calendar.read calendar.write",
    mode: "user_present",
    onSuccess: ({ redirectUrl }) => {
      // Exchange authorization code for access token
      window.location.href = redirectUrl;
    },
    onError: (error) => {
      console.error("Calendar authorization failed:", error);
    },
    onClose: () => {
      console.log("User cancelled calendar authorization");
    },
  });
}

React Hook for Connector Authorization

import { useState } from "react";
import { openAveConnectorSheet } from "@ave-id/embed";

function useConnectorAuth() {
  const [isAuthorizing, setIsAuthorizing] = useState(false);

  const authorizeResource = (resource, scope) => {
    setIsAuthorizing(true);
    
    openAveConnectorSheet({
      clientId: process.env.REACT_APP_AVE_CLIENT_ID,
      redirectUri: `${window.location.origin}/connector/callback`,
      resource,
      scope,
      mode: "user_present",
      onSuccess: ({ redirectUrl }) => {
        window.location.href = redirectUrl;
      },
      onError: (error) => {
        console.error("Authorization error:", error);
        setIsAuthorizing(false);
      },
      onClose: () => {
        setIsAuthorizing(false);
      },
    });
  };

  return { authorizeResource, isAuthorizing };
}

// Usage
function CalendarConnect() {
  const { authorizeResource, isAuthorizing } = useConnectorAuth();

  return (
    <button 
      onClick={() => authorizeResource("calendar:google", "calendar.read calendar.write")}
      disabled={isAuthorizing}
    >
      {isAuthorizing ? "Authorizing..." : "Connect Google Calendar"}
    </button>
  );
}

Connector Runtime

Use openAveConnectorRuntime() for protected browser execution with delegated tokens.

Basic Usage

import { openAveConnectorRuntime } from "@ave-id/embed";

const runtime = openAveConnectorRuntime({
  delegatedToken: "DELEGATED_TOKEN",
  target: "iris", // example target app
  targetOrigin: "https://irischat.app",
  mode: "user_present",
  onEvent: (event) => console.log(event),
});

runtime.send({
  op: "infer",
  payload: { prompt: "hello" },
});

Configuration Options

OptionTypeRequiredDescription
delegatedTokenstringYesDelegated access token for the runtime
targetstringYesTarget application identifier
targetOriginstringYesOrigin URL of the target application
modestringNoRuntime mode: "user_present" or "background"
onEventfunctionNoEvent callback for runtime messages

Return Value

The openAveConnectorRuntime() function returns an object with:
{
  send: (message) => void // Send messages to the runtime
}

Sending Messages

Use the send() method to communicate with the protected runtime:
const runtime = openAveConnectorRuntime({
  delegatedToken: token,
  target: "iris",
  targetOrigin: "https://irischat.app",
  onEvent: (event) => {
    console.log("Runtime event:", event);
  },
});

// Send a message
runtime.send({
  op: "infer",
  payload: { 
    prompt: "What's the weather today?",
    model: "gpt-4"
  },
});

Receiving Events

Handle events from the runtime using the onEvent callback:
import { openAveConnectorRuntime } from "@ave-id/embed";

const runtime = openAveConnectorRuntime({
  delegatedToken: "DELEGATED_TOKEN",
  target: "iris",
  targetOrigin: "https://irischat.app",
  mode: "user_present",
  onEvent: (event) => {
    switch (event.type) {
      case "response":
        console.log("Got response:", event.data);
        break;
      case "error":
        console.error("Runtime error:", event.error);
        break;
      case "complete":
        console.log("Operation complete");
        break;
      default:
        console.log("Unknown event:", event);
    }
  },
});

Examples

AI Inference Runtime

import { openAveConnectorRuntime } from "@ave-id/embed";

function createAIRuntime(delegatedToken) {
  const runtime = openAveConnectorRuntime({
    delegatedToken,
    target: "iris",
    targetOrigin: "https://irischat.app",
    mode: "user_present",
    onEvent: (event) => {
      if (event.type === "response") {
        displayAIResponse(event.data);
      } else if (event.type === "error") {
        handleError(event.error);
      }
    },
  });

  return {
    ask: (prompt) => {
      runtime.send({
        op: "infer",
        payload: { prompt },
      });
    },
  };
}

// Usage
const ai = createAIRuntime(delegatedToken);
ai.ask("Explain quantum computing");

React Hook for Runtime

import { useEffect, useRef, useState } from "react";
import { openAveConnectorRuntime } from "@ave-id/embed";

function useAveRuntime(delegatedToken, target, targetOrigin) {
  const runtimeRef = useRef(null);
  const [events, setEvents] = useState([]);

  useEffect(() => {
    if (!delegatedToken) return;

    runtimeRef.current = openAveConnectorRuntime({
      delegatedToken,
      target,
      targetOrigin,
      mode: "user_present",
      onEvent: (event) => {
        setEvents(prev => [...prev, event]);
      },
    });
  }, [delegatedToken, target, targetOrigin]);

  const send = (message) => {
    runtimeRef.current?.send(message);
  };

  return { send, events };
}

// Usage
function AIChat({ delegatedToken }) {
  const { send, events } = useAveRuntime(
    delegatedToken,
    "iris",
    "https://irischat.app"
  );

  const handleSend = (prompt) => {
    send({
      op: "infer",
      payload: { prompt },
    });
  };

  return (
    <div>
      {events.map((event, i) => (
        <div key={i}>{JSON.stringify(event)}</div>
      ))}
      <button onClick={() => handleSend("Hello")}>Send</button>
    </div>
  );
}

Security Considerations

Important security notes:
  • Delegated tokens should be treated as sensitive credentials
  • Always validate targetOrigin to prevent message interception
  • Use user_present mode for sensitive operations requiring user approval
  • Never expose delegated tokens in client-side code or logs
  • Implement proper token expiration and refresh mechanisms
  • Validate all events received from the runtime before processing

Use Cases

Connector flows are ideal for:
  • Third-party API integration - Authorize access to external services (Google, Slack, etc.)
  • Resource delegation - Grant limited access to specific resources
  • Protected execution - Run sensitive operations in isolated runtime environments
  • AI/ML workflows - Execute AI inference in protected contexts
  • Multi-step authorization - Separate authentication from resource authorization

Best Practices

  1. Use specific scopes - Request only the minimum required permissions
  2. Handle errors gracefully - Provide fallbacks for failed authorizations
  3. Implement token refresh - Don’t rely on long-lived tokens
  4. Validate events - Always validate runtime events before processing
  5. Monitor runtime state - Track runtime lifecycle and handle disconnections

Next Steps

Overview

Learn about all embedding options

Inline iframe

Standard authentication embedding

Build docs developers (and LLMs) love