API keys act as digital gatekeepers, authenticating interactions between online services by confirming that requests come from authorized sources. They're critical for enabling secure communication between applications, services, and APIs. Unfortunately, attackers understand their value all too well and often target these keys.
A single leaked key can grant attackers extensive access to your sensitive business information. The consequences of such a security lapse can range from significant financial losses to severe reputational damage. Given these high stakes, developers must prioritize robust API key security practices to prevent unauthorized access to their applications.
In brief:
- API keys are vulnerable credentials that require proper security practices to prevent unauthorized access to systems and sensitive data.
- Common security mistakes include hardcoding keys in source code, storing them in public configuration files, and accidental exposure in repositories.
- Best practices include using environment variables, dedicated secret managers, backend proxies, and implementing regular key rotation.
- A comprehensive security approach combines secure storage, minimal permissions, monitoring, and automated management processes.
Common Mistakes Developers Make While Storing API Keys
Understanding common API key security mistakes helps developers avoid costly security breaches.
- Store API Keys directly in source code. If you store API keys in source code, they are exposed to anyone with code access, including attackers scanning repositories. Always store keys separately from your codebase.
- Use publicly accessible configuration files. Configuration files tracked in version control or publicly accessible can unintentionally expose your keys. Keep sensitive configuration files private and excluded from public repositories.
- Avoid hardcoding keys in front-end applications. Sometimes, developers push API keys to the front end of their websites. Any API key in client-side code is essentially public information. Any bad actor can inspect the JavaScript running in browsers, which can expose your keys. Sensitive keys should remain server-side where they're protected.
- Don’t expose keys in public repositories. "I'll just commit this quickly and clean it up later..." is a lazy developer attitude that might lead to the exposure of API keys. Attackers continuously scan public repositories for credentials, so even brief exposure can lead to compromise.
How to Store API Keys Securely
Developers have multiple reliable approaches for securely storing API keys. Strapi recommends the following methods to safeguard your credentials effectively.
1. Set Environment Variables
Environment variables are dynamic values stored outside the application's code. Developers commonly use them to handle API keys securely. They prevent exposing sensitive information directly in source files, allowing the application to access keys at runtime while keeping them hidden from unauthorized users and separate from version-controlled codebases.
Advantages
- Keeps API keys separate from version-controlled source code
- Easy to use across different development frameworks
- Integrates easily with mainstream CI/CD tools
Disadvantages
- Vulnerable to exposure through misconfigured servers or logging
- Can be challenging to manage at scale without a secrets manager
- No encryption by default
To use environment variables for storing API keys:
- In Windows:
1setx OPENAI_API_KEY "<yourkey>"
- In macOS/Linux:
1echo "export OPENAI_API_KEY='<yourkey>'" >> ~/.zshrc
2source ~/.zshrc
For Node.js applications, you can use the dotenv
package:
1require('dotenv').config();
2const apiKey = process.env.API_KEY;
For Python applications, use the python-dotenv
package:
1from dotenv import load_dotenv
2import os
3
4load_dotenv()
5api_key = os.getenv("API_KEY")
Remember to add your .env
file to .gitignore
to prevent accidental commits of sensitive information.
2. Set Up Configuration Management Tools
You can use configuration management tools (e.g., Ansible) to store, deploy, and manage API keys securely. These tools encrypt secrets, limit access to authorized users, and track any changes. This reduces security risks and keeps keys safe and consistent across all environments.
Advantages
- Encryption at rest and in transit
- Centralized control and detailed audit logs
- Simplified rotation and permissions management
Disadvantages
- Higher operational complexity and setup overhead
- Risk of a single point of failure without proper architecture
These tools connect to your application through SDKs or APIs so you can retrieve secrets when needed.
3. Configure Back-End Proxy Server or Middleware
You can use a backend proxy to keep API keys away from client-side code.
Here's how it works:
- Clients send requests to your proxy server.
- Your proxy adds the API key before forwarding the request.
- The proxy sends responses back to the client.
This approach ensures clients never see your API keys.
Here's a simplified example using Node.js and Express:
1const express = require('express');
2const axios = require('axios');
3const app = express();
4
5const API_KEY = process.env.API_KEY;
6const EXTERNAL_API_URL = 'https://api.example.com';
7
8app.get('/api/data', async (req, res) => {
9 try {
10 const response = await axios.get(`${EXTERNAL_API_URL}/data`, {
11 headers: { 'Authorization': `Bearer ${API_KEY}` }
12 });
13 res.json(response.data);
14 } catch (error) {
15 res.status(500).json({ error: 'An error occurred' });
16 }
17});
18
19app.listen(3000, () => console.log('Proxy server running on port 3000'));
Advantages
- API keys remain hidden from client-side code
- Easy to manage and audit API access centrally
Disadvantages
- Increase in response times due to extra network hops
- If the proxy service goes down, API functionality across the application is impacted
4. Install a Secrets Manager or Dedicated Vault
You can use a Secrets Manager or a Dedicated Vault – specialized tools, such as HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault – explicitly designed for the secure storage, management, and retrieval of sensitive information, like API keys.
To use AWS Secrets Manager:
- Store your API key in Secrets Manager through the AWS Console or CLI.
- In your application, use the AWS SDK to retrieve the secret:
1import boto3
2
3def get_secret():
4 client = boto3.client('secretsmanager')
5 response = client.get_secret_value(SecretId='your-secret-name')
6 return response['SecretString']
7
8api_key = get_secret()
This approach provides centralized management across your infrastructure. You can use powerful features like automatic rotation and granular access controls to strength your API key security.
Advantages
- Automatic key rotation, detailed audit logs, and controlled access
- Enhanced security compliance and reduced risk of exposure
Disadvantages
- Possible vendor lock-in or resource-intensive maintenance requirements
- Additional costs from licensing, infrastructure, or cloud service fees
Choose the storage method that best matches your project's size, security requirements, and organizational setup. Each of these approaches is significantly better than hardcoding keys in your source code and is crucial in learning how to store API keys securely.
Additional Security Measures
A comprehensive API key security strategy requires rotation, permission controls, and vigilant monitoring.
Implement API Key Rotation and Expiration
Think of key rotation like changing your passwords—it limits how long a stolen key remains useful.
- Rotation Schedule: Change your API keys at least every 90 days. For sensitive systems, aim for 30-60 day cycles.
- Expiration Policies: Assign expiration dates, especially for temporary keys, to eliminate forgotten credentials.
- Zero-Downtime Rotation: Create new keys before revoking old ones to avoid service interruptions. Ideally, use systems that support multiple active keys for smooth transitions.
- Automation: Build key rotation into your CI/CD pipeline with scripts that generate new keys, update configs, and revoke old keys after validation.
Limit API Key Permissions & Scope
Assign API keys the minimal permissions required for their specific tasks to mitigate risks.
- Granular Permissions: Provide only necessary access, avoiding broad privileges. For example, if a service only needs to read data, don't give it write access.
- Resource Restrictions: Limit keys to specific datasets, resources, or services.
- IP Whitelisting: Restrict key usage to trusted IP addresses to prevent unauthorized access from external sources.
- Rate Limiting: Cap the number of requests a key can make within a time frame. This slows down attackers and helps flag unusual activity.
- Parameter Filtering: Allow keys to perform only predefined actions and queries, narrowing their capabilities.
Enable Audit Logging & Monitoring
Effective monitoring and detailed logs allow rapid detection and response to unauthorized key use.
- Usage Monitoring: Track API key activity in real-time to detect unexpected usage spikes or unusual access patterns (e.g., access from an unknown location).
- Alerting Systems: Set up notifications for suspicious activities, such as multiple failed authentication attempts or unusual usage patterns.
- Regular Audits: Regularly review logs, remove unnecessary keys, and adjust permissions to minimize potential attack surfaces.
- Comprehensive Logging: Record all key-related events, such as creation, usage, revocation, and access attempts. These logs become crucial during security investigations.
For example, tools like Strapi audit logs provide detailed information about actions within the application, including content type modifications, user activities, and changes to roles and permissions. Each log entry includes details such as the action type, date and time, user involved, and can also show the user's IP address, request body, and response body for thorough tracking and analysis.
Real-world Example: How to Store API Keys Securely with a Headless CMS (Strapi)
The latest Strapi 5 release has significantly improved security features and API handling capabilities. As detailed in the Strapi v5 documentation, the new version includes an Audit Log for tracking API actions, best practices for API security, robust vulnerability management, strong encryption and data management protocols, and secure development practices.\
Strapi provides you with API tokens that allow users to authenticate REST and GraphQL API queries.
Set Up Environment Variables in Strapi
Strapi allows the use of environment variables for sensitive information:
- Create a
.env
file in your Strapi project's root directory:
1API_KEY=your_api_key_here
2DATABASE_PASSWORD=your_database_password
- Add
.env
to your.gitignore
file to prevent accidental commits:
1echo ".env" >> .gitignore
- In your Strapi configuration files (e.g.,
config/server.js
orconfig/database.js
), reference these environment variables using theenv
function:
1module.exports = ({ env }) => ({
2 host: env('HOST', '0.0.0.0'),
3 port: env.int('PORT', 1337),
4 app: {
5 keys: env.array('APP_KEYS'),
6 },
7 apiToken: {
8 salt: env('API_TOKEN_SALT'),
9 },
10});
Configure External API Connections Securely
When connecting to external APIs from Strapi, create a dedicated service:
- Create a custom service to handle API requests:
1// services/externalApi.js
2const axios = require('axios');
3
4module.exports = {
5 async makeApiCall() {
6 const apiKey = process.env.EXTERNAL_API_KEY;
7 const response = await axios.get('https://api.example.com/data', {
8 headers: {
9 'Authorization': `Bearer ${apiKey}`
10 }
11 });
12 return response.data;
13 }
14};
- Use this service in your controllers:
1// controllers/customController.js
2module.exports = {
3 async getData(ctx) {
4 const { externalApi } = strapi.services;
5 const data = await externalApi.makeApiCall();
6 ctx.send(data);
7 }
8};
Best Practices for API Key Management in Strapi
When working with Strapi, especially in cloud environments like managing API keys in Strapi Cloud, it's important to manage API keys securely.
- Use Strapi's built-in API token system: Strapi v5 provides a robust API token management system for authenticating external requests. Developers can create tokens via the admin panel with options such as Read-only, Full access, or Custom permissions, and configurable expiration durations.
- Implement role-based access control: Strapi’s built-in permissions system allows granular control over what each API token can access. Assign minimal necessary permissions to each token, following the principle of least privilege.
- Rotate keys regularly: Rotate your API keys regularly to minimize the risk of compromised credentials. Automate this rotation through Strapi’s lifecycle scripts or integrate external rotation processes into your CI/CD pipeline.
- Monitor API usage: Strapi’s audit logs record crucial activities, including data modifications, user actions, and configuration changes. Regularly reviewing audit logs helps identify suspicious API usage and ensures accountability.
- Use secure protocols: Always use HTTPS when communicating with Strapi’s API to ensure encryption and data integrity in transit.
Secure API Keys to Improve Your Security Posture
Securing API keys requires consistent attention throughout their lifecycle. Implementing secure storage, limited permissions, regular rotation, and active monitoring helps build a reliable security posture.
Begin with practical steps, such as removing API keys from source code and implementing scheduled key rotations. Gradually enhance security by incorporating automated management and detailed monitoring solutions.
Ready to implement enterprise-grade API key security? Try Strapi v5 with its enhanced API token management, granular permissions system, and robust audit logging. Secure your headless CMS and protect your digital assets with Strapi's comprehensive security features.