Go言語

Goで実装するJWT認証付きWeb API入門 – GinとDocker Compose活用

ⓘ本ページはプロモーションが含まれています

もっとスキルを活かしたいエンジニアへ

スポンサードリンク
働き方から選べる

無料で使えて良質な案件の情報収集ができるサービス

エンジニアの世界では、「いつでも動ける状態を作っておけ」とよく言われます。
技術やポートフォリオがあっても、自分に合う案件情報を日常的に見れていないと、いざ動こうと思った時に比較や判断が難しくなってしまいます。
普段から案件情報が集まる環境を作っておくと、良い案件が出た時にすぐ動きやすくなりますよ。
筆者自身も、メガベンチャー勤務時代に年収1,500万円を超えた経験があります。振り返ると、技術だけでなく「どんな案件や働き方があるか」を日頃から見ていたことが、キャリアの選択肢を広げるきっかけになりました。
このブログを読んでくれた方に感謝を込めて、実際に使っている情報収集サービスを紹介します。

フルリモート・週3日・高単価、どんな条件も妥協したくないなら

フリーランスボードに無料会員登録する

利用者10万人以上。業界最大規模45万件の案件。AIマッチ機能や無料の相場情報が人気。

年収800万円以上のキャリアアップ・ハイクラス正社員を視野に入れているなら

Beyond Careerに無料相談する

内定獲得率90%以上。紹介先企業とは役員クラスのコネクションがある安心と信頼できるエージェント。


スポンサードリンク

認証と認可の基本概念と Go における位置付け

認証(Identity verification)はユーザーが誰であるかを確定し、認可(Access control)はそのユーザーに何を許可するかを決めます。Web API では、認証情報をリクエストコンテキストに乗せて次のハンドラへ受け渡すことで、認可ロジックをシンプルに実装できます。本節では Go の標準ライブラリが提供するツールと、実務での組み合わせ方を示します。

認証 vs 認可

この比較表は、2 つの概念がどこで分岐し、どんな責務を持つかを明確にします。

項目 認証 認可
目的 「誰が」アクセスしているかを判定 「何が」できるかを制御
主な実装例 パスワード検証、OAuth2、JWT の署名検証 RBAC / ABAC ポリシー評価、エンドポイント単位の許可チェック

Go 標準ライブラリで扱える認証要素

以下は、標準パッケージだけで実装可能な基礎機能です。実務ではこれらを組み合わせてミドルウェアやハンドラを構築します。

標準パッケージ 主な役割
net/http ハンドラチェーン・ミドルウェアの土台
context 認証情報(例: ユーザー ID)を安全に伝搬
crypto/subtle 定数時間比較でタイミング攻撃を防止
errors エラーラッピングで原因追跡を容易化

実装ヒント
認証ミドルウェアはトークン検証後に ctx = context.WithValue(ctx, userIDKey, uid) と設定し、ハンドラ側では uid := ctx.Value(userIDKey).(int64) で取得するとシンプルです。


JWT の仕組みと安全な実装ガイド

JWT は Header / Payload / Signature の三部構成で、Web API のステートレス認証に広く利用されています。本章では必須クレームだけを簡潔に示し、署名方式の選択基準と鍵管理のベストプラクティスを解説します。

JWT の必須クレームと構造

JWT で最低限必要なのは sub(Subject)、exp(Expiration)、iat(Issued At)です。これらだけでトークンの有効性と所有者が判定できます。カスタムクレームは roleperm のように、認可ロジックで参照する情報を付加します。

パート
Header {"alg":"HS256","typ":"JWT"}
Payload {"sub":12345,"exp":1735689600,"iat":1735603200,"role":"admin"}
Signature HMAC‑SHA256( base64url(header) + "." + base64url(payload), secret )

参考文献
Zenn に掲載された実装ガイド「JWT 実装の落とし穴と対策」を [2] として採用しています。

署名方式 HS256 と RS256 の選択基準

方式 特徴 推奨シーン
HS256 (対称鍵) 秘密鍵 1 本で署名・検証。高速だがキー漏洩リスクがある。 小規模サービス、内部 API、キー管理が容易な場合
RS256 (非対称鍵) 公開鍵で検証、秘密鍵はサーバ側に限定。鍵ローテーションがしやすい。 マルチサービス・外部連携、PKI 環境、セキュリティ要件が高い場合

