TL;DR
This guide shows how to securely authenticate requests from your Software Development Kit (SDK) to a private API using API keys and tokens. We’ll cover key generation, secure storage within the SDK, and including authentication headers in each request.
1. Generate API Keys
Your API needs unique keys for each application or user using your SDK. Don’t use a single key for everything! Here’s how to generate them (example using Python):
import uuid
def generate_api_key():
return str(uuid.uuid4())
# Example usage:
new_key = generate_api_key()
print(f"New API Key: {new_key}")
Store these keys securely in your database, associated with the application or user that owns them. Never commit API keys directly into source control.
2. Secure Storage within the SDK
The SDK needs to store the API key safely on the user’s device/system. The best approach depends on the platform:
- Mobile (iOS & Android): Use the Keychain (iOS) or Keystore (Android). These are secure storage systems provided by the operating system, designed for sensitive data like passwords and API keys.
- Desktop Applications: Consider using OS-level secure storage mechanisms (e.g., Windows Credential Manager, macOS Keychain).
- Web Applications: Avoid storing API keys directly in browser local storage. Use server-side sessions or a more robust authentication flow like OAuth 2.0.
Important: Never hardcode API keys into your SDK code.
3. Authentication Header
Each request from the SDK to your API must include an authentication header. The most common approach is using the Authorization header with a bearer token:
- Get the Key: Retrieve the API key from secure storage within the SDK.
- Construct the Header: Create the
Authorizationheader in the formatBearer <API_KEY>. - Include in Request: Add this header to every HTTP request sent to your API.
Here’s an example using JavaScript (fetch API):
async function makeApiRequest(endpoint, data) {
const apiKey = await getApiKeyFromSecureStorage(); // Function to retrieve from Keychain/Keystore etc.
const headers = new Headers({
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
});
const response = await fetch(endpoint, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
});
return response.json();
}
4. API-Side Verification
Your API must verify the authenticity of each request:
- Extract Token: Extract the
Authorizationheader from the incoming request. - Validate Key: Check if the extracted API key exists in your database and is still active.
- Handle Invalid Keys: If the key is invalid, return an appropriate error response (e.g., 401 Unauthorized).
Example using Python/Flask:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/data', methods=['POST'])
auth_header = request.headers.get('Authorization')
if not auth_header:
return jsonify({'error': 'Missing Authorization header'}), 401
token = auth_header.split(' ')[1]
# Check if token exists in database and is valid (replace with your actual logic)
if not validate_api_key(token):
return jsonify({'error': 'Invalid API key'}), 401
# Process the request...
return jsonify({'message': 'Data processed successfully'})
5. Token Expiration & Refresh (Optional)
For increased security, consider using short-lived tokens and a refresh token mechanism:
- Short-Lived Tokens: Issue tokens with a limited lifespan (e.g., 1 hour).
- Refresh Tokens: Provide a separate refresh token that allows the SDK to obtain a new access token without requiring the user to re-authenticate.
This adds complexity but significantly improves security by limiting the impact of compromised tokens.