How Dual-Auth Provider Handling Works in `provider-listing.ts`
Dual-auth providers in provider-listing.ts are discovered dynamically from SDK definitions and split into two separate lists—API-key and OAuth—with cross-flags (supportsOAuth/supportsApiKey) enabling UI toggles between authentication methods.
The provider-listing.ts module in the agegr/pi-web repository powers the Models panel's provider selection interface. It processes providers that support multiple authentication methods—such as Anthropic, GitHub Copilot, Kimi-coding, OpenRouter, Radius, and XAI—and ensures each appears correctly without duplicate entries.
How Dual-Auth Capability Is Discovered
A provider qualifies as dual-auth when it declares both hasApiKeyLogin and hasOAuth in its SDK definition. The module reads this directly from ProviderListingInput objects rather than inferring from hard-coded IDs.
"Which providers are dual-auth is a property of the SDK's provider definitions and changes between releases — read it from
auth, never assume it from an id." — Source comment in [/lib/provider-listing.ts](https://github.com/agegr/pi-web/blob/main/lib/provider-listing.ts#L4-L11)
Each input contains:
hasApiKeyLogin– Boolean flag for API-key supporthasOAuth– Boolean flag for OAuth supportcredentialType– Currently stored credential type ("api_key"|"oauth")status.configured– Whether authentication is activemodelCountand display metadata
Deduplication of Provider Entries
The same provider may appear multiple times in raw SDK output. The dedupeById helper preserves first occurrence while removing duplicates:
function dedupeById(providers: readonly ProviderListingInput[]): ProviderListingInput[] {
const seen = new Set<string>();
const result: ProviderListingInput[] = [];
for (const provider of providers) {
if (seen.has(provider.id)) continue;
seen.add(provider.id);
result.push(provider);
}
return result;
}
Source: /lib/provider-listing.ts#L62-L70
Building the API-Key Provider List
The buildApiKeyProviderList function constructs entries for the API-key tab with specific dual-auth logic:
- Skips providers without
hasApiKeyLogin - Excludes custom
models.jsonproviders (handled separately) - Marks as unconfigured when
credentialType === "oauth"—preventing OAuth-authenticated dual-auth providers from appearing active in both lists - Adds
supportsOAuthflag whenhasOAuthis true
if (!provider.hasApiKeyLogin) continue;
if (provider.status.source && CUSTOM_PROVIDER_SOURCES.has(provider.status.source)) continue;
const configured = provider.status.configured && provider.credentialType !== "oauth";
result.push({
id: provider.id,
displayName: provider.name,
configured,
...(configured && provider.status.source ? { source: provider.status.source } : {}),
modelCount: provider.modelCount,
supportsOAuth: provider.hasOAuth,
});
Source: /lib/provider-listing.ts#L81-L99
Building the OAuth Provider List
The buildOAuthProviderList function handles the OAuth tab:
- Includes only providers with
hasOAuth - Uses friendly display names from
OAUTH_DISPLAY_NAMESmapping or falls back tooauthName/name - Sets
loggedInwhencredentialType === "oauth" - Adds
supportsApiKeyflag for dual-auth detection
if (!provider.hasOAuth) continue;
result.push({
id: provider.id,
name: OAUTH_DISPLAY_NAMES[provider.id] ?? provider.oauthName ?? provider.name,
usesCallbackServer: false,
loggedIn: provider.credentialType === "oauth",
supportsApiKey: provider.hasApiKeyLogin,
});
Source: /lib/provider-listing.ts#L102-L117
Complete Implementation Example
import {
buildApiKeyProviderList,
buildOAuthProviderList,
ProviderListingInput,
} from "./provider-listing";
const rawProviders: ProviderListingInput[] = [
{
id: "anthropic",
name: "Anthropic",
hasApiKeyLogin: true,
hasOAuth: true,
oauthName: "Anthropic (Claude Pro/Max)",
status: { configured: true },
credentialType: "oauth",
modelCount: 5,
},
// additional providers...
];
const apiKeyList = buildApiKeyProviderList(rawProviders);
const oauthList = buildOAuthProviderList(rawProviders);
console.log(apiKeyList);
// Anthropic appears with configured: false, supportsOAuth: true
console.log(oauthList);
// Anthropic appears with loggedIn: true, supportsApiKey: true
Related Files in the Authentication Pipeline
| File | Purpose |
|---|---|
lib/provider-listing.ts |
Core dual-auth detection and list building |
lib/provider-listing-runtime.ts |
SDK data fetching wrapper |
lib/provider-credential-store.ts |
Credential storage and credentialType resolution |
components/models-config-helpers.ts |
UI rendering with authentication toggles |
Summary
- Dual-auth providers are identified by SDK flags (
hasApiKeyLogin+hasOAuth), never hard-coded IDs dedupeByIdeliminates duplicate provider entries before list constructionsupportsOAuthandsupportsApiKeyflags enable UI toggles between authentication methods- OAuth-active providers appear unconfigured in the API-key list to prevent duplication
- The architecture supports future SDK providers automatically without code changes
Frequently Asked Questions
How does provider-listing.ts know if a provider supports both authentication methods?
The module reads hasApiKeyLogin and hasOAuth boolean flags directly from each ProviderListingInput object supplied by the SDK. These flags are defined in the provider's authentication schema, making detection dynamic rather than based on maintained ID lists.
What prevents a dual-auth provider from appearing twice in the UI?
The credentialType field determines active authentication. When credentialType === "oauth", the buildApiKeyProviderList function sets configured: false for that provider, so it only appears active in the OAuth list. The UI renders one row per provider with toggle capabilities instead of duplicate entries.
Can custom providers defined in models.json appear in these lists?
No. The CUSTOM_PROVIDER_SOURCES Set filters out providers with status.source matching custom entries. These are rendered separately in the UI through different components, keeping the built-in provider lists clean.
What happens when the SDK adds a new dual-auth provider?
No code changes are required. Since provider-listing.ts reads authentication capabilities from SDK-provided flags rather than hard-coded logic, new dual-auth providers automatically receive correct supportsOAuth/supportsApiKey flags and proper list placement based on their credentialType.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →