Connectors & Authentication
Connectors & Authentication
Creating Connectors
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:
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:
// 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
// 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
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.
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:
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.