2024 年の実務では マイクロサービス間のトラストを明確化したい 場合は RS256 を採用することが多く、Zenn の事例([2])でも同様です。

シークレット・鍵管理のベストプラクティス

  1. 環境変数またはファイル
    bash
    # .env 例
    JWT_ALG=RS256
    PRIVATE_KEY_PATH=/run/secrets/jwt_private.pem
    PUBLIC_KEY_PATH=/run/secrets/jwt_public.pem
    JWT_SECRET=my-very-long-secret # HS256 用
  2. 外部シークレットストア(Vault / AWS Secrets Manager)
    起動時に API で取得し、メモリ上だけ保持することでディスク漏洩を防止します。
  3. ローテーション戦略
    kid ヘッダーでキー ID を付与し、古い鍵は一定期間保持してバックワード互換性を保ちます。

ユーザー認証基盤の構築:パスワードハッシュ化と DB 設計

安全なユーザーデータ管理は認証システム全体の土台です。ここでは bcrypt によるハッシュ生成・比較と、実務で使える PostgreSQL のテーブル定義を示します。

bcrypt を用いたパスワード保存と比較

以下コードはインポート文・エラーハンドリングを含めて完全版です。cost=12 が推奨値ですが、CPU リソースに合わせて調整してください。

ベンチマーク情報
2024 年の Zenn 記事([2])でも cost=12 が実務上最もバランスが良いと報告されています。

PostgreSQL のテーブル設計例

テーブル 主なカラム 補足
roles id, name ロールは一意に管理し、認可ロジックで参照
users id, email, password_hash, role_id, created_at, updated_at email にユニーク制約、role_id は外部キー

  • password_hash には上記 HashPassword の出力を保存します。
  • role_id を外部キー化することで、認可チェックはシンプルに「ユーザーが所属するロールの権限」を参照できます。

Gin と Docker Compose で JWT 認証を実装する手順

この章ではプロジェクト構成からミドルウェア実装、トークン発行・更新フロー、Docker Compose 設定まで一通り網羅します。コード例は コンパイル可能 な形に整えてあります。

プロジェクト構成と依存パッケージ

まずはディレクトリツリーと go.mod の雛形です。バージョンは「最低保証」だけを書き、go get -u ./... で将来の互換性を保てます。

go.mod(抜粋)

注意go.mod では「v1.9」や「v5」のように 最小 バージョンを示すだけで、go get -u により将来のマイナーバージョンへ自動更新できます。

JWT ミドルウェア(HS256 と RS256 両対応)

以下実装は keyPath が空でも HS256 用シークレットが必須 になるように修正し、インポート・エラーハンドリングを網羅しています。

