API Key Best Practices
Follow these guidelines to keep your API tokens secure and your integrations reliable.
Security
Never hardcode tokens
Use environment variables or a secrets manager instead of hardcoding credentials.
Use a secrets manager
- AWS Secrets Manager
- HashiCorp Vault
- Google Secret Manager
- Azure Key Vault
Never commit tokens to version control
Add your environment files to .gitignore.
Environment Variables.gitignore
# Good — use environment variables
export UDACITY_API_KEY="your-token-here"
curl -H "Authorization: Token $UDACITY_API_KEY" ...// Good — read from environment
const apiKey = process.env.UDACITY_API_KEY;// Bad — hardcoded in source
const apiKey = "abc123def456";.env
.env.local
*.secretLifecycle
Token lifecycle
Always create tokens with an expiration date. We recommend 90 days or less.
Rotate tokens regularly
- Create a new token before the old one expires
- Update your integration to use the new token
- Verify the new token works
- Revoke the old token
Use descriptive names
Name tokens to make them easy to identify and audit.
Create TokenNaming Examples
mutation {
createToken(input: {
description: "Q1 2025 reporting integration"
expiresAt: "2025-04-01T00:00:00Z"
}) {
fullToken
token { id expiresAt }
}
}Good: "Production reporting - Accenture TQ - Q1 2025"
Good: "Staging catalog sync - weekly job"
Bad: "test"
Bad: "my token"Least Privilege
Request only the scopes you need
COMPANY:<companyId>scope
Grants access to Catalog, Program Progress, Assessment Progress, and Learning Plan Progress for a single company.
Use separate tokens for separate concerns
- One token for your reporting pipeline
- One token for your catalog sync
- One token for your staging environment
This limits the blast radius if a token is compromised.
Error Handling
Handle token expiration gracefully
Check for 401 Unauthorized responses and alert your team.
See Rate Limits for details on retry strategies.
Check for 401
const response = await fetch('https://api.udacity.com/api/public/api/v1/program-progress/graphql', { ... });
if (response.status === 401) {
// Token expired or revoked
alertOps('API token needs rotation');
}