Go言語で実現するBearerトークン認証
モダンなWeb API開発において、セキュリティを確保するための認証方式として「Bearerトークン(主にJWTなど)」は事実上の標準となっています。
Go言語の標準ライブラリ net/http を用いて、この認証ヘッダーを正しく、かつ安全に実装する方法を詳しく解説します。
1. 実装サンプルコード
以下のコードは、JSONデータをPOSTしつつ、AuthorizationヘッダーにBearerトークンを付与する完結したサンプルです。 エラーハンドリングやタイムアウト設定など、実務で必須となる要素を盛り込んでいます。
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"time"
)
func main() {
// 接続先URLと認証トークンの定義
const (
apiURL = "https://example.com/api/v1/resource"
bearerToken = "your_secret_access_token"
)
// 送信するペイロード(JSON)の構築
payload := []byte(`{"name": "Gopher", "role": "Developer"}`)
// 1. リクエストオブジェクトの生成
// http.Post() 等の簡易メソッドではヘッダーの個別設定ができないため、NewRequestを使用します
req, err := http.NewRequest(http.MethodPost, apiURL, bytes.NewBuffer(payload))
if err != nil {
fmt.Printf("リクエストの作成に失敗しました: %v\n", err)
return
}
// 2. 必須ヘッダーの設定
// Bearerの後には必ず半角スペースが必要です
req.Header.Set("Authorization", "Bearer "+bearerToken)
req.Header.Set("Content-Type", "application/json")
// 3. HTTPクライアントの実行
// http.DefaultClient はタイムアウトが設定されていないため、独自のClient定義を強く推奨します
client := &http.Client{
Timeout: 10 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
fmt.Printf("通信エラーが発生しました: %v\n", err)
return
}
// リソースリークを防ぐため、必ずCloseを呼び出す
defer resp.Body.Close()
// 4. 結果の読み取りと判定
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == http.StatusOK {
fmt.Printf("成功: %s\n", string(body))
} else {
fmt.Printf("サーバーエラー: %d - %s\n", resp.StatusCode, string(body))
}
}
2. 実装上の重要なTips
なぜ http.NewRequest を使うのか?
http.Get や http.Post は内部でデフォルトのクライアントを使用しており、独自のヘッダーを追加する機能がありません。
認証が必要なAPIを叩く場合は、http.NewRequest を使用してリクエストインスタンスを生成し、Header.Set で個別に制御するのが正しいアプローチです。
Bearerスキームの書式に注意
Authorizationヘッダーの値は Bearer <token> という形式で指定する必要があります。
この Bearer とトークンの間の半角スペースを忘れると、サーバー側で正しくパースされず、401 Unauthorizedエラーの原因となります。
プロダクション環境での注意点
- タイムアウト: ネットワークの遅延やサーバーの無応答に備え、必ず
http.Clientにタイムアウトを設定してください。 - トークンの秘匿: トークンをコード内にハードコードせず、環境変数(
os.Getenv)やシークレット管理サービスから取得するようにしましょう。