Developer Documentation

クライアント作成からデプロイまで

デベロッパーポータルで認証情報を発行し、API ドキュメントでエンドポイントを確認し、サンプルアプリで実装を検証したうえで、準備ができたら Vercel にデプロイします。

1. OAuth クライアントを作成する

デベロッパーポータルのダッシュボードからアプリケーションを作成し、発行された Client ID と Client Secret を保存します。必要なリダイレクト URI、CORS オリジン、スコープを設定してください。

2. API の使い方を確認する

Swagger の API ドキュメントでエンドポイント、リクエストスキーマ、サンプル payload を確認します。まずは認証方式と、利用するリソースに必要なリクエスト形式を把握してください。

3. サンプルアプリで試す

サンプルリポジトリには、連携フローを一通り確認できる実装例があります。環境変数、コールバック URL、トークン処理の確認に最も手早く使えます。

サンプルリポジトリを見る

4. Vercel にデプロイする

ローカルで動作確認できたら Vercel にデプロイします。本番環境の OAuth フローが成立するよう、デベロッパーポータル側のリダイレクト URI も本番 URL に更新してください。

おすすめの進め方

  1. 1. デベロッパーポータルでクライアントを作成し、Secret を安全に保管する。
  2. 2. ローカル用と本番用のコールバック URL を先に登録する。
  3. 3. API ドキュメントで必要なヘッダーと payload を確認する。
  4. 4. サンプルアプリでログインフロー全体をローカル検証する。
  5. 5. Vercel にデプロイし、本番設定をポータル側で更新する。

運用上の注意

Client Secret はサーバー側で扱う秘密情報です。ブラウザ向けコードや公開リポジトリに含めないでください。

このポータルの各設定項目に関する技術的なリファレンスです。

OAuth2 リファレンス

Authorization Code フロー

サーバーサイドアプリケーションおよびSPAに推奨されるフローです。

  1. 1必要なクエリパラメータを付けてユーザーを認可エンドポイントにリダイレクトする。
  2. 2ユーザーが認証を行い、リクエストしたスコープを承認する。
  3. 3プロバイダーが ?code= を含む redirect_uri にリダイレクトで戻す。
  4. 4サーバーがトークンエンドポイントにコードをPOSTしてトークンを受け取る。
  5. 5保護されたAPIを呼ぶ際、Authorization: Bearer … ヘッダーにアクセストークンを付ける。
  6. 6アクセストークンの有効期限が切れたら、リフレッシュトークンで静かに更新する。

グラントタイプ

authorization_codeRecommended

標準的なサーバーサイドまたはPKCEフロー。ユーザーがプロバイダーで認証し、サーバーが返ってきたコードをトークンと交換します。ほぼすべてのアプリケーションに推奨です。

refresh_tokenCommon

ユーザーに再度ログインを求めずにアクセストークンを更新できます。初回の認可リクエスト時に offline_access スコープが必要です。

client_credentialsComing soon

ユーザー操作なしのマシン間認証(M2M)。サーバーが自身の認証情報をトークンエンドポイントに直接送信します。(近日公開予定)

レスポンスタイプ

codeRecommended

リダイレクトURLに認可コードを返します。authorization_code グラントと必ずセットで使います。推奨オプションです。

code id_tokenAdvanced

リダイレクトに認可コードとIDトークンの両方を返します。サーバーでコード交換する前にユーザー情報を検証したい場合に便利です。

トークンエンドポイント認証方法

client_secret_basicRecommended

client_id と client_secret を HTTP Basic Auth ヘッダー(Base64エンコード)で送信します。最も広くサポートされている推奨のデフォルト方式です。

client_secret_postAlternative

ヘッダーではなくPOSTボディに client_id と client_secret フィールドとして送信します。Basic Auth に対応していないサーバーで使います。

none (PKCE)Public clients

クライアントシークレット不要。代わりにPKCE(Proof Key for Code Exchange)を使います。シークレットを安全に保管できないSPAやモバイルアプリ向けです。

トークン交換:コード → トークン

認可コードを受け取ったあと、サーバーからトークンエンドポイントにPOSTします。

リクエスト

