API Key 驗證是什麼?新手一看就懂的完整教學

Published December 12, 2025 by 徐培鈞
基礎概念

嘿!如果你正在用 AI 工具寫程式,或是玩一些自動化工具(像 Make、Zapier、n8n),一定碰過這種情況:

「請輸入你的 API Key」

蛤?那是什麼?我要去哪裡拿?

或是 AI 幫你生出一段程式碼,裡面寫著 X-API-Key: your_key_here,然後你就卡住了。

別擔心,這篇文章就是要用最白話的方式,讓你搞懂:

  • API Key 到底是什麼東西?
  • 為什麼有些服務需要它?
  • 拿到之後要放在哪裡?

不用會寫程式也能看懂,看完你就知道怎麼處理了。

先搞懂 HTTP 長什麼樣子

在講 API Key 之前,我們要先知道 HTTP 請求的結構。這很重要,因為 API Key 就是塞在 HTTP 裡面的。

HTTP 請求就像寄一封信

每次你打一個 API,其實就是送出一個 HTTP 請求。你可以把它想像成寄一封信:

  • Header(表頭):就像信封外面的資訊——寄件人、收件人、郵戳、掛號或平信
  • Body(內容):就像信封裡面的信紙——你真正要講的內容

這兩個部分各有各的用途,不能搞混。

來看一個真實的 HTTP 請求

假設你要打一個 API 新增一筆使用者資料,整個請求長這樣:

POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer abc123
X-API-Key: my_secret_key

{
  "name": "小明",
  "email": "ming@example.com"
}

上半部(空行以上)就是 Header,下半部就是 Body

Header 裡面有什麼?

Header 就是一堆「欄位名稱: 值」的組合,每一行一個。常見的有:

幹嘛用的告訴對方你要打哪個網站
範例Host: api.example.com
幹嘛用的告訴對方你傳的資料是什麼格式
範例Content-Type: application/json
幹嘛用的放驗證資訊(像是 Token)
範例Authorization: Bearer abc123
幹嘛用的告訴對方你是用什麼工具發請求
範例User-Agent: Mozilla/5.0...
幹嘛用的告訴對方你想要什麼格式的回應
範例Accept: application/json

這些都是「標準」的 Header,大家都認得。

Body 裡面有什麼?

Body 就是你要傳的實際資料。最常見的格式是 JSON:

{
  "name": "小明",
  "email": "ming@example.com"
}

不是每個請求都有 Body 喔!像 GET 請求通常就沒有,因為你只是要「拿」資料,不是要「傳」資料。

重點來了:你可以自己定義 Header!

除了那些標準的 Header 之外,我們可以自己發明新的欄位,這叫做 Custom Header(自定義表頭)。

以前有個慣例是在自定義 Header 前面加 X-,像這樣:

X-API-Key: 你的金鑰
X-Request-ID: 12345

但這只是慣例,不是強制規定。你愛怎麼取名都可以,沒有人會阻止你。

而且這個 X- 慣例在 2012 年已經被官方(RFC 6648)建議棄用了,原因是:如果一個自定義 Header 後來變成標準,名字裡還卡著 X- 就很尷尬。

所以現在你會看到兩種風格並存:

X-API-Key: abc123     // 舊慣例,還是很多人在用
API-Key: abc123       // 新風格,不加 X- 也完全 OK

實務上,看你串接的服務要求什麼格式就用什麼

有些服務用 X-API-Key,有些用 API-Key,甚至有些用 Authorization,都可以,沒有絕對的對錯。

API Key 到底怎麼用?什麼時候該用?

API Key 是什麼?

簡單講,API Key 就是一組「通關密碼」,用來證明「我有權限使用這個服務」。

舉個例子:你想在自己的網站上嵌入 Google Maps 地圖。Google 不會讓你免費無限用,所以你要先去 Google 後台申請一組 API Key,拿到之後可能長這樣:

AIzaSyD8f9Gk3xPm2nQwR7vL4jH5kM6sT1oY2bC

之後每次你的網站要顯示地圖,就要帶上這組 Key。Google 收到請求後會檢查:「這把 Key 我認得,是有註冊的,放行!」然後才把地圖資料給你。

就像進公司要刷門禁卡一樣——沒卡,門不會開。

