The Freerouting API implements a modular API authentication system to optionally protect sensitive endpoints from unauthorized access. The system uses a provider-based architecture that allows for multiple API key validation storage backends. Providers are evaluated in a priority fallback sequence.
Authentication is enabled by default. This is the secure-by-default configuration introduced in the Issue 650 fix. For local deployments (e.g. running Freerouting as a KiCad or EasyEDA plugin), authentication must be explicitly disabled:
java -jar freerouting-executable.jar --gui.enabled=false --api_server.enabled=true --api_server.authentication.enabled=false
Additionally, the server binds to http://127.0.0.1:37864 (localhost only) by default. To expose it to a network interface, explicitly set --api_server.endpoints=http://0.0.0.0:37864.
- Global Enable/Disable Toggle: easily switch authentication on or off depending on the environment.
- Priority-based Fallback: Configure multiple providers (e.g.
"GoogleSheets, MySQL"). The system checks them in sequence until one explicitly grants or denies access. - Modular Provider Architecture: Extensible design supports implementing multiple API authentication mechanisms.
- Tri-State Validation: Providers return
ACCESS_GRANTED,ACCESS_DENIED, orUNDECIDED. - Google Sheets Integration: A built-in provider reads API keys from a publicly accessible Google Sheet.
- Intelligent Caching: 5-minute cache refresh interval minimizes API calls to Google Sheets.
- Selective Endpoint Protection: Even when enabled, public endpoints remain accessible without authentication.
-
ApiKeyValidationService (
app.freerouting.api.security.ApiKeyValidationService)- The central service for authentication.
- Reads the configured provider list, initializes them, and orchestrates the fallback sequence.
- Resolves access grants based on provider Priority.
-
ApiKeyProvider Interface (
app.freerouting.api.security.ApiKeyProvider)- Defines the contract for API key validation.
- Supports multiple implementations (Google Sheets, database, file-based, etc.).
- Returns an
ApiKeyValidationResult.
-
GoogleSheetsApiKeyProvider (
app.freerouting.api.security.GoogleSheetsApiKeyProvider)- Reads API keys from a Google Sheet.
- Implements caching with automatic refresh.
- Validates GUID format and access permissions.
- Returns
PROVIDER_FAILEDduring severe outages orUNDECIDEDif keys are missing.
-
ApiKeyValidationFilter (
app.freerouting.api.security.ApiKeyValidationFilter)- JAX-RS request filter that intercepts all API requests.
- Uses the
ApiKeyValidationServiceto determine access rights. - Excludes specific public endpoints from validation.
To create a new API key provider, implement the ApiKeyProvider interface:
package app.freerouting.api.security;
public class MyCustomApiKeyProvider implements ApiKeyProvider {
@Override
public ApiKeyValidationResult validateApiKey(String apiKey) {
// Implement your validation logic
// 1. Validate key format
// 2. Check against your data source
// 3. Verify access permissions
return ApiKeyValidationResult.UNDECIDED;
}
@Override
public void refresh() {
// Implement cache refresh logic
// Should handle errors gracefully
}
@Override
public String getProviderName() {
return "My Custom Provider";
}
@Override
public boolean isHealthy() {
// Return true if provider can validate keys
return true;
}
}To use your custom provider, you need to append your provider's name to the string list of providers inside your apiServerSettings.authentication configuration, and instantiate your module inside ApiKeyValidationService:
// Inside ApiKeyValidationService.java
if (this.isEnabled && authSettings != null && authSettings.providers != null) {
String[] providerNames = authSettings.providers.split(",");
for (String providerName : providerNames) {
providerName = providerName.trim();
if ("MyCustomProvider".equalsIgnoreCase(providerName)) {
providers.add(new MyCustomApiKeyProvider());
FRLogger.info("Added Custom API Key Provider");
}
}
}The Google Sheets provider requires:
- A publicly accessible Google Sheet with API keys
- A Google API key for authentication
The sheet must have the following columns (order doesn't matter):
| API Key | Access granted? | (other columns...) |
|---|---|---|
| 550e8400-e29b-41d4-a716-446655440000 | Yes | ... |
| 660e8400-e29b-41d4-a716-446655440001 | No | ... |
Required Columns:
- API Key: Must contain valid GUID strings (RFC 4122 format)
- Access granted?: Must contain "Yes" (case-insensitive) to grant access
To access the Google Sheets API, you need a Google API key:
-
Create API Key:
- Go to Google Cloud Console - Credentials
- Click "Create Credentials" → "API Key"
- Copy the generated API key
-
Restrict API Key (Recommended):
- Click "Restrict Key" on your new API key
- Under "API restrictions", select "Restrict key"
- Choose "Google Sheets API" from the dropdown
- Click "Save"
-
Enable Google Sheets API:
- Go to Google Cloud Console - APIs
- Search for "Google Sheets API"
- Click "Enable" if not already enabled
A representative JSON configuration snippet showing the authentication block to enable the Google Sheets provider:
"api_server": {
"endpoints": ["http://127.0.0.1:37864"],
"authentication": {
"enabled": true,
"providers": "GoogleSheets",
"google_sheets": {
"google_api_key": "YOUR_GOOGLE_API_KEY",
"sheet_url": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
}
}
}Alternatively, you can supply these configuration values via environment variables:
Linux/Mac:
export FREEROUTING__API_SERVER__AUTHENTICATION__ENABLED=true
export FREEROUTING__API_SERVER__AUTHENTICATION__PROVIDERS="GoogleSheets"
export FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__SHEET_URL="https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
export FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"Windows PowerShell:
$env:FREEROUTING__API_SERVER__AUTHENTICATION__ENABLED="true"
$env:FREEROUTING__API_SERVER__AUTHENTICATION__PROVIDERS="GoogleSheets"
$env:FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__SHEET_URL="https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
$env:FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"-
Create Google Sheet:
- Create a new Google Sheet or use an existing one
- Add columns: "API Key" and "Access granted?"
- Add your API keys (must be valid GUIDs)
- Set "Access granted?" to "Yes" for authorized keys
-
Make Sheet Public:
- Click "Share" button
- Change to "Anyone with the link" can view
- Copy the sheet URL
-
Configure Freerouting:
- Build your
ApiServerSettingsconfiguration using the new JSON schema or use the environment variables explicitly mentioned above to configure theauthenticationblock. - Restart the Freerouting API server
- Build your
-
Verify:
- Check logs for:
"Added GoogleSheets API Key Provider" - Test with a valid API key:
curl -H "Authorization: Bearer YOUR_KEY" http://localhost:37864/v1/sessions/list
- Check logs for:
- Initial Load: Synchronous during provider initialization
- Refresh Interval: Every 5 minutes automatically
- Failure Handling: Maintains cached data if refresh fails
- Thread Safety: Uses
ConcurrentHashMapfor thread-safe access
The following endpoints are publicly accessible without API key validation:
| Endpoint Pattern | Description |
|---|---|
/v1/system/* |
System monitoring and health checks |
/v1/analytics/* |
Analytics tracking endpoints |
/dev/* |
Development and testing endpoints |
/openapi/* |
OpenAPI specification (JSON/YAML) |
/swagger-ui |
Swagger UI documentation interface |
/swagger-ui/* |
Swagger UI static assets |
All other endpoints require a valid API key in the Authorization: Bearer <API_KEY> header.
API keys must follow the RFC 4122 GUID format:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Where x is a hexadecimal digit (0-9, a-f, A-F).
Valid Examples:
550e8400-e29b-41d4-a716-446655440000A1B2C3D4-E5F6-7890-ABCD-EF1234567890
Invalid Examples:
not-a-guid12345678-1234-1234-1234-12345678901(too short)550e8400e29b41d4a716446655440000(missing hyphens)
curl http://localhost:37864/v1/sessions/listResponse:
{
"error": "Missing API key. Please provide a valid API key in the Authorization header using Bearer scheme (Authorization: Bearer <API_KEY>). You can apply for a free API key at https://www.freerouting.app."
}curl -H "Authorization: Bearer invalid-key" http://localhost:37864/v1/sessions/listResponse:
{
"error": "Invalid or unauthorized API key."
}When authentication is enabled but no providers are correctly configured, all requests to protected endpoints are denied. The log will contain:
API authentication is enabled but no providers are correctly configured. Denying access.
Response:
{
"error": "Invalid or unauthorized API key."
}Symptom: All protected endpoints return 401 with "Invalid or unauthorized API key." and the log contains "API authentication is enabled but no providers are correctly configured. Denying access."
Solutions:
- Check both environment variables (or corresponding JSON tokens) are configured when
providersincludes Google Sheets:"sheet_url"/FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__SHEET_URL"google_api_key"/FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__GOOGLE_API_KEY
- Verify Google Sheet URL is correct and accessible (sample)
- Verify Google API key is valid and has Sheets API enabled
- Check logs for initialization errors
- Ensure Google Sheet is publicly readable
Symptom: Known valid API keys return 401 "Invalid or unauthorized API key"
Solutions:
- Verify API key is a valid GUID format
- Check "Access granted?" column contains exactly "Yes" (case-insensitive)
- Wait up to 5 minutes for cache refresh if recently added
- Check logs for refresh errors
Symptom: New API keys not working after being added to Google Sheet
Solutions:
- Wait up to 5 minutes for automatic refresh
- Check Google Sheets API connectivity
- Verify sheet permissions haven't changed
- Restart API server to force refresh
- GUID Generation: Use cryptographically secure random GUID generators
- Key Rotation: Regularly rotate API keys and remove old ones
- Access Logging: Monitor API key usage via application logs
- Sheet Permissions: Keep Google Sheet read-only for public access
- HTTPS Only: Always use HTTPS in production to protect API keys in transit
- Public Sheet: Google Sheet must be publicly readable (anyone with link)
- No Rate Limiting: Provider does not implement rate limiting (add separately if needed)
- Cache Delay: Up to 5 minutes delay for new keys to become active
- No Key Expiration: Provider does not support automatic key expiration
FROM freerouting:latest
ENV FREEROUTING__API_SERVER__AUTHENTICATION__ENABLED="true"
ENV FREEROUTING__API_SERVER__AUTHENTICATION__PROVIDERS="GoogleSheets"
ENV FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__SHEET_URL="https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
ENV FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"apiVersion: v1
kind: ConfigMap
metadata:
name: freerouting-config
data:
FREEROUTING__API_SERVER__AUTHENTICATION__ENABLED: "true"
FREEROUTING__API_SERVER__AUTHENTICATION__PROVIDERS: "GoogleSheets"
FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__SHEET_URL: "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__GOOGLE_API_KEY: "YOUR_GOOGLE_API_KEY"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: freerouting-api
spec:
template:
spec:
containers:
- name: freerouting
envFrom:
- configMapRef:
name: freerouting-config[Unit]
Description=Freerouting API Server
After=network.target
[Service]
Type=simple
Environment="FREEROUTING__API_SERVER__AUTHENTICATION__ENABLED=true"
Environment="FREEROUTING__API_SERVER__AUTHENTICATION__PROVIDERS=GoogleSheets"
Environment="FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__SHEET_URL=https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
Environment="FREEROUTING__API_SERVER__AUTHENTICATION__GOOGLE_SHEETS__GOOGLE_API_KEY=YOUR_GOOGLE_API_KEY"
ExecStart=/usr/local/bin/freerouting
Restart=on-failure
[Install]
WantedBy=multi-user.targetcurl -H "Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000" \
http://localhost:37864/v1/sessions/listimport requests
headers = {
'Authorization': 'Bearer 550e8400-e29b-41d4-a716-446655440000'
}
response = requests.get(
'http://localhost:37864/v1/sessions/list',
headers=headers
)
print(response.json())const axios = require('axios');
const config = {
headers: {
'Authorization': 'Bearer 550e8400-e29b-41d4-a716-446655440000'
}
};
axios.get('http://localhost:37864/v1/sessions/list', config)
.then(response => console.log(response.data))
.catch(error => console.error(error));import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:37864/v1/sessions/list"))
.header("Authorization", "Bearer 550e8400-e29b-41d4-a716-446655440000")
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.
println(response.body());The API key validation system logs the following events:
INFO Level:
"Added GoogleSheets API Key Provider"— Google Sheets provider initialized successfully"Successfully refreshed X valid API keys from Google Sheets (total entries: Y, skipped: Z)"— Cache refresh completed with a change in key count"Google Sheets API key provider initialized with X keys"— Provider constructed
WARN Level:
"GoogleSheets provider configured but sheetUrl or googleApiKey is missing."— Required configuration absent"API key validation failed: missing or invalid Authorization header for path X"— Request without API key"API key validation failed: invalid or unauthorized API key for path X"— Invalid key used"API authentication is enabled but no providers are correctly configured. Denying access."— No usable providers"API server authentication is DISABLED. All API endpoints are accessible without an API key."— Auth disabled warning (logged once on server startup)
ERROR Level:
"Failed to initialize Google Sheets API key provider"- Provider initialization failed"Failed to refresh API keys from Google Sheets"- Cache refresh failed"Required columns not found in Google Sheet"- Sheet structure invalid
DEBUG Level:
"API key validation skipped for excluded path: X"- Public endpoint accessed"API key validation successful for path: X"- Valid key used"Skipping invalid GUID in row X"- Invalid GUID in sheet
Potential improvements for the API key validation system:
- Database Provider: Store API keys in PostgreSQL/MySQL for better performance
- Redis Caching: Use Redis for distributed caching across multiple instances
- Key Expiration: Support automatic key expiration dates
- Rate Limiting: Implement per-key rate limiting
- Scoped Permissions: Allow different keys to access different endpoint sets
- Audit Logging: Detailed audit trail of all API key usage
- Key Management API: Endpoints to manage API keys programmatically
- Multiple Providers: Support multiple providers simultaneously with fallback