POST /oauth2/token HTTP/1.1
Host: auth.bravefrontierheroes.com
Authorization: Basic base64(CLIENT_ID:CLIENT_SECRET)
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTH_CODE_HERE
&redirect_uri=https://yourapp.com/callback

レスポンス

{
  "access_token": "eyJhbGciOiJSUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "ory_rt_abc123...",
  "scope": "openid profile email offline_access",
  "id_token": "eyJhbGciOiJSUzI1NiJ9..."
}

リフレッシュ:アクセストークンの更新

保存しておいたリフレッシュトークンでユーザー操作なしに新しいアクセストークンを取得します。

リクエスト

POST /oauth2/token HTTP/1.1
Host: auth.bravefrontierheroes.com
Authorization: Basic base64(CLIENT_ID:CLIENT_SECRET)
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=ory_rt_abc123...

レスポンス

{
  "access_token": "eyJhbGciOiJSUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "ory_rt_xyz789...",
  "scope": "openid profile email offline_access"
}

保護されたAPIの呼び出し

保護されたエンドポイントへのリクエストには必ずアクセストークンをBearerトークンとして含めます。

リクエスト

GET /v1/some-protected-resource HTTP/1.1
Host: api.bravefrontierheroes.com
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...

レスポンス

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": { ... }
}

リフレッシュトークンでユーザーを継続認証する方法。

ログイン状態の維持

デフォルトではアクセストークンの有効期限は1時間です。ユーザーに再ログインを求めずに自動的に再認証するには、refresh_token グラントと offline_access スコープを使用するようにクライアントを設定します。

クライアント登録の要件

  • グラントタイプに authorization_code と refresh_token の両方が含まれていること。
  • スコープに offline_access が含まれていること。

Step 1 — 認可リクエスト時に offline_access を追加する

ユーザーを認可エンドポイントにリダイレクトする際、scope パラメータに offline_access を追加します。これにより認可サーバーはアクセストークンと同時にリフレッシュトークンを発行します。

# Redirect the user to:
https://auth.bravefrontierheroes.com/oauth2/auth
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.com/callback
  &scope=openid+profile+offline_access
  &state=RANDOM_STATE

Step 2 — トークンレスポンスの refresh_token を保存する

認可コード交換後、トークンエンドポイントのレスポンスに refresh_token フィールドが含まれます。サーバー側で安全に保管し、ブラウザには絶対に公開しないでください。

レスポンス

{
  "access_token": "eyJhbGciOiJSUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "ory_rt_abc123...",
  "scope": "openid profile email offline_access",
  "id_token": "eyJhbGciOiJSUzI1NiJ9..."
}

Step 3 — 有効期限切れ時にアクセストークンを更新する

アクセストークンが期限切れになった場合(または 401 レスポンスを受け取った場合)、保存しておいたリフレッシュトークンをトークンエンドポイントにPOSTして新しいアクセストークンを無操作で取得します。

リクエスト

POST /oauth2/token HTTP/1.1
Host: auth.bravefrontierheroes.com
Authorization: Basic base64(CLIENT_ID:CLIENT_SECRET)
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=ory_rt_abc123...

レスポンス

{
  "access_token": "eyJhbGciOiJSUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "ory_rt_xyz789...",
  "scope": "openid profile email offline_access"
}

セキュリティ上の注意

リフレッシュトークンは長期有効な認証情報です。サーバーサイドのセッションやデータベースに暗号化して保存してください。localStorage・JavaScriptからアクセス可能なCookie・ソースコードリポジトリには絶対に保存しないでください。

以下のプロンプトをClaudeやChatGPTに貼り付けると、連携の骨格を素早く生成できます。

AIスキャフォールディングプロンプト

Next.js フルスタックアプリ

サーバーサイドセッションとhttpOnlyクッキーを使ったAuthorization Codeフロー。

BFH OAuth2 プロバイダーと連携する Next.js 16 App Router アプリケーションを作成してください。

技術スタック: TypeScript、Tailwind CSS、iron-session(httpOnlyクッキーセッション)

