KMIoT-API/BFF ご利用ガイド(エンドユーザ向け) PKCE + BFF

このドキュメントは 開発者が AWS Cognito(以下 Cognito)を利用して、KMIoT-API を利用するための手順を記載します。KMIoT-API のエンドポイントの詳細は Swagger ドキュメントをご参照ください。

対象: KMIoT が提供する BFF(Backend for Frontend) を利用して SPA/フロントから KMIoT-API を呼びたい開発者/範囲: M2M / LLM 連携は扱いません。PKCE + BFF 前提で、フロント実装に必要な最小事項を説明します。

PKCE + BFF シーケンス

本サービスでは以下のようなシーケンスにて動作します。

Cognitoシーケンス図
Cognito PKCE + BFF

1. サポートから受け取る情報(初期セットアップ)

契約・テナントごとにサポートから以下が案内されます。

標準ではユーザのフロントから直接 KMIoT-API へのアクセス不可となりますので、別途 KMIoT-API のカスタマイズが必要です。
(※本アクセスが必要な環境をご利用になる場合はサポートへご連絡ください。)

重要: フロントは トークンを保持しません。BFF がサーバ側セッションで管理します。

2. 導入ステップ(フロント実装)

2.0 クライアント設定の自己記述(GET /auth/client-config

SPA はまず /auth/client-config を呼び、ログインパラメータ名CSRF 設定リフレッシュ/ログアウトのエンドポイント等を動的に取得できます。

// 例: 起動時に一度だけ読み込む
const conf = await fetch('https://<bff>.kmiot-app.net/auth/client-config', { credentials: 'include' }).then(r => r.json());
// conf 例:
// {
//   "loginParam": "next",
//   "aliases": ["returnTo"],
//   "nextRules": "relative-only",
//   "csrfHeader": "X-CSRF-Token",
//   "csrfEndpoint": "/csrf",
//   "refreshEndpoint": "/auth/refresh",
//   "logoutEndpoint": "/auth/logout",
//   "issuer": "https://tenant.auth.ap-northeast-1.amazoncognito.com",
//   "apiPrefix": "/api/kmiot",
//   "version": "v1"
// }

規約: ログイン遷移クエリは next(互換: returnTo)で、相対パスのみ許可します(http(s)://// は不可)。

2.1 ログイン導線(Hosted UI へ)

<a href="https://<bff>.kmiot-app.net/auth/login?next=%2Fapp%2Fhome">ログイン</a>

Hosted UI でサインイン後、BFF の /auth/callback を経由して next に自動遷移します(ポップアップの場合は自動クローズ)。

2.2 API 呼び出しは BFF 経由

// 参照系(例: センサー一覧)
const res = await fetch('https://<bff>.kmiot-app.net/api/kmiot/v2/sensorinfo/th', {
  method: 'GET',
  credentials: 'include', // ← 重要(sid Cookie を送る)
});
if (res.status === 401) {
  location.href = 'https://<bff>.kmiot-app.net/auth/login?next=' + encodeURIComponent(location.pathname);
}
const data = await res.json();
// 参照系(例: グラフデータ)
const res2 = await fetch('https://<bff>.kmiot-app.net/api/kmiot/v2/graphdata', {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    kind: 'th',
    from: '2025-09-20T00:00:00Z',
    to:   '2025-09-21T00:00:00Z',
  }),
});
const data2 = await res2.json();

2.3 書き込み系は CSRF を付与

// 1) まず CSRF トークンを取得(Cookie + JSON)
const t = await fetch('https://<bff>.kmiot-app.net/csrf', { credentials: 'include' }).then(r => r.json());
// 2) 書き込み時にヘッダへ付与
await fetch('https://<bff>.kmiot-app.net/api/kmiot/v2/alertsetting', {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': t.csrfToken },
  body: JSON.stringify({ sensorkind: 'door', limit_open: '120', limit_close: '0' }),
});

2.4 期限切れ時のリフレッシュ

