- Knowledge
- technology
- OOP
- Tips
- Programming
- Tips
- Tutorial
- SEO
- Ranking
- Knowledge
- Special Day
- Seo
- Bug
- Data science
- Seo
- artificial intelligence
- Machine Learning
- Robotics
- happyNewYear2021
- newYearEve
- 2021
- Automation
- Smart Home
- Career
- Best Practices
- Git
- Logging
- Web Fundamentals
- DNS
- HTTPS
- Performance
- AI Tools
- ChatGPT
- Claude
- Gemini
- Laravel
- Eloquent
- MySQL
- HTTPS
- TLS
- Web Security
- Certificates
- Developer Life
- Debugging
- Docker
- DevOps
- Transactions
- Queues
- LLMs
- AI
- AI Coding
- Developer Tools
- React Native
- Expo
- Kate PMS
- Mobile Apps
- Laravel
- Authentication
- Sanctum
- Cookies
- API Design
- Payments
- Idempotency
- DeepSeek
- Open Source AI
- LLMs
- AI News
- Git
- Version Control
- AI Coding
- Prompting
- PHP
- Checklist
- MCP
- AI Agents
- OpenAI
- Architecture
- Microservices
- Modular Monolith
- Estimation
- Developer Life
- Project Planning
- Humour
- OAuth
- OpenID Connect
- Authentication
- Embeddings
- Vector Search
- RAG
- pgvector
- OpenAI
- GPT-4.1
- Codex CLI
- Events
- Testing
- Clean Code
- Maintainability
- Code Review
- Webhooks
- API
- Security
- Claude Code
- Workflow
- AI
- LLM
- Prompt Injection
- Mobile
- React
- Networking
- TCP
- UDP
- HTTP/3
- CLAUDE.md
- AWS
- Cloud Security
- Backups
- PHPUnit
- Software Engineering
- Leadership
- Communication
- RAG
- Embeddings
- AI Engineering
- IT Infrastructure
- Networking
- Access Control
- CI/CD
- GitHub Actions
- Gemini CLI
- Claude Code
- JavaScript
- Async/Await
- Node.js
- Promises
- Security
- Cryptography
- Passwords
- MySQL
- Database
- Vibe Coding
- Software Quality
- DNS
- Code Reading
- Onboarding
- Productivity
- Background Jobs
- Developer Humour
- Estimates
- Dev Life
- JWT
- o3-mini
- DeepSeek R1
- Rate Limiting
- Kate PMS
- E-Signing
- Audit Trail
- REST
- GraphQL
- API Design
- Laravel 12
- Upgrade Guide
- Open Source
- Self-Hosting
- Task Scheduling
- Cron
- Secrets
- CORS
- PHP
- PHP-FPM
- OPcache
- GitHub Copilot
- Software Architecture
- Engineering
- TypeScript
- JavaScript
- Type Safety
- AI Security
- React Native
- Product Design
- AI Agents
- Kiro
- Queues
- Redis
- RabbitMQ
- AWS SQS
- Nginx
- Apache
- GPT-5
- gpt-oss
- Clean Code
- Architecture
- Naming
- Documentation
- Career
- ADR
- Teamwork
- Supply Chain
- Kate HRM
- HR Software
- Permissions
- System Design
- Pagination
- SSH
- Linux
- Big O
- Databases
- Laravel Boost
- MCP
- Developer Skills
- Validation
- Databases
- Indexes
- Code Quality
- Deployment
- Developer Humour
- Feature Flags
- Code Review
- Pull Requests
- Docker
- Cursor
- Authorization
- RBAC
- Gemini
- Long Context
- PHP 8.4
- Caching
- Dependency Injection
- Web Performance
- Browser
- CSS
- Database
- Migrations
- ChatGPT
- AI for Developers
- Monitoring
- On-Call
- REST
- Backend
- SQL
- NoSQL
- Database Design
- Coding Agents
- Claude 4
- API Resources
- REST API
- Load Balancing
- Scaling
- AWS
- AI Tools
- Claude
- Sora 2
- CTE
- 2FA
- TOTP
- Programming Languages
- Prompts
- Developer Workflow
- API Gateway
- APIs
- Passport
- API Auth
- Learning
- Burnout
- Developer Growth
- Web Development
- SEO
- Kate Mall
- ChatGPT Atlas
- Agent Skills
- Middleware
- Laravel 12
- Collections
- Context Window
- Monitoring
- Commit Messages
- Self Review
- Growth
- Regex
- Programming Basics
- Text Processing
- Database Design
- Normalization
- Linux
- Server Security
- Linux Foundation
- Open Standards
- Legacy Code
- Documentation
- AI Workflow
- File Uploads
- Test Data
- Hashing
- Performance
- Caching
- Enums
- Scope Creep
- Estimation
- Codex
- Gemini CLI
- Timezones
- Carbon
- Bugs
- PHP 8.5
- Gemini 3
- GPT-5.1
- Data Integrity
- Event Loop
- Async
- Opus 4.5
- AI Models
- React
- Forms
- Frontend
- Backups
- AI Images
- DALL-E
- Midjourney
- Race Conditions
- Concurrency
- Legacy Code
- Refactoring
- Senior Engineer
- Scope
- LLM
- CDN
- Web
- Sub-Agents
- Soft Deletes
- Audit Log
- Concurrency
- AI Learning
- NestJS
- AI Evals
- Policies
- SPF DKIM DMARC
- Unicode
- UTF-8
- Knowledge Graph
- Value Objects
- Technical Debt
- Feature Flags
- Laravel Pennant
- Deployment
- Copilot
- Composer
- Dependencies
- Artisan
- Automation
- AWS S3
- Object Storage
- Cloud
- Small Language Models
- Ollama
- Production
- Sessions
- HTTP
- Mentoring
- SQL
- Virtual Machines
- Web Development
- HTTP/2
- QUIC
- Web Performance
- AI Integration
- LLM API
- SOLID
- OOP
- Hosting
- Serverless
- Merge Conflicts
- Temperature
- AI Development
- Reverse Proxy
- Nginx
- Infrastructure
- Verification
- Passkeys
- WebAuthn
- Teams
- Communication
- Stakeholders
- Monorepo
- CI/CD
- Versioning
- JSON Schema
- Livewire
- Inertia
- Meetings
- Distributed Systems
- Privacy
- Full-Stack
- T-Shaped Skills
- Money
- Notifications
- Web Security
- HTTP Headers
- CSP
- Function Calling
- Load Testing
- k6
- Data Extraction
- Debugging
- WebSockets
- SSE
- Real-Time
- Laravel Reverb
- Infrastructure as Code
- Terraform
- Side Projects
- Laravel Pint
- OpenAPI
- Swagger
- UX
- Multimodal
- Jest
- Pair Programming
- APIs
- Rate Limiting
- Resilience
- Dev Humour
- Design Tokens
- JWT
- API Keys
- Sessions
- PHPStan
- Rector
- Incidents
- Reporting
- Dashboards
- Zero Trust
- IAM
- Search
- Laravel Scout
- Junior Developers
- Mentoring
- Images
- WebP
- AVIF
- Bug Reports
- Let's Encrypt
- Design Docs
- Software Design
- Observers
- Replication
- Accountability
- Data Structures
- Reliability
- LLM Memory
- Error Handling
- Payments
- Payment Gateway
- Webhooks
- PCI DSS
- Observability
- OpenTelemetry
- Personal Brand
- Writing
- Conventions
- Dates
- Scheduling
- Disaster Recovery
- Compression
- Brotli
- Deadlines
- Developer Habits
- State Machines
- Tech Roles
- UUID
- ULID
- Horizon
- Planning
- Engineering Culture
- Ownership
- Soft Skills
- Socialite
- Cost Control
- Collations
- Unicode
- Octane
- PostgreSQL
Environment Variables and Secrets: Keeping API Keys Out of Your Code (and Git History)
About Post
A developer notices an API key committed to the repository. They delete it, commit "remove key", push, and relax.
The key is still there. It's in the previous commit, in every clone, in every fork, and possibly in the logs of whatever bot scanned the repository while it was public. Deleting a secret from your code doesn't un-leak it.
Secrets are one of those topics everyone thinks they understand until the day something goes wrong. So let's go through how they should live in an app, where they actually leak, and what to do in the first hour after a leak.
The basic rule: config comes from the environment
Code is the same everywhere. Configuration is what changes between local, staging and production: database passwords, API keys, mail servers. The Twelve-Factor App guidelines put it neatly: store config in the environment, not in the code.
In practice, for most PHP and Node projects, that means a .env file locally and real environment variables (or a generated .env) on servers. Laravel gives you this from day one:
.envholds real values and is listed in.gitignore. Never commit it..env.exampleis committed, with every key and placeholder values, so a new developer knows what to fill in.
The habit that keeps this honest: any pull request that adds a new variable also adds it to .env.example. Reviewers should reject a new config key without one.
The Laravel trap: env() after config caching
In production you run php artisan config:cache, which compiles all config files into one cached PHP file. After that, Laravel stops loading .env, and any env() call outside the config/ folder returns null.
// Wrong: works locally, returns null in production after config:cache
$key = env('PAYMENT_API_KEY');
// Right: config/services.php
'payment' => [
'key' => env('PAYMENT_API_KEY'),
],
// Right: anywhere else in the app
$key = config('services.payment.key');
Read env() only in config files. Use config() everywhere else. This one rule removes a whole category of "it works locally" bugs, and it also gives you one place to see every secret the app depends on.
Where secrets actually leak
Committing .env is the famous mistake. These are the quieter ones I see more often:
- Frontend build variables. In a Vite project, anything prefixed
VITE_is compiled into the JavaScript bundle and readable by anyone. The same goes for keys baked into a mobile app. If it ships to the client, it's public. Only publishable keys belong there. - Debug pages.
APP_DEBUG=truein production can expose configuration and stack details to anyone who triggers an error. - Logs. Logging a whole request or an outgoing HTTP call can write tokens and passwords into files that many people can read.
- CI output and Docker images. An
echoin a pipeline step, or a.envcopied into an image layer, survives longer than you think. - Copy and paste. Screenshots in tickets, snippets in chat, a config file pasted into an AI assistant to "help debug".
Beyond .env: secret managers
A .env file on a server is fine for many apps. It starts to hurt when you have several servers, several people with access, and keys that need rotating. That's when a secret manager pays for itself: AWS Secrets Manager or Systems Manager Parameter Store, HashiCorp Vault, or your cloud's equivalent.
What you gain:
- Access control and audit. You can see who or what read a secret, and limit it per service.
- Rotation without redeploying by hand. Update the value in one place.
- No secrets on laptops. Developers don't need production values at all.
Usually the deploy pipeline fetches the values and writes them into the environment before config:cache runs, so the app itself stays simple.
And the best secret is the one you don't have. On AWS, an EC2 instance can use an IAM role to reach S3 or other services, so there is no access key to store, leak or rotate. Prefer that over long-lived keys wherever the platform allows it.
The rule that saves you: treat every secret as something that will leak one day. Give it the smallest permissions possible, make it easy to rotate, and know exactly where it's used.
A key leaked. Now what?
Order matters here. Most people instinctively start by cleaning the code. That's step four.
- Revoke or rotate the key immediately. Generate a new one, update production, then disable the old one. Until the old key is dead, nothing else matters.
- Check what it was used for. Look at the provider's usage logs or your cloud's audit trail for activity you don't recognise.
- Find out how it leaked. A commit, a log, a bundle, a screenshot? The cause decides the real fix.
- Clean up. Remove it from the code. If the repo was public, rewriting history is good hygiene, but assume the key is compromised regardless.
- Add a guard. Enable secret scanning (GitHub offers secret scanning and push protection), or add a pre-commit scanner like gitleaks.
One Laravel-specific note: rotating APP_KEY breaks existing encrypted data and sessions unless you plan for it. Since Laravel 11 you can list old keys in APP_PREVIOUS_KEYS so data encrypted with them can still be decrypted while you move over. The encryption docs explain how it works.
Checklist
.envignored,.env.examplecomplete and reviewed.env()only insideconfig/.- No secrets in frontend variables, mobile bundles, logs or CI output.
APP_DEBUG=falsein production.- IAM roles instead of static cloud keys where possible.
- A written, boring plan for rotating every key you own.
Which leak path surprised you the first time you saw it? For me it was frontend build variables: the name looks like config, the result is public JavaScript.

Be first to comment it...