OAuth2 設定:
- 認可エンドポイント: https://auth.bravefrontierheroes.com/oauth2/auth
- トークンエンドポイント: https://auth.bravefrontierheroes.com/oauth2/token
- Client ID: YOUR_CLIENT_ID
- Client Secret: YOUR_CLIENT_SECRET(サーバーサイドのみ、ブラウザに公開しないこと)
- リダイレクトURI: http://localhost:3000/callback
- スコープ: openid profile email offline_access

必要なルート:
1. GET /  — 「BFHでサインイン」ボタンのログインページ
2. GET /api/auth/login  — ランダムなstateを生成してクッキーに保存し、認可エンドポイントにリダイレクト
3. GET /callback  — code+state パラメータで /api/auth/callback を呼ぶクライアントコンポーネント
4. POST /api/auth/callback  — stateを検証し、コードをトークンと交換してセッションを保存
5. GET /dashboard  — 保護ページ。未認証なら / にリダイレクト
6. GET /api/auth/logout  — セッションクッキーを削除して / にリダイレクト

セッション構造: accessToken(string)、refreshToken(string)、expiresAt(number)
自動リフレッシュ: expiresAt < Date.now() + 60000 の場合、リクエスト前にリフレッシュする。

認証後、JWTをデコードして sub と wallet_address クレームを取り出し、ダッシュボードに表示する。

Express.js API(JWT検証)

Bearerトークンを保護ルートで検証するNode.jsバックエンド。

BFH OAuth2 プロバイダーが発行した Bearer JWT アクセストークンを検証する Node.js + Express REST API を作成してください。

技術スタック: TypeScript、express、jose(JWT/JWKS)、cors、dotenv

設定(.envから読み込み):
- JWKS_URI=https://auth.bravefrontierheroes.com/.well-known/jwks.json
- EXPECTED_ISSUER=https://auth.bravefrontierheroes.com/
- EXPECTED_AUDIENCE=YOUR_CLIENT_ID
- PORT=4000

ルート:
1. GET /health  — パブリック。status "ok" と timestamp を返す
2. GET /api/profile  — 保護。JWTクレームから sub と walletAddress を返す
3. GET /api/items  — 保護。アイテムのプレースホルダー配列を返す

認証ミドルウェア(保護ルートに適用):
- "Authorization: Bearer <token>" ヘッダーからトークンを取り出す
- JWKSエンドポイントで署名を検証(jose の createRemoteJWKSet でキャッシュ)
- iss、aud、exp クレームを検証
- デコードしたペイロードを req.user に付ける
- 失敗時は 401 JSON でエラー "Unauthorized" を返す

.env.example と全ルートの curl 実行例も含めること。

React SPA(PKCE)

クライアントシークレット不要のパブリッククライアント向けフロントエンド実装。

バックエンドなしで OAuth2 PKCE フローで認証する React SPA を作成してください。

技術スタック: TypeScript、React 18、Vite、OAuthライブラリなし(PKCEを手動実装)

OAuth2 設定:
- 認可エンドポイント: https://auth.bravefrontierheroes.com/oauth2/auth
- トークンエンドポイント: https://auth.bravefrontierheroes.com/oauth2/token
- Client ID: YOUR_CLIENT_ID(パブリッククライアント — クライアントシークレットなし)
- リダイレクトURI: http://localhost:5173/callback
- スコープ: openid profile email offline_access

PKCE実装:
1. 暗号論的に安全なランダム code_verifier を生成(43〜128文字、URLセーフ)
2. code_challenge = BASE64URL(SHA-256(ASCII(code_verifier))) を導出
3. リダイレクト前に sessionStorage に verifier を保存
4. 認証URLに code_challenge と code_challenge_method=S256 を含める
5. /callback でURLからcodeを取得、sessionStorageからverifierを取得してトークンエンドポイントにPOST

トークン保存: メモリのみ(Reactのstate/context)。localStorage は使わないこと。
サイレントリフレッシュ: 有効期限の60秒前にリフレッシュトークンで更新する setTimeout をセット

ページ:
- / — 未認証なら「サインイン」ボタン、認証済みなら wallet_address とサインアウトを表示
- /callback — コード交換を処理して / にナビゲート

ログイン後は id_token(JWT)をデコードして sub と wallet_address クレームを読み取る。
BFH Developer Portal