其他常見的情境:

  • OpenAI API 讓你的應用程式能呼叫 ChatGPT
  • 串接金流服務(綠界、藍新)處理付款
  • Facebook / Instagram API 發文或抓數據

這些服務都會給你一組 API Key,你要保管好,別讓外人知道。

什麼情況適合用 API Key?

✅ 正確場景:從你的伺服器呼叫 API

這是 API Key 最適合的用法。

舉個例子:你做了一個電商網站,使用者下單後要付款。流程是這樣:

flowchart LR
    User["使用者"] -->|1.按下結帳| Server["你的伺服器"]
    Server -->|2.帶 API Key 呼叫| Payment["綠界金流 API"]
    Payment -->|3.回傳結果| Server
    Server -->|4.顯示成功| User

整個過程中,API Key 都待在你的伺服器裡,使用者完全碰不到,也看不到。

這就是為什麼這種做法安全:

  • Key 只有你的伺服器知道
  • 外人沒有任何管道可以偷看
  • 你可以設定只有特定 IP 能連進來,多一層保護

❌ 錯誤場景:從瀏覽器或 App 直接呼叫 API

這是很多新手會踩的坑。

舉個例子:你做了一個網頁,想讓使用者輸入問題,然後直接呼叫 OpenAI API 取得回答。你把 API Key 寫在 JavaScript 裡面:

flowchart LR
    User["使用者的瀏覽器"] -->|帶 API Key 呼叫| OpenAI["OpenAI API"]
    Hacker["有心人士 👀"] -.->|打開開發者工具偷看| User

問題來了:JavaScript 是跑在使用者瀏覽器裡的,任何人只要按 F12 打開開發者工具,就能看到你的 Key。

手機 App 也一樣,可以被反編譯,Key 照樣被挖出來。

Key 被偷走之後會怎樣?別人拿你的 Key 亂用,帳單寄給你。

真實案例:Google Maps API Key

這是一個經典案例,用 Google Maps 來看正確和錯誤的差別:

❌ 錯誤示範:Key 寫在前端

很多網站直接把 Google Maps 的 API Key 寫在 HTML 裡:

<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD8f9Gk3xPm2nQwR7vL4jH5kM6sT1oY2bC"></script>

任何人只要「檢視原始碼」就能複製這把 Key,然後拿去自己的網站用。Google Maps 是要收費的,帳單會寄給原本的 Key 擁有者。

✅ 正確示範:Key 放在後端

安全的做法是讓你的伺服器去呼叫 Google Maps API,前端只跟你的伺服器溝通:

flowchart LR
    Browser["使用者的瀏覽器"] -->|1.請求地圖資料| Server["你的伺服器"]
    Server -->|2.帶 API Key 呼叫| Google["Google Maps API"]
    Google -->|3.回傳地圖資料| Server
    Server -->|4.轉給前端| Browser

這樣 Key 永遠不會出現在使用者的瀏覽器裡,自然也不會被偷。

記住這個原則:API Key 只能存在伺服器上,絕對不能出現在前端。

那 Key 要放在哪裡?

確定要用 API Key 之後,要放在請求的哪個位置呢?

推薦做法:放在 Header

X-API-Key: Admin123

打 API 的時候帶上這個 Header,後端收到就會去檢查「這把 Key 對不對」,對了才給你資料。

另一種做法:放在 Query String

有些人會放在網址後面:

https://api.example.com/data?api_key=Admin123

但這樣比較不安全,因為網址可能會被記錄在瀏覽器歷史、伺服器 Log 裡面,所以建議還是放 Header

怎麼管理 API Key?

假設今天你要提供 API 給別人用,你要怎麼給他們 Key?

方法一:直接寫死

最簡單的方式,就是訂好一組 Key,然後告訴對方。

API_KEY=secret123456

優點是簡單,缺點是不夠彈性。適合公司內部系統,大家都是自己人的情況。

方法二:用資料庫管理

比較正式的做法是把 Key 存在資料庫裡,這樣你可以:

  • 隨時產生新的 Key
  • 隨時把 Key 停用或刪除
  • 設定 Key 的有效期限

像 Slack、Discord 這些服務,都有一個「產生 API Key」的按鈕,按下去就給你一組 Key。不想用了?按刪除就好。這就是用資料庫管理的方式。

