Documentation/Connectors & Authentication
v2.0.0-beta.1Snapshot bebdcd1Markdown ↗

Connectors & Authentication

Connectors & Authentication

Creating Connectors

typescript
import { Connector, Vendor } from 'oneringai';

// API Key Authentication
Connector.create({
  name: 'openai',
  vendor: Vendor.OpenAI,
  auth: { type: 'api_key', apiKey: process.env.OPENAI_API_KEY! },
});

// With custom base URL
Connector.create({
  name: 'openai-custom',
  vendor: Vendor.OpenAI,
  auth: { type: 'api_key', apiKey: process.env.OPENAI_API_KEY! },
  baseURL: 'https://custom-proxy.example.com/v1',
});

// Runtime-only rotating credentials (Vendor.OpenAI only)
Connector.create({
  name: 'openai-brokered',
  vendor: Vendor.OpenAI,
  auth: {
    type: 'api_key_provider',
    getApiKey: async () => credentialBroker.getOpenAIKey(),
  },
});

// With vendor-specific options
Connector.create({
  name: 'anthropic',
  vendor: Vendor.Anthropic,
  auth: { type: 'api_key', apiKey: process.env.ANTHROPIC_API_KEY! },
  options: {
    anthropicVersion: '2023-06-01'
  },
});

api_key_provider is host-local and cannot be saved through ConnectorConfigStore. OpenAI text, image, audio, video, and embedding SDK requests resolve and validate the callback when the SDK sends a request. The Codex SDK runtime resolves it once when opening each Codex session. Empty or whitespace-only values fail before reaching the SDK. Other vendors must use their documented authentication forms.

Preserving OAuth configuration and requesting refresh access

Use the provider template's refreshStrategy when a host requires reusable authorization-code grants. The public applyRefreshStrategy() helper applies only the provider's refresh requirements to the configuration you already have:

typescript
import {
  applyRefreshStrategy,
  getVendorAuthTemplate,
  type OAuthConnectorAuth,
} from 'oneringai';

function requireRefreshAccess(
  auth: OAuthConnectorAuth,
  vendorId: string,
  authTemplateId: string,
): OAuthConnectorAuth {
  const template = getVendorAuthTemplate(vendorId, authTemplateId);
  if (auth.flow !== 'authorization_code' || template?.flow !== auth.flow) {
    throw new Error('Select the matching authorization-code template');
  }
  return {
    ...auth,
    ...applyRefreshStrategy(
      auth.scope,
      auth.authorizationParams,
      template.refreshStrategy,
      { enforce: true, requiredScope: auth.requiredScope },
    ),
  };
}

The helper is pure and idempotent. It preserves your API scopes, existing required scope tokens and unrelated authorization parameters, including prompt. It never copies the template's general scope list or prompt defaults. Its return value is a config patch, not a token or a storage operation.

auth.scope is the authoritative scope field, including an explicitly empty string. A legacy authorizationParams.scope is used only when auth.scope is absent. The helper promotes that fallback into the returned scope and removes the duplicate parameter. This prevents stale parameters from undoing scope edits or reintroducing removed permissions. Authorization URL construction follows the same precedence and always merges requiredScope, including for configurations that bypass the helper. Unrelated parameters such as prompt remain unchanged.

Template strategy Effect
scope Merge the provider-required scope tokens without duplicating them.
auth_param Add the provider's required parameter. With enforce: true, replace a conflicting value; otherwise retain the existing value.
automatic / never_expires No provider-specific request additions.
manual_setup No invented request additions; the host must handle the documented provider setup.

For example, the Google and Dropbox templates declare their respective offline parameters; Microsoft, Salesforce and Twitter declare their respective refresh scopes. Host code does not need a provider switch. Enforcement with no strategy throws a configuration error. Existing three-argument calls keep their current parameter precedence, including an explicitly configured online flow.

Enforcement requests the provider's renewal behavior; it does not guarantee a refresh token on every callback. Providers can omit a replacement refresh token after a subsequent authorization. Hosts must retain an existing valid grant for the exact same account/client and must not confuse omission with disconnect. automatic/never_expires describe the template's renewal model, not a promise that consent or credentials cannot be revoked. manual_setup must be completed outside the helper. No refresh scopes are added to app-only client-credentials or JWT-bearer flows by this API integration.

buildAuthConfig(template, credentials) retains normal creation defaults. For an existing same-method authorization-code connector, use buildAuthConfig(template, credentialPatch, { existingAuth }) instead. Nonempty supplied template credentials replace their fields; empty values keep the existing values, including secrets. Existing scopes, prompts, PKCE, token storage namespace, refresh margin and custom endpoints survive the update. An absent/empty saved scope does not import the template's broad scope list. A changed parameter such as tenantId updates an endpoint only if that endpoint still matches its previous template-derived URL; custom endpoints are preserved.

