- No hardcoded credentials in any files
- Environment variables used for sensitive data
- Token files are gitignored (
zoho_tokens.json
,tokens.json
) - Credential files are gitignored (
.env
,*.txt
credential files) - No console output of sensitive information
- Example values used in documentation (not real credentials)
Use these environment variables instead of hardcoded values:
ZOHO_CLIENT_ID=your_client_id_here
ZOHO_CLIENT_SECRET=your_client_secret_here
ZOHO_ORG_ID=your_organization_id_here
The following files are automatically excluded via .gitignore
:
# Tokens and credentials
zoho_tokens.json
tokens.json
.env
.env.local
.env.production
ZOHO-CLIENT-ID.txt
ZOHO-CLIENT-SECRET.txt
ZOHO-ORG-ID.txt
-
Minimal Scopes: Only request necessary permissions
'scopes' => [ 'ZohoAnalytics.data.all', 'ZohoAnalytics.metadata.read', 'ZohoAnalytics.embed.read', 'ZohoAnalytics.embed.update' ]
-
Secure Redirect URIs: Use HTTPS in production
'redirectUri' => 'https://yourdomain.com/oauth/callback'
-
Token Storage: Store tokens securely, never in version control
// Good: Local file with proper permissions $tokenFile = __DIR__ . '/zoho_tokens.json'; // Bad: Hardcoded tokens in code $accessToken = 'hardcoded_token_here'; // β NEVER DO THIS
- HTTPS Only: All API requests must use HTTPS
- Token Rotation: Implement automatic token refresh
- Error Handling: Don't expose sensitive information in error messages
- Rate Limiting: Respect API rate limits to avoid blocking
-
Production Environment:
- Use environment variables for all credentials
- Secure file permissions on token storage
- Regular token rotation
- Monitor API usage
-
Development Environment:
- Use separate OAuth applications for dev/staging/prod
- Never use production credentials in development
- Clear tokens when switching environments
- Organization ID: Verify you're accessing the correct organization
- Workspace Permissions: Ensure users have appropriate access levels
- Domain Restrictions: Configure allowed domains in Zoho Console
- IP Whitelisting: Use IP restrictions where applicable
// Load from environment with fallback
private function loadCredential(string $envVar, string $filePath): string
{
$value = getenv($envVar);
if ($value !== false && !empty(trim($value))) {
return trim($value);
}
$fullPath = realpath(__DIR__ . $filePath);
if ($fullPath && file_exists($fullPath)) {
return trim(file_get_contents($fullPath));
}
throw new \RuntimeException("Credential not found for $envVar");
}
// Hardcoded credentials - NEVER DO THIS
$clientId = '1000.ABC123DEF456';
$clientSecret = 'hardcoded_secret_here';
- Embed URLs: Have configurable expiry times
- Private URLs: Use secure random keys
- Shared URLs: Require authentication
- Domain Validation: Verify URLs are from expected domains
- Log Security Events: Authentication failures, token refresh
- Monitor API Usage: Unusual patterns or excessive requests
- Error Tracking: Monitor for security-related errors
- Audit Trail: Keep records of access and modifications
-
Credential Compromise:
- Immediately revoke OAuth application
- Generate new client credentials
- Update all environments
- Review access logs
-
Token Leakage:
- Revoke affected tokens
- Force re-authentication
- Check for unauthorized access
Before deploying:
- Credential Scan: Verify no credentials in code
- Permission Test: Confirm minimal required permissions
- Token Lifecycle: Test token refresh and expiry
- Error Handling: Ensure no sensitive data in error messages
- Data Privacy: Follow GDPR/CCPA guidelines for data access
- Access Control: Implement role-based access
- Audit Requirements: Maintain access logs
- Data Retention: Follow organizational data policies
When serving embed URLs, use appropriate security headers:
<meta http-equiv="Content-Security-Policy" content="frame-ancestors 'self' https://trusted-domain.com;">
<meta http-equiv="X-Frame-Options" content="SAMEORIGIN">
- Detection: Monitor for unusual API activity
- Containment: Revoke compromised credentials immediately
- Investigation: Review logs and access patterns
- Recovery: Restore secure access with new credentials
- Lessons Learned: Update security practices
- Review and rotate credentials quarterly
- Update dependencies for security patches
- Audit user permissions monthly
- Review API access logs weekly
- Test emergency procedures annually
For security issues:
- Do not create public issues for security vulnerabilities
- Contact repository maintainers directly
- Provide detailed information about the security concern
- Allow reasonable time for response and fix
Remember: Security is everyone's responsibility. When in doubt, choose the more secure option.