flowchart TB
    subgraph 管理階段["📋 管理階段"]
        Admin["管理員"] -->|1.按下「產生 Key」| Dashboard["後台介面"]
        Dashboard -->|2.建立一筆記錄| DB[("資料庫<br>─────<br>Key: abc123<br>期限: 2025/12/31<br>狀態: 有效")]
        Dashboard -->|3.顯示 Key| Admin
    end

    subgraph 使用階段["🔐 驗證階段"]
        Request["API 請求<br>帶著 Key: abc123"] -->|4.檢查這把 Key| DB
        DB -->|5a.Key 有效 ✅| Allow["放行,回傳資料"]
        DB -->|5b.Key 過期/刪除 ❌| Deny["拒絕,回傳錯誤"]
    end

這樣做的好處是:如果發現 Key 被外洩了,馬上進後台刪掉,那把 Key 立刻就失效了。

Key 什麼時候會失效?

兩種情況:

  1. 被刪除:你主動把這把 Key 停用了
  2. 過期了:Key 通常會設有效期限,過了就不能用

後端收到請求時,會去資料庫查這把 Key:存在嗎?過期了嗎?被刪除了嗎?都沒問題才放行。

來看看程式碼怎麼寫

打 API 的時候

用 cURL:

curl -X GET "https://api.example.com/data" \
  -H "X-API-Key: your_key_here"

用 JavaScript:

fetch('https://api.example.com/data', {
  headers: {
    'X-API-Key': 'your_key_here'
  }
})

用 Python:

import requests

headers = {'X-API-Key': 'your_key_here'}
response = requests.get('https://api.example.com/data', headers=headers)

後端驗證(Node.js 範例)

app.get('/api/data', (req, res) => {
  const apiKey = req.headers['x-api-key'];

  if (!apiKey) {
    return res.status(401).json({ error: '請提供 API Key' });
  }

  // 檢查 Key 是否有效(實際上會查資料庫)
  if (apiKey !== 'Admin123') {
    return res.status(401).json({ error: 'Key 不對喔' });
  }

  res.json({ message: '驗證成功!' });
});

X-API-KeyAuthorization 的差別

剛剛的程式碼範例都是用 X-API-Key 這個 Header,但如果你實際去串接 OpenAI、Stripe 這些服務,會發現他們要求的格式不太一樣:

# 我們剛剛教的
curl -H "X-API-Key: your_key_here"

# OpenAI 要求的
curl -H "Authorization: Bearer sk-xxxxxxxx"

這兩種寫法都可以放 API Key,那差在哪裡?什麼時候該用哪個?

X-API-Key 是自己定義的

還記得前面說的嗎?我們可以自己發明 Header 欄位。

X-API-Key 就是大家約定俗成的寫法,不是官方規定的標準。

有些服務用 X-API-Key,有些用 API-Key(不加 X-),都可以,看服務文件怎麼寫就怎麼用。

Authorization 是 HTTP 規範的標準 Header

Authorization 就不一樣了,它不是誰發明的,而是 HTTP 協定本身就定義好的標準 Header,專門用來放驗證資訊。

你可以把它想成:HTTP 在設計的時候,就預留了一個「放通行證」的欄位,這個欄位就叫 Authorization

最常見的格式是 Authorization: Bearer <你的金鑰>,很多大型服務(OpenAI、Stripe、GitHub…)都用這個格式。

實際打 OpenAI API 的程式碼

用 JavaScript:

fetch('https://api.openai.com/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk-xxxxxxxx',  // 注意這裡是 Authorization,不是 X-API-Key
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'gpt-4',
    messages: [{ role: 'user', content: '你好' }]
  })
})

用 Python:

import requests

headers = {
    'Authorization': 'Bearer sk-xxxxxxxx',
    'Content-Type': 'application/json'
}
response = requests.post('https://api.openai.com/v1/chat/completions', 
                         headers=headers, 
                         json={'model': 'gpt-4', 'messages': [{'role': 'user', 'content': '你好'}]})

那我到底該用哪個?

簡單原則:

用什麼照他們文件規定,通常是 Authorization: Bearer
用什麼兩種都可以,Authorization 比較標準,X-API-Key 比較直覺
用什麼看團隊習慣,統一就好

進階問題:Authorization 會不會「撞車」?