ConnectorConfigStore.updateFromTemplate() uses this preservation automatically. An explicit provider/authentication-method change requires that method's own required credentials and does not inherit the previous method's credentials. Legacy configurations with matching provider and unambiguous method information can be edited; ambiguous ones require an explicit saveFromTemplate() replacement. The full-config save() API remains a replacement operation. A changed OAuth client does not make the old client's user grants transferable.

Reconstructed Connector instances apply the same refresh requirements using their canonical serviceType, even when requiredScope is already populated. If a service has conflicting authorization-code strategies, automatic backfill does not guess one: select the exact auth template and apply it explicitly as shown above. This backfill does not import prompt or general scope defaults and does not silently enable parameter enforcement for existing hosts.

Multiple Keys Per Vendor

Use different keys for different purposes:

typescript
// Main production key
Connector.create({
  name: 'openai-main',
  vendor: Vendor.OpenAI,
  auth: { type: 'api_key', apiKey: process.env.OPENAI_KEY_MAIN! },
});

// Backup key
Connector.create({
  name: 'openai-backup',
  vendor: Vendor.OpenAI,
  auth: { type: 'api_key', apiKey: process.env.OPENAI_KEY_BACKUP! },
});

// Use main key
const agent1 = Agent.create({ connector: 'openai-main', model: 'gpt-4.1' });

// Use backup key
const agent2 = Agent.create({ connector: 'openai-backup', model: 'gpt-4.1' });

Managing Connectors

typescript
// Check if connector exists
if (Connector.has('openai')) {
  console.log('OpenAI connector configured');
}

// Get a connector
const connector = Connector.get('openai');
console.log(connector.vendor); // 'openai'

// List all connectors
const names = Connector.list();
console.log(names); // ['openai', 'anthropic', 'google']

// Clear all (useful for testing)
Connector.clear();

// Get an IConnectorRegistry interface (unfiltered)
const registry = Connector.asRegistry();

// Create a scoped (filtered) view — see Scoped Connector Registry section
Connector.setAccessPolicy(myPolicy);
const scopedView = Connector.scoped({ tenantId: 'acme' });

Supported Vendors

typescript
import { Vendor } from 'oneringai';

Vendor.OpenAI        // OpenAI (GPT-4, GPT-5, o3-mini)
Vendor.Anthropic     // Anthropic (Claude)
Vendor.Google        // Google AI (Gemini)
Vendor.GoogleVertex  // Google Vertex AI
Vendor.Groq          // Groq (ultra-fast inference)
Vendor.Together      // Together AI
Vendor.Grok          // xAI (Grok)
Vendor.DeepSeek      // DeepSeek
Vendor.Mistral       // Mistral AI
Vendor.Perplexity    // Perplexity
Vendor.Ollama        // Ollama (local models)
Vendor.Custom        // Custom OpenAI-compatible endpoints

DeepSeek connectors and hosted providers

Vendor.DeepSeek uses a dedicated provider with current model metadata, reasoning/tool history handling, and both Chat Completions and Responses transports. The official connector automatically uses Responses for all current first-party V4 models, including deepseek-v4-flash, deepseek-v4-pro, and deepseek-v4-flash-vision-exp.

typescript
import {
  Agent,
  Connector,
  DEEPSEEK_HOSTS,
  LLM_MODELS,
  Vendor,
} from 'oneringai';

Connector.create({
  name: 'deepseek-main',
  vendor: Vendor.DeepSeek,
  auth: { type: 'api_key', apiKey: process.env.DEEPSEEK_API_KEY! },
});

const official = Agent.create({
  connector: 'deepseek-main',
  model: LLM_MODELS[Vendor.DeepSeek].DEEPSEEK_V4_FLASH,
});

Connector.create({
  name: 'deepseek-deepinfra',
  vendor: Vendor.DeepSeek,
  auth: { type: 'api_key', apiKey: process.env.DEEPINFRA_API_KEY! },
  options: { deepseekHost: DEEPSEEK_HOSTS.DeepInfra },
});

Available presets are official, openrouter, together, fireworks, deepinfra, nvidia-nim, and azure-foundry. Azure needs its resource endpoint in baseURL. For another OpenAI-compatible deployment, select custom and provide baseURL. You may force deepseekTransport to responses or chat_completions; auto is recommended. A canonical model name is mapped to the selected host's model ID, while a host-specific deployment ID passes through unchanged.

The connector-backed DeepSeekAPI facade exposes listModels(), createFimCompletion(), and getBalance() without introducing a second source of credentials:

typescript
import { DeepSeekAPI } from 'oneringai';

const api = DeepSeekAPI.for('deepseek-main');
const models = await api.listModels();
const balance = await api.getBalance();
api.destroy();

FIM and balance are first-party account APIs and intentionally reject third-party host presets. DeepSeek does not expose a first-party embeddings endpoint; choose a separate embedding connector for memory and RAG.


Documentation snapshot · 2026-11-02Suggest a correction ↗

Search documentation

Type to search the v2 documentation.