async function fetchWithRefresh(input, init = {}) {
  const res = await fetch(input, { ...init, credentials: 'include' });
  if (res.status !== 401) return res;
  const r = await fetch('https://<bff>.kmiot-app.net/auth/refresh', { method: 'POST', credentials: 'include' });
  if (r.ok) return fetch(input, { ...init, credentials: 'include' });
  location.href = 'https://<bff>.kmiot-app.net/auth/login?next=' + encodeURIComponent(location.pathname + location.search + location.hash);
}

3. 代表的な BFF 経由エンドポイント

4. エラーと対処

HTTPJSON 例対処
401{"error":"no_session"} / {"error":"invalid_token","detail":"jwt expired"}まず /auth/refresh → 単回リトライ。ダメなら /auth/login
403{"error":"csrf_required"}/csrf を取得し直して再送
403{"error":"insufficient_scope"}スコープ不足。サポートへ連絡
404{"error":"sensor_not_found"}パラメータ(kind 等)確認
5xx{"error":"..._failed"}リトライ。継続時はサポートへ連絡

5. セキュリティと運用のポイント

6. よくある質問(FAQ)

7. BFF利用規約(開発者向け)

KMIoT 提供BFFを通じて KMIoT-API を利用する際の必須ルールです。

7.1 セッション管理ポリシー

7.2 CSRF の扱い

7.3 リフレッシュの扱い

7.4 エラーモデル

7.5 利用規約(BFF 規約相当)

7.6 運用情報

8. 連絡先

技術サポート/許可オリジン登録・スコープ追加の依頼は、契約書記載の サポート窓口 へご連絡ください。

付録:エンドユーザが独自BFFを開発する場合

本付録は PKCE + BFF の一般パターンを前提に、KMIoT 固有の前提(Issuer/スコープ/パス等)を明示します。公式運用は「KMIoT 提供 BFF の利用」を推奨します。

A. 前提・制約(KMIoT 固有)

B. サポートが必ず提供すべき情報(独自 BFF 開発時)

{
  "apiBase": "https://api.kmiot-app.net",
  "version": "v2",
  "authDomain": "https://<tenant>.auth.ap-northeast-1.amazoncognito.com",
  "clientId": "<PUBLIC_CLIENT_ID>",
  "scopes": ["openid","profile","email","myapi/api.read"],
  "token": { "accessTtlSec": 3600, "refreshTtlDays": 30, "clockSkewSec": 60 },
  "callbacks": {
    "login": "https://bff.example.com/auth/callback",
    "logout": "https://bff.example.com/auth/logout"
  },
  "oidcDiscovery": "https://<tenant>.auth.ap-northeast-1.amazoncognito.com/.well-known/openid-configuration",
  "rateLimit": { "perMinute": 600, "burst": 200 },
  "contact": { "support": "support@kmiot-app.net" }
}

C. 実装チェックリスト(独自BFF)

  1. PKCE 実装/auth/login(state, code_challenge=S256)→ /auth/callback(server-side /oauth2/token)。
  2. セッション/Cookie:AT/RT はサーバ保持、ブラウザは sid のみ。
    • 同一サイト… SameSite=Lax/Strict でも可。
    • クロスサイト… SameSite=None; Secure + CORS + credentials:"include"
  3. BFF→API プロキシAuthorization: Bearer <AT> を付与して /v2/* を呼ぶ。
  4. CSRF 対策(書込系):ダブルサブミット(/csrfX-CSRF-Token)。
  5. リフレッシュ/401 リトライ:期限前更新、401 で一度だけ再取得→単回リトライ。
  6. ログアウト:サーバセッション破棄+ Cognito Logout URL。
  7. CORS 設定:必要最小、Access-Control-Allow-Credentials: true
  8. 運用:HTTPS/HSTS、レート制御、入力検証、監査ログ、NTP。

D. フロント実装の差分(提供BFF → 独自BFF)

呼び先のベース URL だけが変わることを目標にします。

https://<bff>.kmiot-app.net/api/kmiot/...  →  https://<your-bff.example.com>/api/kmiot/...

どちらでも credentials:"include" は必須(Cookie 送信)。

E. 受け入れテスト(UAT)観点

F. サポートへの申請テンプレ(独自BFF 稼働前)