Table of Contents
概要
本APIは、Bearer認証(JWT)を採用しています。すべてのAPIリクエストには、有効なJWTトークンを含むAuthorizationヘッダーが必要です。
認証方式
Bearer認証(JWT)
ヘッダー形式:
Authorization: Bearer <JWT_TOKEN>
例:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTYxNjIzOTAyMiwiZXhwIjoxNjE2MjQyNjIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JWTトークンの構造
JWTトークンは、以下の3つの部分で構成されています:
<Header>.<Payload>.<Signature>
1. Header(ヘッダー)
トークンのタイプと署名アルゴリズムを含みます。
{
"alg": "HS256",
"typ": "JWT"
}
- alg:署名アルゴリズム(HS256、RS256等)
- typ:トークンタイプ(常に”JWT”)
2. Payload(ペイロード)
ユーザー情報とクレームを含みます。
{
"sub": "user_123", // Subject: ユーザーID
"role": "admin", // Role: ユーザーロール(admin/user/device)
"iat": 1616239022, // Issued At: トークン発行時刻(UNIXタイムスタンプ)
"exp": 1616242622, // Expiration: トークン有効期限(UNIXタイムスタンプ)
"device_id": "A1B2C3D4..." // デバイスID(デバイス認証の場合のみ)
}
必須クレーム:
sub(subject):ユーザーまたはデバイスの一意な識別子role:ユーザーのロールadmin:管理者(すべてのAPI実行可能)user:一般ユーザー(通知閲覧のみ)device:デバイス(デバイス登録・更新のみ)
iat(issued at):トークン発行時刻exp(expiration):トークン有効期限
オプションクレーム:
device_id:デバイスID(デバイス認証時)session_f:セッションID(デバイス認証時)
3. Signature(署名)
改ざん防止のための署名です。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
SECRET_KEY
)
トークンの生成方法
環境変数の設定
JWTの署名に使用する秘密鍵を環境変数に設定します:
# .env ファイル
JWT_SECRET_KEY=your-256-bit-secret-key-here
JWT_ALGORITHM=HS256
JWT_EXPIRATION_HOURS=1
⚠️ 重要:
JWT_SECRET_KEYは最低256ビット(32文字以上)の強力なランダム文字列を使用してください- 本番環境では絶対にコードにハードコードせず、環境変数または秘密管理サービスを使用してください
PHP(Laravel)での生成例
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class JWTService
{
private string $secretKey;
private string $algorithm;
private int $expirationHours;
public function __construct()
{
$this->secretKey = env('JWT_SECRET_KEY');
$this->algorithm = env('JWT_ALGORITHM', 'HS256');
$this->expirationHours = env('JWT_EXPIRATION_HOURS', 1);
}
public function generateAdminToken(string $userId, string $role = 'admin'): string
{
$issuedAt = time();
$expiration = $issuedAt + ($this->expirationHours * 3600);
$payload = [
'sub' => $userId,
'role' => $role,
'iat' => $issuedAt,
'exp' => $expiration,
];
return JWT::encode($payload, $this->secretKey, $this->algorithm);
}
public function generateDeviceToken(string $sessionF, string $deviceId): string
{
$issuedAt = time();
$expiration = $issuedAt + (24 * 3600);
$payload = [
'sub' => $sessionF,
'role' => 'device',
'device_id' => $deviceId,
'session_f' => $sessionF,
'iat' => $issuedAt,
'exp' => $expiration,
];
return JWT::encode($payload, $this->secretKey, $this->algorithm);
}
public function validateToken(string $token): object
{
try {
return JWT::decode($token, new Key($this->secretKey, $this->algorithm));
} catch (\Exception $e) {
throw new \Exception('Invalid token: ' . $e->getMessage());
}
}
}
Node.js(Express)での生成例
const jwt = require("jsonwebtoken");
class JWTService {
constructor() {
this.secretKey = process.env.JWT_SECRET_KEY;
this.algorithm = process.env.JWT_ALGORITHM || "HS256";
this.expirationHours = parseInt(process.env.JWT_EXPIRATION_HOURS || "1");
}
generateAdminToken(userId, role = "admin") {
const payload = { sub: userId, role: role };
return jwt.sign(payload, this.secretKey, {
algorithm: this.algorithm,
expiresIn: `${this.expirationHours}h`,
});
}
generateDeviceToken(sessionF, deviceId) {
const payload = {
sub: sessionF,
role: "device",
device_id: deviceId,
session_f: sessionF,
};
return jwt.sign(payload, this.secretKey, {
algorithm: this.algorithm,
expiresIn: "24h",
});
}
validateToken(token) {
try {
return jwt.verify(token, this.secretKey, { algorithms: [this.algorithm] });
} catch (error) {
throw new Error(`Invalid token: ${error.message}`);
}
}
}
module.exports = JWTService;
トークンの有効期限
| トークンタイプ | 有効期限 | 用途 |
|---|---|---|
| 管理者トークン | 1時間 | 管理画面API操作 |
| デバイストークン | 24時間 | デバイス登録・更新 |
| リフレッシュトークン | 30日 | アクセストークンの再発行(オプション) |
セキュリティベストプラクティス
1. 秘密鍵の管理
- ✅ 環境変数または秘密管理サービス(AWS Secrets Manager、HashiCorp Vault等)で管理
- ✅ 最低256ビット(32文字以上)の強力なランダム文字列を使用
- ❌ コードにハードコードしない
- ❌ GitHubなどのバージョン管理システムにコミットしない
2. トークンの保管(クライアント側)
モバイルアプリ(iOS/Android):
- ✅ Keychain(iOS)またはKeyStore(Android)を使用
- ❌ SharedPreferencesやUserDefaultsに平文保存しない
Webアプリ:
- ✅ HttpOnly Cookie(XSS攻撃対策)
- ⚠️ LocalStorage使用時はXSS対策を徹底
3. HTTPS必須
- ✅ 本番環境では必ずHTTPSを使用
- ✅ HSTSヘッダーを設定
4. トークンのローテーション
- ✅ 定期的にトークンを再発行
- ✅ パスワード変更時は既存トークンを無効化
- ✅ 疑わしいアクティビティ検出時は即座に無効化
5. レート制限
- ✅ 認証エンドポイントにレート制限を実装
- ✅ 失敗回数に応じてアカウントを一時ロック
トラブルシューティング
エラー: “Invalid token”
原因:
- トークンの有効期限切れ
- トークンの改ざん
- 秘密鍵の不一致
解決策:
- トークンの有効期限を確認(
expクレーム) - 秘密鍵が正しいか確認
- トークンの形式が正しいか確認(ヘッダー・ペイロード・署名の3部構成)
エラー: “Missing or invalid authorization header”
原因:Authorizationヘッダーが含まれていない、またはヘッダーの形式が間違っている(Bearer プレフィックスが必要)。
正しい形式: Authorization: Bearer <token>
誤った形式: Authorization: <token>
エラー: “Insufficient permissions”
原因:要求されたロールと実際のロールが一致しない。
解決策:トークンのペイロードを確認し、正しいロール(admin・user・device)が設定されているか確認してください。

コメント