API認証・セキュリティガイド
築古不動産投資シミュレーターのAPIは、企業レベルのセキュリティ要件を満たすOAuth 2.0認証を採用しています。このガイドでは、認証フローから実装まで、セキュリティのベストプラクティスを詳しく解説します。
🔐 認証システム概要
OAuth 2.0:業界標準の認証プロトコル
Multiple Providers:Google、GitHub、Microsoft対応
JWT Tokens:ステートレスなトークン管理
Refresh Tokens:長期間のセッション維持
Scope-based Access:細かい権限制御
Rate Limiting:DoS攻撃の防止
🔄 OAuth 2.0 認証フロー詳細
📋 Authorization Code Flow
最も安全な認証フローで、サーバーサイドアプリケーションに推奨されます。
1. 認証URL生成
GET https://kominka-apart-sim.vercel.app/auth/oauth/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://your-app.com/callback&
scope=read:simulations write:simulations&
state=RANDOM_STATE_STRING
2. ユーザー認証
ユーザーはプロバイダー(Google/GitHub)で認証を行います。
3. 認証コード取得
GET https://your-app.com/callback?
code=AUTHORIZATION_CODE&
state=RANDOM_STATE_STRING
4. アクセストークン交換
POST https://kominka-apart-sim.vercel.app/auth/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
redirect_uri=https://your-app.com/callback
5. トークンレスポンス
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"scope": "read:simulations write:simulations",
"user_id": "123e4567-e89b-12d3-a456-426614174000"
}
🔒 Client Credentials Flow
サーバー間通信やMCPサーバー用の認証フローです。
トークン取得
POST https://kominka-apart-sim.vercel.app/auth/oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic BASE64(client_id:client_secret)
grant_type=client_credentials&
scope=mcp:tools calculation:realtime
レスポンス
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "mcp:tools calculation:realtime"
}
🎫 JWT トークンの詳細
JWT構造
JWTは3つの部分で構成されています:
Header
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-id-2024"
}
Payload
{
"iss": "https://kominka-apart-sim.vercel.app",
"sub": "123e4567-e89b-12d3-a456-426614174000",
"aud": "kominka-api",
"exp": 1642694400,
"iat": 1642690800,
"scope": "read:simulations write:simulations",
"user_email": "user@example.com",
"user_name": "田中太郎",
"plan": "premium"
}
Signature
RS256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
private_key
)
JWT検証
受信したJWTは以下の手順で検証します:
署名検証:公開鍵を使用してRS256署名を検証
有効期限チェック:expクレームを確認
発行者確認:issクレームが正しいか確認
オーディエンス確認:audクレームが一致するか確認
🔄 トークンリフレッシュ
自動リフレッシュの実装
JavaScript実装例
class AuthManager {
constructor(clientId, clientSecret) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.accessToken = null;
this.refreshToken = null;
this.expiresAt = null;
}
async getValidToken() {
// トークンの有効期限をチェック(余裕をもって5分前)
if (this.expiresAt && Date.now()
Python実装例
import time
import requests
from datetime import datetime, timedelta
class AuthManager:
def __init__(self, client_id, client_secret):
self.client_id = client_id
self.client_secret = client_secret
self.access_token = None
self.refresh_token = None
self.expires_at = None
self.base_url = "https://kominka-apart-sim.vercel.app"
def get_valid_token(self):
# トークンの有効期限をチェック
if self.expires_at and datetime.now()
🔒 セキュリティベストプラクティス
⚠️ 重要なセキュリティ対策
1. クライアントシークレットの保護
環境変数:機密情報は環境変数で管理
サーバーサイドのみ:フロントエンドにシークレットを含めない
定期的な更新:90日ごとにシークレットをローテーション
2. トークンストレージ
HttpOnly Cookie:XSS攻撃を防ぐため
Secure Flag:HTTPS通信でのみ送信
SameSite属性:CSRF攻撃を防ぐため
3. HTTPS通信
TLS 1.2以上:暗号化通信の強制
Certificate Pinning:中間者攻撃の防止
HSTS:HTTP Strict Transport Security
4. 入力値検証
スキーマ検証:JSONスキーマによる厳格な検証
SQLインジェクション対策:パラメータ化クエリ
XSS対策:入力値のサニタイゼーション
🛡️ 高度なセキュリティ機能
🔍 異常検知とモニタリング
1. 不審なアクセスパターン検知
レート制限超過:短時間の大量リクエスト
地理的異常:通常とは異なる地域からのアクセス
デバイス異常:新しいデバイスからのアクセス
2. セキュリティヘッダー
// 推奨セキュリティヘッダー
const securityHeaders = {
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'",
'Permissions-Policy': 'geolocation=(), microphone=(), camera=()'
};
3. APIレスポンスの匿名化
// 機密情報のマスキング
{
"user_id": "123e4567-****-****-****-426614174000",
"email": "user@******.com",
"api_key": "ak_****...****",
"simulation_data": {
// 実際のデータ
}
}
🔧 実装例とコードサンプル
🚀 Complete Authentication Client
React Hooks実装
import { useState, useEffect, useContext, createContext } from 'react';
const AuthContext = createContext();
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within AuthProvider');
}
return context;
};
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [accessToken, setAccessToken] = useState(null);
useEffect(() => {
// ページ読み込み時の認証状態確認
checkAuthStatus();
}, []);
const checkAuthStatus = async () => {
try {
const response = await fetch('/api/auth/me', {
credentials: 'include' // HttpOnly cookieを送信
});
if (response.ok) {
const userData = await response.json();
setUser(userData);
setAccessToken(userData.access_token);
}
} catch (error) {
} finally {
setLoading(false);
}
};
const login = (provider = 'google') => {
const authUrl = `https://kominka-apart-sim.vercel.app/auth/oauth/authorize?` +
new URLSearchParams({
response_type: 'code',
client_id: process.env.NEXT_PUBLIC_CLIENT_ID,
redirect_uri: `${window.location.origin}/auth/callback`,
scope: 'read:simulations write:simulations',
state: generateRandomState(),
provider: provider
});
window.location.href = authUrl;
};
const logout = async () => {
try {
await fetch('/api/auth/logout', {
method: 'POST',
credentials: 'include'
});
setUser(null);
setAccessToken(null);
} catch (error) {
}
};
const apiCall = async (endpoint, options = {}) => {
const response = await fetch(`/api${endpoint}`, {
...options,
headers: {
...options.headers,
'Authorization': accessToken ? `Bearer ${accessToken}` : undefined
},
credentials: 'include'
});
if (response.status === 401) {
// 認証エラーの場合は再ログインを促す
setUser(null);
setAccessToken(null);
throw new Error('認証が必要です');
}
return response;
};
const generateRandomState = () => {
return Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
};
const value = {
user,
loading,
login,
logout,
apiCall,
isAuthenticated: !!user
};
return (
{children}
);
};
Node.js Express Middleware
const jwt = require('jsonwebtoken');
const rateLimit = require('express-rate-limit');
// JWT検証ミドルウェア
const authenticateJWT = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Authorizationヘッダーが必要です' });
}
const token = authHeader.substring(7);
try {
const decoded = jwt.verify(token, process.env.JWT_PUBLIC_KEY, {
algorithms: ['RS256'],
issuer: 'https://kominka-apart-sim.vercel.app',
audience: 'kominka-api'
});
req.user = decoded;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'トークンの有効期限が切れています' });
}
return res.status(403).json({ error: '無効なトークンです' });
}
};
// レート制限ミドルウェア
const createRateLimit = (windowMs, max, message) => {
return rateLimit({
windowMs,
max,
message: { error: message },
standardHeaders: true,
legacyHeaders: false,
handler: (req, res) => {
res.status(429).json({
error: 'レート制限に達しました',
retryAfter: Math.ceil(windowMs / 1000)
});
}
});
};
// API用レート制限
const apiRateLimit = createRateLimit(
60 * 60 * 1000, // 1時間
1000, // 1000リクエスト
'API制限に達しました。1時間後に再試行してください。'
);
// 計算API用レート制限
const calculationRateLimit = createRateLimit(
60 * 60 * 1000, // 1時間
500, // 500リクエスト
'計算API制限に達しました。1時間後に再試行してください。'
);
module.exports = {
authenticateJWT,
apiRateLimit,
calculationRateLimit
};
🔍 セキュリティ監査とコンプライアンス
🏆 セキュリティ認証
SOC 2 Type II:セキュリティ統制の監査済み
ISO 27001:情報セキュリティ管理システム
GDPR準拠:EU一般データ保護規則
個人情報保護法:日本の個人情報保護法準拠
セキュリティ監査ログ
// セキュリティイベントの記録
{
"timestamp": "2024-01-17T10:30:00Z",
"event_type": "authentication_success",
"user_id": "123e4567-e89b-12d3-a456-426614174000",
"ip_address": "192.168.1.100",
"user_agent": "Mozilla/5.0...",
"location": {
"country": "Japan",
"city": "Tokyo"
},
"risk_score": 0.1,
"additional_data": {
"provider": "google",
"session_duration": 3600
}
}
🔗 関連リンク
MCP Server完全セットアップガイド
エンドポイント詳細リファレンス
API完全ガイド
OAuth 2.0 仕様
JWT.io - JWT デバッガー