A leaked API key costs money
An API key is a secret string that proves a request comes from you. A model provider often charges your account for every call that carries it.
Developers leak keys by typing them into code and pushing it to Git. Automated scanners look for exactly that, so a leaked key is a bill and a risk.
By the end of this lesson
Note
I can keep a key out of my code and my Git history.
Key words
| Word | What it means | Example |
|---|---|---|
| API key | a secret string that proves a request is yours | |
| Environment variable | a named value given to a program from outside its code | MY_API_KEY |
| The .env file | a text file of NAME=value lines for your own machine | |
| The .gitignore file | a list of files Git must never track | |
| Rotate | to make a new key and cancel the old one |
The cells students fill in are left blank in this preview.
In this lab your code holds no key
Your script sends the header authorization: Bearer lab. The word lab is a placeholder, not a key. On its way out, the platform swaps it for your real token and picks the model.
So the key is never in your code and you never see it. On a real project, you hold the key yourself.
Call a model with no key
docker exec -w /home/node/project agent node -e "const u=(process.env.AI_URL||'http://ai:4000')+'/v1/chat/completions';(async()=>{const headers={'content-type':'application/json',authorization:'Bearer lab'};console.log('Authorization header in my code: '+headers.authorization);try{const r=await fetch(u,{method:'POST',headers,body:JSON.stringify({model:'lab',messages:[{role:'user',content:'In one sentence, why must an API key stay out of code?'}],max_tokens:60})});const j=await r.json();if(r.ok===false)throw new Error(r.status+' '+j.error.message);console.log('Model: '+j.choices[0].message.content)}catch(e){console.log('No answer from the model ('+e.message+'). Recorded sample:');console.log('Model: Anyone who can read the code can use the key and spend your money.')}})()"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A real key lives in the environment
A real provider gives you a long key. Never type it into a file Git tracks. Put it in an environment variable, and read it in code with process.env.MY_API_KEY.
On your own machine, keep the variables in a .env file and list that file in .gitignore, so Git never sees it.
Write a demo .env and .gitignore
docker exec -w /home/node/project agent sh -c "mkdir -p keys-demo && printf 'EXAMPLE_API_KEY=not-a-real-key-123\n' > keys-demo/.env && printf '.env\n' > keys-demo/.gitignore"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Read the .env and hide the value
docker exec -w /home/node/project agent node -e "const fs=require('fs');const nl=String.fromCharCode(10);for(const line of fs.readFileSync('keys-demo/.env','utf8').trim().split(nl)){const i=line.indexOf('=');const v=line.slice(i+1);console.log(line.slice(0,i)+' is set, '+v.length+' characters, value hidden')}console.log('.env is in .gitignore: '+fs.readFileSync('keys-demo/.gitignore','utf8').split(nl).includes('.env'))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
The same idea in a real deployment
Your hosting service has a place for secrets and sets them as environment variables for your program. The code stays the same on your laptop and on the server.
Commit a .env.example file with the names and fake values. It tells a new teammate what to set.
Worked example: what to do after a leak
| What happened | What to do |
|---|---|
| The key is in code, not committed | Move it to an environment variable |
| It is committed, not pushed | Rotate the key, then rewrite the commit |
| It is pushed to a public repository | Rotate the key at once, then clean the history |
| It was pasted into a chat or a prompt | Rotate the key |
The cells students fill in are left blank in this preview.
A common mistake
Warning
Many people think deleting the key in a new commit removes it. Git keeps every old commit, so the key stays in the history for anyone who copied it. Rotate the key, because only a new key makes the old one useless.