使い方例(cmd/server/main.go

トークン生成ユーティリティ(アクセストークン・リフレッシュトークン)

以下関数は エラーハンドリング とインポートを完備した実装です。HS256 と RS256 の両方に対応しています。

Docker Compose による開発・テスト環境構築

以下 docker-compose.yml は Go アプリ、PostgreSQL、Redis を一括起動します。イメージタグは latest のマイナーバージョン互換 を前提に記載しています。

  • api コンテナはビルドしたバイナリを実行し、.env で渡された JWT_ALG, JWT_SECRET, PRIVATE_KEY_PATH 等を参照します。
  • Redis はトークンブラックリストやレートリミットに利用できますが、本サンプルでは TTL と同時に自動削除 する設計です。

運用・テスト・CI/CD:エラーハンドリング、ログ、テスト自動化のベストプラクティス

実装だけでなく、運用フェーズでの安定性を確保するために必要な手法をまとめます。Go 1.22 標準ライブラリと一般的な CI ツールを前提にしています。

構造化ロギングとエラーラッピング

  • エラーラッピングfmt.Errorf("db query: %w", err) のように行い、errors.Is で原因判定が可能です。
  • 構造化ロギングは Go 1.21+ の log/slog を利用し、JSON 出力で Loki / Elastic にそのまま流せます。

ユニットテストと統合テストのサンプル

ミドルウェア単体テスト(HS256)

Docker Compose を利用した統合テスト(testcontainers-go)

GitHub Actions での CI パイプライン例

  • services でテスト用 DB と Redis を自動起動し、環境変数で接続情報を渡しています。
  • Lint は staticcheck(推奨)に変更し、将来的なコード品質維持に寄与します。

実務での落とし穴と次のアクション

実装・運用段階で頻出する問題点を一覧化し、具体的な回避策と監視ポイントを示します。これらを踏まえてプロジェクトにすぐ適用できる チェックリスト を最後に添付します。

落とし穴 主因 回避策 / 監視ポイント
トークン期限切れが頻発 アクセストークンの TTL が短すぎ、リフレッシュエンドポイント未実装 refresh エンドポイントで自動再取得ロジックを組み込み、失敗時は UI で再ログイン促進
秘密鍵・シークレット漏洩 環境変数やコードにハードコーディング CI にシークレットスキャン(GitGuardian 等)を導入し、Vault / Secrets Manager へ移行
Redis ブラックリスト肥大化 ログアウト・失効トークンが大量に残る TTL をトークン有効期限と同一に設定し、定期的に SCAN + DEL でクリーンアップ
アルゴリズム不一致(HS256 ↔ RS256) 複数サービスで設定差分がある キーの kid ヘッダーを必須化し、認証サーバーで統一的に署名・検証する
エラーハンドリング漏れ DB/Redis のエラーがそのまま 500 に流れる errors.Is(err, pgx.ErrNoRows) 等で原因別ステータスコードを返すユーティリティ関数を作成

今すぐ取るべきアクション

  1. リポジトリのクローン
    bash
    git clone https://github.com/example/myapp.git && cd myapp
    cp .env.example .env
  2. 環境変数を設定(例: .envJWT_ALG=HS256, JWT_SECRET=my-secret
  3. スタック起動
    bash
    docker compose up -d
  4. ログイン → トークン取得 → 保護 API 呼び出し を手順通りに実行し、期待どおり 200 が返ることを確認。
  5. CI が成功することを確認(GitHub Actions のステータスが緑になる)後、本番環境へデプロイ用の GitOps パイプラインに組み込みます。

チェックリスト(実装・運用時に活用)

  • [ ] JWT_ALG と鍵/シークレットの取得ロジックがミドルウェアと一致しているか
  • [ ] 必須クレーム (sub, exp, iat) が必ず設定されていることをテストで検証
  • [ ] シークレットは環境変数または Vault から取得し、コードにハードコーディングが残っていないか
  • [ ] Redis のトークンブラックリストに TTL を付与し、定期クリーンアップジョブを設定
  • [ ] CI に staticcheck とテストカバレッジ測定を組み込み、失敗時はプルリクエストをブロック
  • [ ] ログは JSON 形式で出力され、Loki / Elastic へ転送できるか

以上で Go 言語による安全な認証基盤 の全体像と実装ガイドが完成です。提示したベストプラクティスをプロジェクトに落とし込み、継続的な改善サイクルを回すことで、セキュリティインシデントのリスクを大幅に低減できます。

スポンサードリンク

もっとスキルを活かしたいエンジニアへ

スポンサードリンク
働き方から選べる

無料で使えて良質な案件の情報収集ができるサービス

エンジニアの世界では、「いつでも動ける状態を作っておけ」とよく言われます。
技術やポートフォリオがあっても、自分に合う案件情報を日常的に見れていないと、いざ動こうと思った時に比較や判断が難しくなってしまいます。
普段から案件情報が集まる環境を作っておくと、良い案件が出た時にすぐ動きやすくなりますよ。
筆者自身も、メガベンチャー勤務時代に年収1,500万円を超えた経験があります。振り返ると、技術だけでなく「どんな案件や働き方があるか」を日頃から見ていたことが、キャリアの選択肢を広げるきっかけになりました。
このブログを読んでくれた方に感謝を込めて、実際に使っている情報収集サービスを紹介します。

フルリモート・週3日・高単価、どんな条件も妥協したくないなら

フリーランスボードに無料会員登録する

利用者10万人以上。業界最大規模45万件の案件。AIマッチ機能や無料の相場情報が人気。

年収800万円以上のキャリアアップ・ハイクラス正社員を視野に入れているなら

Beyond Careerに無料相談する

内定獲得率90%以上。紹介先企業とは役員クラスのコネクションがある安心と信頼できるエージェント。


-Go言語