前面教的是用 Authorization 放 API Key,但其實這個 Header 還有另一個很常見的用途:放使用者的登入 Token

舉個例子:你做了一個網站,有會員登入功能。

使用者登入成功後,後端會發一組 Token 給他,之後使用者每次發請求,都要帶上這組 Token 來證明「我是已登入的會員」。

這組 Token 通常也是放在 Authorization: Bearer 裡面。

所以問題來了:

「使用者的登入 Token 要放 Authorization…」

「串接 OpenAI 的 API Key 也要放 Authorization…」

「這樣不就衝突了嗎?同一個欄位怎麼放兩種東西?」

答案是:完全不會衝突!

為什麼?因為這是兩個完全獨立的請求

還記得前面講的嗎?API Key 適合用在 Server 對 Server 的情境:

flowchart LR
    User["使用者<br>瀏覽器"] -->|"① 帶登入 Token"| Server["你的後端<br>Server"]
    Server -->|"② 帶 API Key"| OpenAI["OpenAI<br>API"]
    OpenAI -->|"③ 回傳結果"| Server
    Server -->|"④ 回傳給使用者"| User

這裡有兩個完全獨立的 HTTP 請求,各自有自己的 Header:

請求 ①:使用者 → 你的後端

POST /api/chat HTTP/1.1
Host: your-website.com
Authorization: Bearer eyJhbGciOiJIUzI1...  ← 使用者的登入 Token

請求 ②:你的後端 → OpenAI

POST /v1/chat/completions HTTP/1.1
Host: api.openai.com
Authorization: Bearer sk-xxxxxxxx  ← OpenAI 的 API Key

看到了嗎?這是兩封完全不同的 HTTP 請求

使用者的 Token 是放在「使用者 → 你」這個 HTTP 請求裡,OpenAI 的 API Key 是放在「你 → OpenAI」這個 HTTP 請求裡。

兩個請求各走各的路,根本不會打架。

用前面的便利商店例子來想:你拿會員卡給店員(你的身份),店員再用 POS 機登入總公司(店員的身份)。你的會員卡跟店員的帳號是兩回事,不會互相干擾。

完整的後端程式碼長這樣

把前面學的串起來,看看你的後端(Node.js)會怎麼處理這兩個請求:

app.post('/api/chat', async (req, res) => {
  // ===== 請求 ①:驗證「使用者」是誰 =====
  const userToken = req.headers['authorization'];  // 使用者的登入 Token
  const user = verifyUserToken(userToken);
  
  if (!user) {
    return res.status(401).json({ error: '請先登入' });
  }

  // ===== 請求 ②:用「你的 API Key」呼叫 OpenAI =====
  // 注意:這個 Key 存在環境變數,不會暴露給前端
  const response = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,  // OpenAI 的 Key
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ 
      model: 'gpt-4',
      messages: [{ role: 'user', content: req.body.message }]
    })
  });

  // ===== 把結果回傳給使用者 =====
  const data = await response.json();
  res.json(data);
});

這段程式碼完美呼應了前面講的幾個重點:

  1. API Key 放在後端process.env.OPENAI_API_KEY 是環境變數,前端看不到
  2. Server 對 Server:是你的伺服器去呼叫 OpenAI,不是使用者的瀏覽器
  3. 兩個請求分開處理:使用者的 Token 和 OpenAI 的 Key 各管各的

安全小提醒

幾個重點,幫你避免踩雷:

  1. Key 只放伺服器端,前端絕對不能出現
  2. 用環境變數存 Key,不要直接寫在程式碼裡
  3. 記得設過期時間,定期換新的 Key
  4. 搭配 IP 白名單,只讓特定的伺服器連進來
  5. 一定要用 HTTPS,不然 Key 在傳輸過程中可能被攔截

總結

來複習一下重點:

內容一把用來驗證身份的鑰匙
內容HTTP Header 裡面,格式是 X-API-Key: 你的Key
內容Server 對 Server ✅,Client 對 Server ❌
內容簡單的寫死,正式的用資料庫
內容Key 絕對不能暴露在前端!

API Key 是最基本的驗證方式,搞懂這個之後,你就可以繼續學更進階的東西,像是 OAuth、JWT 等等。

希望這篇有幫助到你,有問題歡迎留言!