How to Test Provider Credentials for API Connections in Open Notebook
Testing provider credentials in Open Notebook involves validating endpoint URLs for security and then executing a minimal API call using the cheapest available model to verify connectivity and key validity.
Open Notebook stores AI provider configurations as Credential records containing API keys and endpoint URLs. Before using these credentials in production workflows, you must verify they work correctly. The lfnovo/open-notebook repository provides a robust testing framework that validates both security constraints and actual API connectivity through a dedicated service layer.
How Credential Testing Works
The credential testing process follows a strict two-step validation sequence implemented in api/credentials_service.py. First, the system validates any custom endpoint URLs to prevent security vulnerabilities. Second, it executes a provider-specific minimal API request to confirm the credentials actually function.
URL Validation and Security Checks
Before making any external API calls, the validate_url function checks that custom endpoints are well-formed HTTP/HTTPS URLs. This validation explicitly blocks link-local addresses (e.g., 169.254.x.x) to protect self-hosted instances from Server-Side Request Forgery (SSRF) attacks. The function raises a ValueError immediately if the URL violates security policies.
Provider-Specific API Tests
After URL validation succeeds, the test_credential function loads the stored credential, converts it to an Esperanto configuration via to_esperanto_config(), and delegates to the appropriate test helper in open_notebook/ai/connection_tester.py. Each helper uses the cheapest model defined in TEST_MODELS to minimize costs while verifying connectivity.
Test Models by Provider
The open_notebook/ai/connection_tester.py file defines provider-specific test strategies using minimal-cost models:
- OpenAI: Uses
gpt-3.5-turboto send a single "Hi!" chat message - Anthropic: Uses
claude-3-haiku-20240307for a single-message chat test - Google: Uses
gemini-2.0-flashfor a minimal chat request - Ollama: Dynamically calls the
/api/tagsendpoint to verify model list access - Azure: Uses
gpt-35-turboto call the Azure OpenAI/openai/modelsendpoint - OpenAI Compatible: Calls the generic
/modelsendpoint of custom servers - ElevenLabs: Uses
eleven_multilingual_v2to generate a short audio clip - Deepgram: Uses
aura-2-thalia-ento test text-to-speech generation
Testing Credentials via the REST API
The FastAPI router in api/routers/credentials.py exposes a POST /credentials/{credential_id}/test endpoint that handles HTTP-level credential validation.
Test a specific credential using curl:
curl -X POST \
-H "Content-Type: application/json" \
http://localhost:5055/credentials/cred-12345/test
Successful responses return a JSON payload confirming connectivity:
{
"provider": "openai",
"success": true,
"message": "Connection successful"
}
Testing Credentials Programmatically
You can invoke the testing logic directly from Python without HTTP overhead using the service layer or low-level connection testers.
Direct Service Call
Call test_credential from api/credentials_service.py to test by credential ID:
import asyncio
from api.credentials_service import test_credential
async def main():
cred_id = "cred-12345"
result = await test_credential(cred_id)
print(result)
asyncio.run(main())
This returns a dictionary with the provider name, success status, and message.
Low-Level Connection Testing
For Azure-specific testing, use _test_azure_connection directly:
import asyncio
from open_notebook.ai.connection_tester import _test_azure_connection
async def demo():
ok, msg = await _test_azure_connection(
endpoint="https://my-azure-openai.openai.azure.com",
api_key="my-secret-key",
api_version="2024-10-21"
)
print(ok, msg)
asyncio.run(demo())
Generic Model Testing
To test any individual model using the Esperanto wrapper:
import asyncio
from open_notebook.ai.connection_tester import test_individual_model
from open_notebook.ai.models import ModelManager
async def demo():
manager = ModelManager()
model = await manager.get_model("openai/gpt-3.5-turbo")
success, msg = await test_individual_model(model)
print(success, msg)
asyncio.run(demo())
Error Handling and Normalization
When API calls fail, the _normalize_error_message function in open_notebook/ai/connection_tester.py converts raw exceptions into concise, actionable descriptions. Common normalized errors include "Invalid API key", "API key lacks required permissions", and "Connection timed out". This normalization ensures users receive clear feedback regardless of the provider's specific error format.
Summary
- URL validation occurs first via
validate_urlinapi/credentials_service.py, blocking link-local addresses to prevent SSRF attacks. - Provider-specific tests use the cheapest available models defined in
TEST_MODELSto minimize costs while verifying connectivity. - REST API endpoint
POST /credentials/{id}/testinapi/routers/credentials.pyprovides HTTP access to testing functionality. - Python service layer allows direct invocation of
test_credentialwithout HTTP overhead. - Error normalization converts provider-specific failures into standard messages like "Invalid API key" or "Connection timed out".
Frequently Asked Questions
How does Open Notebook prevent SSRF attacks when testing credentials?
The validate_url function in api/credentials_service.py explicitly rejects link-local addresses (such as 169.254.x.x) and validates that custom endpoints use proper HTTP/HTTPS schemes. This prevents attackers from using the credential testing feature to probe internal network resources.
What happens if my API key is valid but lacks permissions for specific models?
The connection tester will return a normalized error message indicating "API key lacks required permissions". The test uses the cheapest available model for each provider, so if your key works for basic models but not premium ones, the test will still pass, confirming basic connectivity and authentication.
Can I test Ollama connections to local endpoints?
Yes, but with security constraints. While Ollama typically runs locally, the validate_url function may block certain local addresses to prevent SSRF. The _test_ollama_connection helper dynamically calls the /api/tags endpoint to verify the Ollama instance is responding and accessible. Ensure your Ollama endpoint uses a valid, non-link-local URL format.
Where is the credential domain model defined?
The Credential domain model is defined in open_notebook/domain/credential.py. This model includes the to_esperanto_config() method used by the testing service to convert stored credentials into the format required by the connection testing framework.
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 →