はじめに
前回は JWT (JSON Web Token) による認証を導入し、トークンを用いたセキュアな API アクセス方法を紹介しました。
今回は API Key を用いたシンプルな認証方法を実装します。
API Key 方式は、特定のクライアントだけに鍵を配布し、それをヘッダーなどに含めることでアクセスを制限する仕組みです。
1. API Key 認証の概要
- API Key はランダムに生成された文字列を使い、クライアントがリクエスト時に付与します。
- Hono (Cloudflare Workers) では、ミドルウェアを利用して API Key の検証を行い、正しくない場合は 401 (Unauthorized) を返却します。
mermaid 図:API Key 認証フロー
2. 環境変数 (.env) の導入
API Key をソースコード内に直書きすると、漏洩リスクが高まります。
.dev.vars
ファイルにキーを記述し、公開リポジトリには含めない運用にしましょう。
touch .dev.vars
.env
ファイルの例:
API_KEY=my-very-secret-api-key
PORT=3000
.gitignore
に .dev.vars
を追加し、リポジトリに含めないようにします。
3. ディレクトリ構成
前回までのチュートリアルと同様に、認証用のロジックは middlewares/
に配置すると整理しやすいです。
my-hono-crud/
├─ .dev.vars
├─ package.json
├─ tsconfig.json
├─ src/
│ ├─ index.ts // エントリーポイント
│ ├─ middlewares/
│ │ └─ apiKeyAuth.ts // API Key検証ミドルウェア
│ └─ users/
│ └─ index.ts
└─ ...
4. コード例
4-1. src/middlewares/apiKeyAuth.ts
API Key を検証するミドルウェアを作成します。以下の例では、Authorization
ヘッダーに Bearer <YOUR_API_KEY>
の形式でキーが渡される想定です。
import { Context, Next } from 'hono'
import 'dotenv/config'
export const apiKeyAuthMiddleware = async (c: Context, next: Next) => {
const authHeader = c.req.header('Authorization') // "Bearer xxx" が入る想定
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return c.json({ error: 'No or invalid API Key header' }, 401)
}
const apiKey = authHeader.replace('Bearer ', '')
// 環境変数のAPI_KEYと一致するか確認
if (apiKey !== c.env.API_KEY) {
return c.json({ error: 'Invalid API Key' }, 401)
}
// OK なら次へ
await next()
}
4-2. src/users/index.ts
ユーザー CRUD のエンドポイントへアクセスする前に、上記の apiKeyAuthMiddleware
を適用します。
import { Hono } from 'hono'
import { apiKeyAuthMiddleware } from '../middlewares/apiKeyAuth'
type User = { id: number; name: string }
let users: User[] = []
const userApp = new Hono()
// すべてのエンドポイントに対してAPI Key認証を要求
userApp.use('*', apiKeyAuthMiddleware)
// Create: ユーザー作成 (POST /users)
userApp.post('/', async (c) => {
const { name } = await c.req.json()
const newUser: User = {
id: Date.now(),
name
}
users.push(newUser)
return c.json({ message: 'User created', user: newUser })
})
// Read: 全ユーザー取得 (GET /users)
userApp.get('/', (c) => {
return c.json(users)
})
// Read: 特定ユーザー取得 (GET /users/:id)
userApp.get('/:id', (c) => {
const userId = parseInt(c.req.param('id'))
const user = users.find((u) => u.id === userId)
if (!user) {
return c.json({ error: 'User not found' }, 404)
}
return c.json(user)
})
// Update: ユーザー更新 (PATCH /users/:id)
userApp.patch('/:id', async (c) => {
const userId = parseInt(c.req.param('id'))
const { name } = await c.req.json()
const userIndex = users.findIndex((u) => u.id === userId)
if (userIndex === -1) {
return c.json({ error: 'User not found' }, 404)
}
users[userIndex].name = name
return c.json({ message: 'User updated', user: users[userIndex] })
})
// Delete: ユーザー削除 (DELETE /users/:id)
userApp.delete('/:id', (c) => {
const userId = parseInt(c.req.param('id'))
const userIndex = users.findIndex((u) => u.id === userId)
if (userIndex === -1) {
return c.json({ error: 'User not found' }, 404)
}
const deletedUser = users.splice(userIndex, 1)[0]
return c.json({ message: 'User deleted', user: deletedUser })
})
export default userApp
4-3. src/index.ts
メインのエントリーポイントで userApp
を呼び出します。
import { Hono } from 'hono'
import userApp from './users/index'
const app = new Hono()
// "/users" 以下へのルートを委譲
app.route('/users', userApp)
export default app
5. 動作確認
ローカルで npm start
(あるいは wrangler dev
) などを実行し、以下のコマンドでテストしてみましょう。
5-1. ユーザー作成 (POST /users)
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer my-very-secret-api-key" \
-d '{"name":"Alice"}' \
http://localhost:8787/users
-
-H "Authorization: Bearer <API_KEY>"
の形で API Key を指定します。 -
.env
のAPI_KEY=my-very-secret-api-key
と一致しない場合は、401 Unauthorized
が返されます。
5-2. ユーザー取得 (GET /users, GET /users/:id)
curl -X GET \
-H "Authorization: Bearer my-very-secret-api-key" \
http://localhost:8787/users
その他、PATCH / DELETE なども同様に Authorization
ヘッダーを付与することでアクセス可能です。
6. まとめと応用
- API Key 方式 はシンプルで実装しやすいですが、鍵の漏洩リスクに注意が必要です。
- 環境変数 (.env) によるキー管理を行い、ソースコードに直書きしないようにしましょう。
- 鍵の定期的なローテーション や、使用期限を設ける運用なども検討するとより安全です。
- 本番運用では、HTTPS (SSL/TLS) 化した環境で運用し、通信経路を暗号化しておきましょう。
これで API Key 認証 を導入した Hono アプリのチュートリアルは完了です。
今までに紹介した JWT 認証 と API Key 認証 は用途によって使い分けることが多いので、運用シーンに応じて最適な方法を選んでみてください。