go-jwt-middleware について
Go HTTP API に Auth0 JWT 検証を追加するコーディングスキルです。API の設定からミドルウェアの統合、エンドポイント保護、ビルド確認までをエージェントに案内します。
主な機能
- 01Auth0 JWT ミドルウェアの設定
- 02API リソースの設定
- 03保護ルートの統合
- 04スコープに基づく権限確認
- 05Go ビルドの検証
活用シーン
- 01Go API ルートへの JWT 認証追加
- 02権限スコープによるエンドポイント保護
- 03Auth0 認証情報と API の設定
- 04ミドルウェア統合のビルド確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ auth0/ agent-skills --skill go-jwt-middlewareインストール後、Claude Code で/go-jwt-middlewareを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api.mdintegration.mdsetup.md詳細
Go JWT ミドルウェアの統合
github.com/auth0/go-jwt-middleware/v3 を使用して JWT アクセストークンを検証し、Go HTTP API のエンドポイントを保護します。
エージェントへの指示: SDK のセットアップ手順を提示する前に、次のコマンドを実行して最新のリリースバージョンを取得してください。
gh api repos/auth0/go-jwt-middleware/releases/latest --jq '.tag_name'取得したバージョンを使用し、以下の依存関係の行にあるハードコードされたバージョンを置き換えてください。
前提条件
- Go 1.21 以上
- Auth0 API の設定(Application ではなく、API リソースである必要があります)
- Auth0 のセットアップがまだの場合は、まず
auth0-quickstartスキルを使用してください
使用しないケース
- Go のサーバーサイドレンダリング Web アプリケーション - セッションベースの Web アプリには
go-auth0を使用してください - シングルページアプリケーション - クライアントサイド認証には
auth0-react、auth0-vue、またはauth0-angularを使用してください - モバイルアプリケーション -
auth0-swift、auth0-android、またはauth0-react-nativeを使用してください - Go 以外のバックエンド - .NET には
auth0-aspnetcore-api、Node.js にはexpress-jwtを使用してください
クイックスタートのワークフロー
1. SDK をインストールする
go get github.com/auth0/go-jwt-middleware/v3
go get github.com/joho/godotenv
2. Auth0 API を作成する
Auth0 で必要なのは API(Application ではありません)です。
エージェントへの指示: ユーザーのプロンプトに Auth0 の認証情報(ドメインと audience)がすでに記載されている場合は、それらをそのまま使用し、以下のセットアップ方法の選択に関する質問を省略して、Step 3 に進み
.envファイルを作成してください。停止 — 先に進む前にユーザーに確認してください。
次の質問だけを尋ね、それ以外の作業は行わず、回答を待ってください。
"Auth0 API リソースをどのように作成しますか?
- 自動 — Auth0 CLI を使用して API リソースを作成し、正確な値を
.envファイルに自動で書き込みます。- 手動 — Auth0 Dashboard(または
auth0 apis create)で API を作成し、Domain と Audience を教えてください。どちらを希望しますか?(1 = 自動/2 = 手動)"
ユーザーが回答するまで、セットアップ手順に進まないでください。手動を既定の選択肢にしないでください。
ユーザーが「自動」を選択した場合は、セットアップガイドの「Initial Setup」セクション(手順 1~6)に従ってください。自動の手順では .env が作成されるため、以下の Step 3 は省略して Step 4 に進んでください。
エージェントへの指示(自動手順のチェックポイント):
自動の手順に従う場合は、次のチェックポイントを順番どおりに完了する必要があります。どれも省略しないでください。
- Auth0 CLI を確認する —
auth0がインストールされていることを確認します。- Auth0 へのログインを確認する —
auth0 tenants listを実行して、認証されていることを確認します。- アクティブなテナントを確認する — 現在アクティブなテナントをユーザーに示し、次のように尋ねます。「現在アクティブな Auth0 テナントは
<domain>です。このテナントでよろしいですか?」 確認を待ちます。違うと回答した場合は、ターミナルでauth0 tenants use <tenant>を実行するよう伝えてください。- API 名と識別子について尋ねる —
AskUserQuestionを使用します。「Auth0 API の名前と、使用する識別子(audience)を教えてください。例:名前:'My Go API'、識別子:'https://my-api.example.com'。識別子は解決可能である必要のない論理 URI で、API を一意に識別するためのものです。」 回答を待ちます。ユーザーが迷っている場合は、go.mod 内のプロジェクトのモジュール名をもとに識別子を作るよう提案してください(例:https://<module-name>)。- スコープについて尋ねる —
AskUserQuestionを使用します。「API に必要なスコープ(権限)を教えてください。例:read:users、write:users、read:products。まだ決まっていない場合は、一般的な既定値を設定して、後から追加できます。」 回答を待ちます。- 既存の API を確認する —
auth0 apis listを実行し、使用予定の識別子を持つ API がすでに存在するか確認します。存在する場合は、それを再利用するか、別の識別子で新しい API を作成するかをユーザーに尋ねてください。- API リソースを作成する — 手順 4~5 で指定された名前、識別子、スコープを使用します。
- .env を処理する —
.envファイルがすでに存在する場合は、変更する前にユーザーに確認してください。既存の.envの内容は読み取らないでください(シークレットが含まれている可能性があります)。.envが存在しない場合は、AUTH0_DOMAINとAUTH0_AUDIENCEを記述したファイルを作成します。.envを.gitignoreに追加する — まだ追加されていない場合は追加します。- コード統合に進む — Step 3 はすでに完了しているため省略し、Step 4 に進んでミドルウェアのコードを記述します。
ユーザーが「手動」を選択した場合は、セットアップガイドの「Manual Setup」セクションに従ってください。その後、以下の Step 3 に進みます。
手動で API を作成する場合のクイックリファレンス:
# Using Auth0 CLI
auth0 apis create \
--name "My Go API" \
--identifier https://my-api.example.com
または、Auth0 Dashboard → Applications → APIs から手動で作成します。
3. .env を設定する
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_AUDIENCE=https://my-api.example.com
重要: Domain に https:// を含めないでください。ミドルウェアが issuer URL を自動的に構築します。
4. main.go を設定する
エージェントへの指示(既存コードと統合する場合):
コードを書く前に、次のどちらに該当するかを判断してください。
- A)既存のプロジェクトに認証を追加する場合 — ユーザーはすでにルートが定義された
main.goを用意しています。この場合、以下のテンプレートでファイルを置き換えないでください。代わりに、次の手順を行ってください。
- 必要なインポート(
jwtmiddleware、jwks、validator、godotenv、net/url、os、context、strings)を追加します。CustomClaims構造体とメソッドを追加します。main()の冒頭付近にミドルウェアのセットアップコード(発行者 URL、JWKS プロバイダー、バリデーター、ミドルウェア)を追加します。- 保護するエンドポイントを尋ねます(以下を参照)。
- 指定されたハンドラーを
middleware.CheckJWT()でラップします。- B)新しいプロジェクトをゼロから作成する場合 — 以下の完全なテンプレートを出発点として使用します。
停止 — 保護するエンドポイントを尋ねてください:
ユーザーのリクエストで保護するエンドポイントが明示されていない場合は、次のように尋ねてください。
「認証が必要なエンドポイントはどれですか? たとえば、次のように指定できます。
- ヘルスチェック/公開エンドポイント以外すべて — 特定の公開ルートだけを除き、すべてを保護します
- 特定のルート — 認証が必要なルートを教えてください
また、特定のエンドポイントにスコープ/権限チェック(例:POST/DELETE に対する
write:users)が必要ですか? それとも、有効な JWT があればすべてのエンドポイントを利用できますか?」回答を待ちます。ユーザーが「すべて」または「ヘルスチェック以外すべて」と答えた場合は、
/health(またはユーザーが公開すると指定したルート)以外のすべてのルートを保護します。エンドポイントごとのスコープ要件が指定された場合は、customClaims.HasScope()を使用してルートごとのスコープチェックを実装します。
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"net/url"
"os"
"strings"
jwtmiddleware "github.com/auth0/go-jwt-middleware/v3"
"github.com/auth0/go-jwt-middleware/v3/jwks"
"github.com/auth0/go-jwt-middleware/v3/validator"
"github.com/joho/godotenv"
)
// CustomClaims contains custom data we want from the token.
type CustomClaims struct {
Scope string `json:"scope"`
Permissions []string `json:"permissions"`
}
func (c CustomClaims) Validate(ctx context.Context) error {
return nil
}
func (c CustomClaims) HasScope(expectedScope string) bool {
for _, scope := range strings.Split(c.Scope, " ") {
if scope == expectedScope {
return true
}
}
return false
}
func main() {
if err := godotenv.Load(); err != nil {
log.Fatalf("Error loading .env file: %v", err)
}
issuerURL, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/")
if err != nil {
log.Fatalf("Failed to parse issuer URL: %v", err)
}
provider, err := jwks.NewCachingProvider(
jwks.WithIssuerURL(issuerURL),
)
if err != nil {
log.Fatalf("Failed to set up JWKS provider: %v", err)
}
jwtValidator, err := validator.New(
validator.WithKeyFunc(provider.KeyFunc),
validator.WithAlgorithm(validator.RS256),
validator.WithIssuer(issuerURL.String()),
validator.WithAudience(os.Getenv("AUTH0_AUDIENCE")),
validator.WithCustomClaims(func() validator.CustomClaims {
return &CustomClaims{}
}),
)
if err != nil {
log.Fatalf("Failed to set up JWT validator: %v", err)
}
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(jwtValidator),
)
if err != nil {
log.Fatalf("Failed to set up JWT middleware: %v", err)
}
mux := http.NewServeMux()
// Public endpoint - no authentication
mux.HandleFunc("/api/public", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": "Hello from a public endpoint!"})
})
// Protected endpoint - requires valid JWT
mux.Handle("/api/private", middleware.CheckJWT(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
if err != nil {
http.Error(w, `{"message":"Failed to get token claims."}`, http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"message": "Hello from a private endpoint!",
"userId": claims.RegisteredClaims.Subject,
})
})))
// Protected + scoped endpoint - requires JWT with specific scope
mux.Handle("/api/private-scoped", middleware.CheckJWT(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
if err != nil {
http.Error(w, `{"message":"Failed to get token claims."}`, http.StatusInternalServerError)
return
}
customClaims := claims.CustomClaims.(*CustomClaims)
if !customClaims.HasScope("read:messages") {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusForbidden)
json.NewEncoder(w).Encode(map[string]string{"message": "Insufficient scope."})
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": "Hello from a scoped endpoint!"})
})))
log.Println("Server listening on :8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}
5. エンドポイントを保護する
認証が必要なハンドラーをラップするには、middleware.CheckJWT() を使用します。
// Public endpoint - no authentication
mux.HandleFunc("/api/public", publicHandler)
// Protected endpoint - requires valid JWT
mux.Handle("/api/private", middleware.CheckJWT(http.HandlerFunc(privateHandler)))
// Protected + scoped - requires JWT with specific permission
mux.Handle("/api/private-scoped", middleware.CheckJWT(http.HandlerFunc(privateScopedHandler)))
6. API をテストする
エージェントへの指示: コードを書いた後、ビルドが成功することを確認します。
go build ./...コンパイルに失敗した場合は、エラーを診断して修正します。最大 5~6 回繰り返してください。
失敗時の確認: 5~6 回修正を試みてもビルドに失敗する場合は、作業を止め、
AskUserQuestionを使ってユーザーに次のように尋ねてください。 「何度か修正を試みましたが、ビルドはまだ失敗しています。どのように進めますか?」
- 引き続き、反復して修正する
- 手動で修正する — 残っているエラーを表示します
- ビルド確認をスキップする — ビルドに成功していない状態で続行する
エラーが続く場合は、5~6 回の試行ごとにこの確認を繰り返してください。
エージェントへの指示:ビルド成功後は停止して尋ねてください。
ビルドのコンパイルが正常に完了したら、ユーザーに次のように尋ねてください。
「API のセットアップが完了し、正常にコンパイルされました。テストのセットアップもお手伝いしましょうか?
- はい — テスト用トークンを取得するために、M2M アプリケーションの設定をお手伝いします。
- いいえ — 今回はここまでにします。
どちらにしますか?」
ユーザーが「はい」と答えない限り、テストのセットアップに進まないでください。「いいえ」と答えた場合は、実施した内容をまとめて終了します。 エージェントへの指示(M2M アプリのセットアップ — ユーザーがテストを希望する場合のみ):
ユーザーがテストを設定することを選択した場合は、次のように尋ねます。
"保護されたエンドポイントをテストするには、この API のトークンをリクエストする権限を持つマシン間(M2M)アプリケーションが必要です。
- 新規作成 — 新しい M2M アプリケーションを作成し、この API の利用を許可します。
- 既存のものを使用 — すでに M2M アプリケーションをお持ちです。Client ID を入力していただければ、この API の利用を許可します。
どちらを希望しますか?(1 = 新規作成/2 = 既存のものを使用)"
ユーザーが回答するまで、先に進んではいけません。テナント内の既存アプリケーションを暗黙に選択してはいけません。
ユーザーが「新規作成」を選択した場合:
auth0 apps create \ --name "<PROJECT_NAME> (Test App)" \ --type m2m \ --no-input --jsonJSON を解析して
client_idを抽出します。--reveal-secretsは使用してはいけません。エージェントのコンテキスト内でクライアントシークレットを公開してはいけません。 次に、クライアントグラントを作成します。auth0 api post "client-grants" --data '{ "client_id": "<CLIENT_ID>", "audience": "<API_IDENTIFIER>", "scope": ["<SCOPES>"] }'ユーザーが「既存のものを使用」を選択した場合: Client ID を尋ねます。その後、この API の利用を許可するクライアントグラントを作成します。
auth0 api post "client-grants" --data '{ "client_id": "<USER_PROVIDED_CLIENT_ID>", "audience": "<API_IDENTIFIER>", "scope": ["<SCOPES>"] }'グラントがすでに存在する場合(409 conflict)も問題ありません。アプリはすでに許可されています。 エージェントへの指示(トークンの隔離 — 最重要):
エージェントはアクセストークンの値を直接見たり、表示したりしてはなりません。トークンのセキュリティルール:
auth0 test tokenを単独で実行しないでください — トークンが標準出力に出力されます/oauth/tokenエンドポイントへのcurlコマンドを単独で実行しないでください- ユーザーに会話内でトークンを貼り付けるよう求めないでください
- トークンの値をエコー、表示、またはログに記録しないでください
- トークンをファイルに保存しないでください
安全なテスト方法(単一コマンドチェーン):
ユーザーが保護されたエンドポイントのテストを明示的に依頼した場合、エージェントはトークンをシェル変数に取り込み、直ちに使用する単一コマンドチェーンを使用できます — トークンの値が表示されたり、エージェントに見えたりすることはありません:
TEST_TOKEN=$(auth0 test token <CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> 2>/dev/null | grep -o 'ey[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*') && \ [ -n "$TEST_TOKEN" ] && echo "Token acquired (${#TEST_TOKEN} chars)" && \ curl -s http://localhost:8080/<ENDPOINT> -H "Authorization: Bearer $TEST_TOKEN"この方法のセキュリティ上の保証:
$(...)は標準出力を取り込みます — トークンは変数に取り込まれ、表示されませんgrep -oは JWT のパターン(ey...)だけを抽出します — 周囲の出力が漏れることはありませんecho "Token acquired (${#TEST_TOKEN} chars)"は長さのみを表示して成功を確認します。値そのものは表示しません- シェル変数
$TEST_TOKENは単一コマンドチェーンの実行中だけ存在し、実行直後に破棄されます- エージェントに見えるのは
"Token acquired (834 chars)"と API レスポンス本文(JSON)のみです- ファイルは書き込まれず、環境変数もエクスポートされず、何も残りません
このパターンを使用する際のルール:
- ユーザーがテストを明示的に依頼した場合(例:「テストして」「テストを実行して」「エンドポイントが動作することを確認して」)にのみ使用してください
- トークンの取得と curl は必ず単一の
&&コマンドに連結し、2 回の Bash 呼び出しに分けないでください- 複数のエンドポイントをテストする場合は、同じコマンド内で複数の curl を連結してください:
TEST_TOKEN=$(auth0 test token <CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> 2>/dev/null | grep -o 'ey[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*') && \ [ -n "$TEST_TOKEN" ] && echo "Token acquired (${#TEST_TOKEN} chars)" && \ echo "=== GET /users ===" && \ curl -s http://localhost:8080/users -H "Authorization: Bearer $TEST_TOKEN" && \ echo "" && echo "=== POST /users ===" && \ curl -s -X POST http://localhost:8080/users -H "Authorization: Bearer $TEST_TOKEN" -d '{"id":"99","name":"Test","email":"[email protected]"}' && \ echo "" && echo "=== GET /products ===" && \ curl -s http://localhost:8080/products -H "Authorization: Bearer $TEST_TOKEN"echo $TEST_TOKEN、printf $TEST_TOKEN、または未加工のトークン値を表示するコマンドは絶対に追加しないでください- トークンの取得に失敗した場合(変数が空の場合)、
[ -n "$TEST_TOKEN" ]のチェックによってコマンドチェーンは停止します — M2M アプリが認可されていない可能性があることをユーザーに伝えてください- クライアント ID は必須です —
auth0 test tokenコマンドでは、最初の引数としてクライアント ID を渡す必要があります。これは M2M アプリのセットアップ手順(新規作成または既存のものを使用)で取得したclient_idでなければなりません。M2M のセットアップがまだ完了しておらず(クライアント ID がない場合)、テストトークンのコマンドを実行しないでください。代わりに、ユーザーに 「テストトークンを取得するには、M2M アプリケーションのクライアント ID が必要です。新規作成しますか、それとも既存のものをお持ちですか?」 と尋ねてから、先に M2M のセットアップを完了してください。ユーザーがテストを依頼していない場合は、手動で実行するコマンドだけを提示してください:
auth0 test token <CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> curl http://localhost:8080/<endpoint> -H "Authorization: Bearer <PASTE_TOKEN_HERE>"
M2M のセットアップが完了したら:
- バックグラウンドで
go run .を実行してサーバーを起動します - パブリックエンドポイントが 200 を返し、保護されたエンドポイントが 401 を返すことを確認します(トークンは不要です)
- ユーザーがテストを依頼した場合:認証済みリクエストには、上記の安全な単一コマンドチェーンを使用します
- ユーザーがテストを依頼していない場合:手動コマンドを提示し、ターミナルで実行するよう伝えます
パブリックエンドポイントをテストします:
curl http://localhost:8080/api/public
トークンなしで保護されたエンドポイントをテストします(401 が返るはずです):
curl http://localhost:8080/api/private
トークンありで保護されたエンドポイントをテストします(安全な単一コマンドチェーン):
TEST_TOKEN=$(auth0 test token <M2M_CLIENT_ID> --audience https://my-api.example.com --scopes <SCOPE1,SCOPE2> 2>/dev/null | grep -o 'ey[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*') && \
[ -n "$TEST_TOKEN" ] && echo "Token acquired (${#TEST_TOKEN} chars)" && \
curl -s http://localhost:8080/api/private -H "Authorization: Bearer $TEST_TOKEN"
よくある間違い
| 間違い | 修正方法 |
|---|---|
| Auth0 で API ではなく Application を作成した | Auth0 Dashboard → Applications → APIs で API リソースを作成する必要があります |
| Audience が API Identifier と一致しない | Auth0 Dashboard で設定した API Identifier と完全に一致させる必要があります |
Domain に https:// が含まれている | your-tenant.auth0.com の形式のみを使用します。issuer URL は自動的に構築されます |
| v3 のオプションではなく v2 の位置引数を使用している | v3 では validator.WithKeyFunc()、validator.WithAlgorithm() などを使用します |
| issuer URL の末尾にスラッシュがない | issuer は末尾にスラッシュを付けた https://domain/ にする必要があります |
RBAC で permissions ではなく scope クレームを確認している | Permissions []string フィールドを持つカスタムクレーム構造体を使用します |
godotenv.Load() の呼び出しがない | github.com/joho/godotenv を追加し、環境変数を読み取る前に godotenv.Load() を呼び出します |
クレームへのアクセスに ContextKey{} を使用している(v2 のパターン) | 型安全なジェネリクスである jwtmiddleware.GetClaims[T]() を使用します |
スコープベースの認可
スコープと権限のポリシーの定義および適用については、Integration Guide を参照してください。
CORS の設定
ブラウザーベースの SPA から呼び出される API では、認証ミドルウェアより前に CORS を設定します。
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusNoContent)
return
}
next.ServeHTTP(w, r)
})
}
mux をラップする最外部のハンドラーとして適用します。
handler := corsMiddleware(mux)
log.Fatal(http.ListenAndServe(":8080", handler))
CORS の詳しいパターンについては、Integration Guide を参照してください。
DPoP のサポート
RFC 9449 に準拠した、組み込みの proof-of-possession トークンバインディングです。設定については、Integration Guide を参照してください。
関連スキル
auth0-quickstart- Auth0 の基本的なセットアップauth0-mfa- 多要素認証の追加
クイックリファレンス
設定オプション:
validator.WithKeyFunc(provider.KeyFunc)- 署名検証用の JWKS キー関数(必須)validator.WithAlgorithm(validator.RS256)- 想定する署名アルゴリズム(必須)validator.WithIssuer(url)- 末尾にスラッシュを付けたトークン発行者 URL(必須)validator.WithAudience(aud)- Auth0 API 設定の API Identifier(必須)validator.WithCustomClaims(fn)- カスタムクレーム構造体のファクトリーvalidator.WithAllowedClockSkew(d)- クロックスキューの許容範囲
クレームへのアクセス:
jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())- 型安全なクレームの取得claims.RegisteredClaims.Subject- ユーザー ID(sub)claims.CustomClaims.(*CustomClaims).Scope- スペース区切りのスコープclaims.CustomClaims.(*CustomClaims).Permissions- 権限文字列
よくあるユースケース:
- ルートの保護 →
middleware.CheckJWT(handler)(Step 5 を参照) - 権限の適用 → Integration Guide
- DPoP トークンバインディング → Integration Guide
- フレームワークアダプター(Gin、Echo)→ Integration Guide
- 高度な JWT 設定 → API Reference
詳細ドキュメント
- Setup Guide - Auth0 CLI のセットアップ、環境設定
- Integration Guide - スコープポリシー、DPoP、フレームワークアダプター、エラー処理
- API Reference - 設定オプションの全項目、およびバリデーター/ミドルウェアのリファレンス