Authentication

Republic supports both static provider keys and dynamic provider token resolution.

Static API Keys

Use api_key when your process already has the provider token.

from republic import LLM

llm = LLM(
    model="openrouter:openrouter/free",
    api_key="<OPENROUTER_KEY>",
)

For multi-provider fallback, pass a provider-to-token mapping.

from republic import LLM

llm = LLM(
    model="openai:gpt-4o-mini",
    fallback_models=["anthropic:claude-3-5-sonnet-latest"],
    api_key={
        "openai": "<OPENAI_KEY>",
        "anthropic": "<ANTHROPIC_KEY>",
    },
)

Dynamic Key Resolution

Use api_key_resolver when the token should be resolved lazily per provider.

from republic import LLM


def resolve_api_key(provider: str) -> str | None:
    if provider == "openrouter":
        return "<OPENROUTER_KEY>"
    if provider == "openai":
        return "<OPENAI_KEY>"
    return None


llm = LLM(
    model="openrouter:openrouter/free",
    api_key_resolver=resolve_api_key,
)

This is the right hook when:

  • Tokens come from a local credential store.
  • Different providers use different auth flows.
  • Tokens may expire and need refresh logic.

OpenAI Codex OAuth

Republic exposes a dedicated login flow and resolver for OpenAI Codex-style OAuth.

from republic import LLM, login_openai_codex_oauth, openai_codex_oauth_resolver

login_openai_codex_oauth(
    prompt_for_redirect=lambda authorize_url: input(
        f"Open this URL and paste callback URL:\n{authorize_url}\n> "
    ),
)

llm = LLM(
    model="openai:gpt-5.3-codex",
    api_key_resolver=openai_codex_oauth_resolver(),
)
print(llm.chat("Say hello in one sentence."))

openai_codex_oauth_resolver() reads ~/.codex/auth.json by default, or $CODEX_HOME/auth.json when CODEX_HOME is set. The resolver returns the current OpenAI access token for provider openai and refreshes it automatically when expiry is near.

See examples/06_openai_codex_oauth.py for a runnable example.

GitHub Copilot OAuth

Republic also supports GitHub device-flow OAuth for the github-copilot provider.

from republic import LLM, github_copilot_oauth_resolver, login_github_copilot_oauth

login_github_copilot_oauth(
    device_code_notifier=lambda verification_uri, user_code: print(
        f"Open {verification_uri} and enter code: {user_code}"
    ),
)

llm = LLM(
    model="github-copilot:gpt-4.1",
    api_key_resolver=github_copilot_oauth_resolver(),
)
print(llm.chat("Say hello in one sentence."))

github_copilot_oauth_resolver() reads the saved GitHub OAuth token from ~/.config/republic/github_copilot_auth.json by default, or $XDG_CONFIG_HOME/republic/github_copilot_auth.json when XDG_CONFIG_HOME is set.

If no Republic auth file exists, the resolver also tries:

  • COPILOT_GITHUB_TOKEN
  • GH_TOKEN
  • GITHUB_TOKEN
  • ~/.config/gh/hosts.yml
  • gh auth token

The github-copilot provider reuses the standard any-llm OpenAI-compatible client and points it at GitHub Models. Republic only owns the GitHub OAuth token resolution and provider-specific default headers.

See examples/07_github_copilot_oauth.py for a runnable smoke test.

Recommendation

Use this split by default:

  • Simple scripts: api_key="<TOKEN>"
  • Multi-provider apps: api_key={...} or api_key_resolver=...
  • Local CLI integrations with existing auth state: provider-specific OAuth resolvers