API Security Best Practices
Follow these guidelines to build secure integrations that protect student data and your API credentials.
Never expose your API key in client-side code
API keys included in browser JavaScript, mobile apps, or any client-side code can be extracted by anyone. Always make API calls from your server.
// BAD: Never do this!
// This exposes your API key to anyone viewing your page source
// In browser JavaScript:
fetch('https://api.classaddmin.com/v1/students', {
headers: {
'Authorization': 'Bearer sk_live_xxxxx' // EXPOSED!
}
})Security Best Practices
API Key Security
Protect your API credentials
- Never expose API keys in client-side code (JavaScript in browsers)
- Use environment variables to store API keys
- Never commit API keys to version control (add to .gitignore)
- Use different API keys for development and production
- Rotate API keys periodically and after any suspected breach
- Use the minimum required permissions for each API key
Server-Side Requests
Always make API calls from your backend
- Make all API calls from your server, never from the browser
- Create a backend endpoint that proxies requests to ClassAddmin
- Implement your own authentication layer for your users
- Validate and sanitize all user input before sending to the API
- Log API requests for auditing purposes (exclude sensitive data)
Data Protection
Handle student data responsibly
- Only request data you actually need (use field selection)
- Implement proper access controls in your application
- Don't store sensitive API responses longer than necessary
- Encrypt any cached or stored data at rest
- Comply with local data protection regulations (e.g., GDPR, DPA)
- Have a data retention and deletion policy
Error Handling
Handle errors without exposing sensitive information
- Never expose raw API error messages to end users
- Log detailed errors server-side for debugging
- Show generic error messages to users
- Implement proper retry logic with exponential backoff
- Monitor for unusual error patterns that may indicate attacks
Rate Limiting
Respect API limits and protect against abuse
- Implement caching to reduce API calls
- Handle 429 (Too Many Requests) responses gracefully
- Use bulk endpoints instead of multiple individual requests
- Implement your own rate limiting for your users
- Monitor your API usage to stay within limits
Access Control
Implement proper authorization
- Verify user permissions before making API requests on their behalf
- Don't rely solely on client-side permission checks
- Implement role-based access control (RBAC) in your application
- Log all data access for audit trails
- Regularly review who has access to what data
Implementation Examples
1. Store API keys in environment variables
# .env file (never commit this!)
CLASSADDMIN_API_KEY=sk_live_xxxxxxxxxxxxx
# .gitignore
.env
.env.local
.env.production2. Make API calls from your server
// GOOD: Server-side API call (Node.js/Express)
app.get('/api/students', async (req, res) => {
// Verify user is authenticated
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
// Check user has permission
if (!req.user.canViewStudents) {
return res.status(403).json({ error: 'Forbidden' });
}
try {
const response = await fetch('https://api.classaddmin.com/v1/students', {
headers: {
'Authorization': `Bearer ${process.env.CLASSADDMIN_API_KEY}`,
'Content-Type': 'application/json',
},
});
const data = await response.json();
// Log for audit (exclude sensitive fields)
console.log(`User ${req.user.id} accessed students list`);
res.json(data);
} catch (error) {
// Log detailed error server-side
console.error('API Error:', error);
// Return generic error to client
res.status(500).json({ error: 'Failed to fetch students' });
}
});3. Handle errors securely
// Good error handling pattern
async function fetchStudents() {
try {
const response = await classaddmin.students.list();
return response.data;
} catch (error) {
// Log detailed error for debugging
logger.error('Failed to fetch students', {
error: error.message,
code: error.code,
requestId: error.requestId,
});
// Classify error for user-facing message
if (error.code === 'authentication_failed') {
throw new AppError('Configuration error. Please contact support.');
} else if (error.code === 'rate_limit_exceeded') {
throw new AppError('Too many requests. Please try again later.');
} else {
throw new AppError('Unable to load students. Please try again.');
}
}
}4. Validate and sanitize input
// Always validate user input before sending to API
function createStudent(userInput) {
// Validate required fields
if (!userInput.firstName || !userInput.lastName) {
throw new Error('First and last name are required');
}
// Sanitize string inputs
const sanitizedData = {
first_name: sanitizeString(userInput.firstName, 50),
last_name: sanitizeString(userInput.lastName, 50),
date_of_birth: validateDate(userInput.dateOfBirth),
gender: validateEnum(userInput.gender, ['male', 'female']),
class_id: validateUUID(userInput.classId),
};
return classaddmin.students.create(sanitizedData);
}
function sanitizeString(input, maxLength) {
return String(input)
.trim()
.slice(0, maxLength)
.replace(/[<>]/g, ''); // Basic XSS prevention
}Our Security Measures
ClassAddmin implements industry-standard security measures to protect your data.
Encryption in Transit
All API communications use TLS 1.3 encryption
Encryption at Rest
All data is encrypted at rest using AES-256
SOC 2 Compliance
Our infrastructure follows SOC 2 Type II standards
Regular Audits
Third-party security audits conducted annually
DDoS Protection
Enterprise-grade DDoS mitigation on all endpoints
Bug Bounty Program
Responsible disclosure program for security researchers
Found a security vulnerability?
We take security seriously. Please report any vulnerabilities through our responsible disclosure program.