この記事の要点
• Authorizationヘッダーはクライアントがサーバーに認証情報を送るHTTPヘッダー
• Basic認証はbase64エンコードだけで暗号化ではない(HTTPS必須)
• Bearer TokenがモダンなAPI認証の主流(OAuth 2.0 / JWT)
Authorization ヘッダーとは
Authorizationヘッダーは、クライアント(ブラウザやアプリ)がサーバーに対して認証情報を送信するためのHTTPヘッダーです。APIアクセスやログインが必要なリソースへのアクセス時に使用されます。
なぜ必要か: HTTPはステートレスなため、リクエストごとに「誰からのアクセスか」を証明する必要があります。Authorizationヘッダーで認証情報を送り、サーバーが検証します。
基本フォーマット
Authorization: <type> <credentials>
- type: 認証スキーム(
Basic,Bearer,Digestなど) - credentials: 認証情報(形式はスキームによって異なる)
主要な認証スキーム
| スキーム | 形式 | 用途 | セキュリティ |
|---|---|---|---|
| Basic | Basic <base64(user:pass)> | 簡易認証 | 低(HTTPS必須) |
| Bearer | Bearer <token> | OAuth 2.0 / JWT | 高 |
| Digest | Digest <parameters> | Basic認証の改良版 | 中(レガシー) |
| API Key | カスタムヘッダーで送信 | サービス間通信 | 中〜高 |
ポイント: Authorizationヘッダーは標準化されていますが、API Keyはカスタムヘッダー(例: X-API-Key)で送ることも多いです。
Basic認証
最もシンプルな認証方式です。ユーザー名とパスワードをコロンで結合し、Base64エンコードして送信します。
リクエスト例
GET /api/users HTTP/1.1
Host: api.example.com
Authorization: Basic dXNlcjpwYXNzd29yZA==
dXNlcjpwYXNzd29yZA==の中身:
echo -n "user:password" | base64
# dXNlcjpwYXNzd29yZA==
サーバー側の検証
// Node.js / Express
app.get('/api/users', (req, res) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Basic ')) {
return res.status(401).json({ error: 'Missing or invalid Authorization header' });
}
const base64Credentials = authHeader.split(' ')[1];
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [username, password] = credentials.split(':');
// 認証チェック
if (username === 'user' && password === 'password') {
res.json({ users: [...] });
} else {
res.status(401).json({ error: 'Invalid credentials' });
}
});
レスポンス(認証失敗時)
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="API Access"
ブラウザはWWW-Authenticateヘッダーを受け取ると、ログインダイアログを表示します。
注意: Basic認証はBase64エンコードだけで暗号化ではありません。HTTPS通信でない限り、パスワードが平文で送信されます。本番環境では必ずHTTPSを使用してください。
Basic認証の用途
- 開発環境の簡易保護: Stagingサイトへのアクセス制限
- 内部API: 信頼できるネットワーク内での軽量な認証
- 管理画面の初期認証: アプリケーションレベル認証と併用
Basic認証の欠点
- パスワードが毎回送信される(漏洩リスク)
- ログアウト機能がない(ブラウザがキャッシュ)
- 細かい権限制御ができない
Bearer Token(Bearer認証)
OAuth 2.0やJWTで使用される、現代のAPI認証の主流です。トークン(証明書)を発行し、リクエストごとに送信します。
リクエスト例
GET /api/users HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyM30.abcdef
OAuth 2.0 フロー
- クライアントが認証サーバーにログイン
- アクセストークンを取得
POST /oauth/token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=user&password=pass&client_id=app123&client_secret=secret
レスポンス:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def456..."
}
- APIリクエストにトークンを付与
GET /api/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
JWT(JSON Web Token)
JWTはBearer Tokenの実装の一つで、トークン自体に情報を含めます。
構造:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ← Header (Base64)
.
eyJ1c2VySWQiOjEyMywibmFtZSI6IkpvaG4ifQ ← Payload (Base64)
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ← Signature
Payloadの中身:
{
"userId": 123,
"name": "John",
"exp": 1714521600
}
サーバー側の検証(JWT)
const jwt = require('jsonwebtoken');
const SECRET_KEY = process.env.JWT_SECRET;
app.get('/api/profile', (req, res) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing token' });
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, SECRET_KEY);
// decoded = { userId: 123, name: "John", exp: 1714521600 }
res.json({ user: decoded });
} catch (err) {
res.status(401).json({ error: 'Invalid or expired token' });
}
});
ポイント: JWTはサーバー側でセッション管理が不要(ステートレス)です。トークン自体に情報が含まれ、署名で改ざんを検知できます。
Bearer Token の用途
- モダンなWebアプリケーション: React/Vue.js等のSPA
- モバイルアプリ: iOS/Androidアプリのバックエンド認証
- マイクロサービス: サービス間認証
- サードパーティAPI連携: OAuth 2.0でアクセス許可
Bearer Token のベストプラクティス
- 有効期限を短く: 15分〜1時間
- Refresh Token で更新: 長期間のセッションを維持
- HTTPS必須: トークン漏洩を防ぐ
- トークンをlocalStorageに保存しない: XSS攻撃のリスク
// ✗ 悪い例: localStorageに保存
localStorage.setItem('token', token);
// ✓ 良い例: HttpOnly Cookieに保存(サーバーがSet-Cookie)
res.cookie('accessToken', token, {
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 3600000
});
API Key
サービス間通信や、サードパーティ開発者向けAPIでよく使われます。
送信方法
1. Authorizationヘッダー(非標準)
GET /api/data HTTP/1.1
Authorization: ApiKey sk_live_abc123xyz
2. カスタムヘッダー(一般的)
GET /api/data HTTP/1.1
X-API-Key: sk_live_abc123xyz
3. クエリパラメータ(非推奨)
GET /api/data?api_key=sk_live_abc123xyz HTTP/1.1
問題点: URLはログに残りやすく、ブラウザ履歴やアクセスログに記録される。
注意: API Keyをクエリパラメータで送信すると、サーバーログやブラウザ履歴に残るリスクがあります。ヘッダーで送信しましょう。
サーバー側の検証
app.get('/api/data', (req, res) => {
const apiKey = req.headers['x-api-key'];
if (!apiKey) {
return res.status(401).json({ error: 'API key required' });
}
// データベースで検証
const client = apiKeys.find(k => k.key === apiKey);
if (!client || !client.active) {
return res.status(403).json({ error: 'Invalid or inactive API key' });
}
// レート制限チェック
if (client.requestCount > client.limit) {
return res.status(429).json({ error: 'Rate limit exceeded' });
}
res.json({ data: [...] });
});
API Key の管理
| 項目 | 推奨方法 |
|---|---|
| 生成 | 暗号学的に安全なランダム文字列(32文字以上) |
| 保存 | ハッシュ化して保存(bcrypt/argon2) |
| ローテーション | 定期的に再発行 |
| スコープ制限 | 必要な権限のみ付与 |
| 有効期限 | 長期(1年など)だが、使用頻度が低ければ短縮 |
API Key の用途
- 外部開発者向けAPI: Stripe、OpenAI、Google Maps API
- サーバー間通信: マイクロサービス、Webhook
- CI/CDパイプライン: ビルド時のAPI呼び出し
認証方式の比較
| 方式 | セキュリティ | 実装の複雑さ | ステートレス | 用途 |
|---|---|---|---|---|
| Basic認証 | 低(HTTPS必須) | 簡単 | ✓ | 開発環境、簡易保護 |
| Bearer (JWT) | 高 | 中 | ✓ | SPA、モバイルアプリ |
| Bearer (OAuth) | 高 | 高 | △ | サードパーティ連携 |
| API Key | 中〜高 | 簡単 | ✓ | サーバー間通信 |
| Digest | 中 | 中 | ✓ | レガシー(非推奨) |
実践メモ: ユーザー向けアプリはBearer (JWT)、サーバー間通信はAPI Keyが主流です。Basic認証は開発環境の一時的な保護に留めましょう。
クライアント側の実装例
JavaScript(fetch)
// Basic認証
fetch('https://api.example.com/users', {
headers: {
'Authorization': 'Basic ' + btoa('user:password')
}
});
// Bearer Token
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
fetch('https://api.example.com/profile', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// API Key
fetch('https://api.example.com/data', {
headers: {
'X-API-Key': 'sk_live_abc123xyz'
}
});
cURL
# Basic認証
curl -u user:password https://api.example.com/users
# Bearer Token
curl -H "Authorization: Bearer eyJhbGci..." https://api.example.com/profile
# API Key
curl -H "X-API-Key: sk_live_abc123xyz" https://api.example.com/data
Axios(JavaScript)
import axios from 'axios';
// Bearer Token をグローバル設定
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
// リクエスト
const response = await axios.get('https://api.example.com/profile');
セキュリティベストプラクティス
1. HTTPS必須
全ての認証情報はHTTPS通信で送信する。
// ✗ 悪い例: HTTP
http://api.example.com
// ✓ 良い例: HTTPS
https://api.example.com
2. トークンの有効期限
{
"access_token": "...",
"expires_in": 900, // 15分
"refresh_token": "..."
}
3. レート制限
// API Keyごとにリクエスト数を制限
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 60 * 1000, // 1分
max: 60, // 60リクエスト/分
keyGenerator: (req) => req.headers['x-api-key']
});
app.use('/api/', limiter);
4. トークンの保存場所
| 保存場所 | セキュリティ | 用途 |
|---|---|---|
| HttpOnly Cookie | 高(XSS耐性) | SPA、サーバーレンダリング |
| メモリ(変数) | 高(リロードで消える) | SPA(短時間) |
| localStorage | 低(XSS脆弱) | 非推奨 |
| sessionStorage | 低(XSS脆弱) | 非推奨 |
5. スコープと権限分離
// JWTのPayload
{
"userId": 123,
"scope": ["read:users", "write:posts"],
"exp": 1714521600
}
サーバー側で必要な権限があるか確認。
if (!decoded.scope.includes('write:posts')) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
デバッグとトラブルシューティング
Chrome DevTools で確認
-
Network タブ → Headers
Authorizationヘッダーの値を確認WWW-Authenticateレスポンスを確認
-
Console で Base64 デコード
atob('dXNlcjpwYXNzd29yZA=='); // "user:password"
よくあるエラー
401 Unauthorized:
- Authorizationヘッダーが欠けている
- トークンが無効・期限切れ
- 認証情報が間違っている
403 Forbidden:
- 認証は成功したが、権限がない
- API Keyのスコープが不足
429 Too Many Requests:
- レート制限に達した
- API Keyの使用量超過
まとめ
Authorizationヘッダーは、HTTPにおける認証の基本です。Basic認証はシンプルですがHTTPS必須、Bearer Tokenはモダンなアプリケーションの標準、API Keyはサーバー間通信で便利です。用途に応じて適切な認証方式を選び、HTTPS・有効期限・レート制限などのセキュリティ対策を必ず実施しましょう。
参考リソース
- MDN - Authorization
- RFC 7617 - HTTP Basic Authentication
- RFC 6750 - OAuth 2.0 Bearer Token
- JWT.io - JSON Web Tokens
- OWASP - Authentication Cheat Sheet