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
# 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";
.gitignore
.env
.env.local
*.secret
Lifecycle

Token lifecycle

Always create tokens with an expiration date. We recommend 90 days or less.

Rotate tokens regularly

  1. Create a new token before the old one expires
  2. Update your integration to use the new token
  3. Verify the new token works
  4. Revoke the old token

Use descriptive names

Name tokens to make them easy to identify and audit.

Create Token
mutation {
  createToken(input: {
    description: "Q1 2025 reporting integration"
    expiresAt: "2025-04-01T00:00:00Z"
  }) {
    fullToken
    token { id expiresAt }
  }
}
Naming Examples
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');
}