API の資料を読んでいると、「API キーを発行してください」「Bearer トークンを付けてください」「リクエストに署名してください」と、サービスごとに認証のやり方がばらばらです。どれも「誰からのリクエストか」を示すしくみなのに、なぜこんなに種類があるのかを整理したくなりました。この記事では、よく出てくる6つの認証方式を、RFC とベンダーの公式ドキュメントで確かめながら並べて図にしました。
- API が確かめる「認証」と「認可」、401 と 403 の違い
- Basic・API キー・Bearer トークン・署名・クライアント証明書・ワークロード ID のしくみ
- 方式ごとに、何がネットワークに流れ、漏れたときにどうなるか
- 企業での使われ方の例と、選び方の目安
- 401・403 が返ってきたときの見方
API が確かめる2つのこと
API は、リクエストを受けるたびに「誰からか」(認証)と「その人が何をしてよいか」(認可)を確かめます。2つの違いは認証と認可の記事で説明しています。どちらで止まったかは、HTTP のステータスコードでわかります。
| ステータス | 意味 |
|---|---|
| 401 Unauthorized | 認証情報がない、または正しくない。名前は Unauthorized ですが、意味は「認証できない」です |
| 403 Forbidden | 認証はできたが、そのリソースへの権限がない |
この記事で比べる「認証方式」は、①の「誰からか」をどうやって示すかの違いです。
認証情報を入れる場所
方式によって、認証情報を入れる場所が違います。多くは HTTP の Authorization ヘッダに入れ、その先頭の言葉(Basic、Bearer など)で方式を表します。API キーは、サービスごとに名前の違うヘッダに入れることがよくあります。クライアント証明書だけは、HTTP のリクエストより前の TLS の段階で出します。
URL のクエリ文字列に入れる方法もありますが、避けます。OWASP は、パスワードやトークン、API キーを URL に入れるとサーバのログなどに残るとして、URL に入れないよう求めています。
6つの認証方式
Basic 認証:ユーザー名とパスワードをそのまま送る
Basic 認証(RFC 7617)は、「ユーザー名:パスワード」を Base64 という形式に変えて、毎回 Authorization ヘッダに入れる方式です。
例:ユーザー名 Aladdin、パスワード open sesame の場合(RFC 7617 の例)
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Base64 は文字の置き換えで、暗号ではありません。もとに戻せば、ユーザー名とパスワードがそのまま読めます。RFC 7617 も、TLS のような安全な通信路と組み合わせなければ、安全な認証方法とは言えないとしています。しかも、パスワードそのものをリクエストのたびに送ります。
API キー:長く使う秘密の文字列
API キーは、サービスが発行するランダムな文字列で、リクエストのたびにそのまま送ります。どのヘッダに入れるかはサービスごとに決まっていて、たとえば Azure API Management のサブスクリプションキーは Ocp-Apim-Subscription-Key ヘッダ、Cisco Meraki の Dashboard API は Authorization: Bearer の形で送ります。
手軽な反面、取り消すまで有効なものが多く、漏れると長く使われます。OWASP は、API キーだけで重要なリソースを守らないよう勧めています。
Bearer トークン:期限の短いトークン
Bearer トークンは、OAuth 2.0 などのしくみで発行されるアクセストークンを、Authorization: Bearer で送る方式です。期限が短く、使える範囲(スコープ)が決まっているのが特徴です。しくみはセッションとトークンの記事で説明しています。
Microsoft も、Exchange Online で Basic 認証をやめて OAuth 2.0 に移した理由として、アクセストークンは使える期間が限られ、発行されたアプリとリソースにしか使えないこと、多要素認証も有効にしやすいことを挙げています。
署名:秘密の鍵は送らず、署名だけを送る
署名の方式では、クライアントとサーバが同じ秘密の鍵を持ち、クライアントはリクエストの中身からその鍵で署名(HMAC)を計算して付けます。サーバも同じ計算をして、署名が一致するかを確かめます。秘密の鍵そのものはネットワークに流れません。HMAC のしくみは暗号の基礎の記事で説明しています。
AWS の API は、この形の Signature Version 4(SigV4)を使います。
例:SigV4 の Authorization ヘッダ(AWS のドキュメントの例。読みやすいよう改行してあり、実際は1行)
Authorization: AWS4-HMAC-SHA256
Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request,
SignedHeaders=host;x-amz-date,
Signature=calculated-signature
Credential にはアクセスキー ID(誰の鍵か)が入りますが、秘密のアクセスキーは入りません。AWS のドキュメントでは、リクエストの一部から計算したハッシュを含めることで途中での改ざんを防ぎ、ほとんどの場合、リクエストに書かれた時刻から5分以内に届かないと拒否する、と説明しています。
Webhook の通知でも同じ考え方が使われます。GitHub は、Webhook に設定した秘密の値と通知の中身から HMAC-SHA256 を計算し、X-Hub-Signature-256 ヘッダに sha256= で始まる値として付けて送ります。
クライアント証明書(mTLS):TLS の段階で相手を確かめる
ふつうの HTTPS では、サーバだけが証明書を出し、クライアントがサーバを確かめます。mTLS(相互 TLS)では、クライアントも証明書を出し、サーバがクライアントを確かめます。証明書の秘密鍵はクライアントの手元から出ず、TLS のやり取りの中で「その証明書の持ち主か」が確かめられます。
Azure API Management では、クライアント証明書を受け取るよう設定し、ポリシーで発行者やサブジェクト、拇印(サムプリント)を確かめられます。
例:拇印が違う証明書を 403 で断るポリシー(Microsoft のドキュメントの例)
<choose>
<when condition="@(context.Request.Certificate == null || !context.Request.Certificate.Verify() || context.Request.Certificate.Thumbprint != "DESIRED-THUMBPRINT-IN-UPPER-CASE")" >
<return-response>
<set-status code="403" reason="Invalid client certificate" />
</return-response>
</when>
</choose>
mTLS は TLS の段階の認証なので、途中で TLS を終わらせる機器があると、証明書がその先に届きません。Microsoft のドキュメントでも、API Management の前に Application Gateway(L7 のロードバランサ)を置くと、Application Gateway が API Management と別の TLS 接続を張るため、クライアントの証明書が API Management に渡らないと注意しています。
ワークロード ID:アプリに秘密を持たせない
ここまでの方式は、どれもアプリ側に何かしらの秘密(パスワード、キー、秘密鍵)を置きます。ワークロード ID は、アプリが動いている基盤(Azure や GitHub Actions など)に身元を保証してもらい、トークンをもらう方式です。
Azure の中で動くプログラムにはマネージド ID、GitHub Actions のように Azure の外で動くプログラムにはワークロード ID フェデレーションを使います。Microsoft のドキュメントでは、Azure で動くワークロードにはマネージド ID を使い、資格情報は Azure の基盤が管理する、と説明しています。
マネージド ID:VM の中から、基盤にトークンを頼む
Azure の VM でマネージド ID を有効にすると、Azure が VM 用の ID(サービスプリンシパル)を Microsoft Entra ID に作り、その証明書を VM の外側の基盤に用意します。VM の中のプログラムは、VM の中からしか届かない IMDS(Instance Metadata Service)にトークンを頼むだけです。
| 手順 | 何が起きるか |
|---|---|
| 事前 | VM の ID に、使ってよい Azure のリソースへの役割(RBAC)を割り当てておく |
| ① | VM の中のプログラムが、IMDS(http://169.254.169.254/metadata/identity/oauth2/token)にトークンを頼む |
| ②③④ | VM の ID のクライアント ID と証明書で Entra ID にトークンを頼み、JWT のアクセストークンがプログラムに返る |
| ⑤ | プログラムはアクセストークンを Authorization: Bearer で Azure のサービスに送る。サービスは VM の ID に割り当てた権限で処理する |
証明書はプログラムの手元になく、プログラムのコードや設定ファイルに秘密を書く必要がありません。実際のリクエストと応答の例は、セッションとトークンの記事で紹介しています。
ワークロード ID フェデレーション:外の基盤のトークンを、Entra ID のトークンと引き換える
GitHub Actions のように Azure の外で動くプログラムには、Azure の基盤がありません。そこで、その基盤(GitHub)が発行するトークンを、Microsoft Entra ID に「信頼する」と登録しておき、Entra ID のアクセストークンと引き換えます。
| 手順 | 何が起きるか |
|---|---|
| 事前 | Entra ID のユーザー割り当てマネージド ID(またはアプリの登録)に、フェデレーション資格情報を登録する。どの発行元(issuer)の、どの対象(subject:リポジトリやジョブ)、どの宛先(audience)のトークンを信頼するかを決める |
| ①② | ジョブが GitHub にトークンを頼み、GitHub がトークンを発行する |
| ③ | ジョブ(Azure へのサインインのアクション)が、GitHub のトークンを Entra ID に出してアクセストークンを頼む |
| ④ | Entra ID は信頼の設定と照合し、GitHub の OIDC の発行元 URL から署名の鍵を取って、トークンを確かめる。issuer・subject・audience は、登録した値と大文字・小文字まで一致する必要がある |
| ⑤⑥ | 確かめられたら Entra ID がアクセストークンを返し、ジョブはそれで Azure にデプロイする |
GitHub に保存するのは、クライアント ID・テナント ID・サブスクリプション ID といった「どの ID を使うか」を表す値だけで、パスワードや証明書は置きません。期限切れのシークレットを更新する手間や、漏れる心配もなくなります。同じしくみは、Kubernetes や Google Cloud、AWS で動くプログラムにも使えます。
最後に API に送るのは Bearer トークンなので、送り方だけを見ると Bearer と同じです。違いは、そのトークンをもらうためにアプリが長く使う秘密を持たなくてよい点です。
6つを並べて比べる
違いがいちばん出るのは、「何がネットワークに流れるか」と「漏れたときにどうなるか」です。
| 方式 | 送るもの・場所 | 期限 | よく使う場面 |
|---|---|---|---|
| Basic | ユーザー名とパスワード(Authorization: Basic) | パスワードを変えるまで | 古いシステム。新しく選ばない |
| API キー | キー(サービスごとのヘッダ) | 取り消すまでのことが多い | サービスや製品の API を手軽に使う |
| Bearer トークン | アクセストークン(Authorization: Bearer) | 短い(例:1時間前後) | ユーザーやアプリの権限で API を使う |
| 署名 | 署名と鍵の ID(Authorization など) | 鍵は長く使い、署名はリクエストごと | 改ざんを防ぎたい API、Webhook |
| クライアント証明書 | 証明書(TLS の段階) | 証明書の有効期限まで | 取引先や決まったシステムどうし |
| ワークロード ID | 基盤からもらうトークン(最後は Bearer) | 短い | クラウドの中のプログラム、CI/CD |
企業での使われ方(例)
会社のシステムでよく見る例を並べました。製品名と送るものは、どれも公式ドキュメントで確かめたものです。
| 方式 | 場面 | ポイント |
|---|---|---|
| Basic | 古いメールアプリやスクリプトから Exchange Online へ | Exchange Online は、EWS、POP、IMAP、Exchange ActiveSync などで Basic 認証を廃止し、OAuth 2.0 による認証に移った。SMTP AUTH の Basic 認証も廃止の予定が発表されている(時期は Microsoft の最新の告知で確認) |
| API キー | 社内アプリから Azure API Management で公開した API へ | Ocp-Apim-Subscription-Key ヘッダでサブスクリプションキーを送る。キーは既定でバックエンドにも渡るので、ログに残したくなければポリシーで外す |
| API キー | 自動化ツールから Meraki Dashboard API へ | API キーを Authorization: Bearer で送る。キーは発行した管理者と同じ権限を持ち、取り消すまで有効 |
| Bearer | 運用スクリプトから Microsoft Graph へ | Entra ID からアクセストークンをもらい、Authorization: Bearer で送る |
| 署名 | 自動化ツールや SDK から AWS の API へ | SigV4 で署名する。時刻から5分を過ぎたリクエストは、ほとんどの場合拒否される |
| 署名 | GitHub から社内の Webhook の受け口へ | X-Hub-Signature-256 を受け口で計算し直して比べる |
| クライアント証明書 | 取引先のシステムから Azure API Management へ | 証明書の発行者や拇印をポリシーで確かめる |
| ワークロード ID | GitHub Actions から Azure へデプロイ | OIDC のフェデレーションで、GitHub にシークレットを置かない |
| ワークロード ID | Azure の VM から Azure Resource Manager や Storage へ | マネージド ID で、VM の中からトークンをもらう |
1つの API が複数の方式を受け付けることもあります。Azure API Management は、サブスクリプションキーのほかに、OAuth 2.0 やクライアント証明書、呼び出し元の IP アドレスの制限も使えます。
選び方の目安
使う相手のサービスが決まっていれば、そのサービスが対応している方式から選ぶことになります。自分たちで API を作る・選べる場面では、次の順に考えると、アプリが持つ秘密を減らせます。
どの方式でも共通して大事なのは、次の点です。
- HTTPS で送る。Basic や API キー、Bearer トークンは、通信路で読まれればそのまま使われます。
- URL に入れない。ログや履歴に残ります。
- コードや設定ファイルに秘密を書かない。書く必要がない方式(ワークロード ID)を選ぶか、Key Vault のような保管場所に置きます。
- 権限を絞る。キーやトークンで何ができるかを、必要な範囲だけにします。
401・403 が返ってきたら
認証で止まったときは、まずステータスコードと WWW-Authenticate ヘッダを見ます。
| 状態 | よくある原因 | 確認すること |
|---|---|---|
401(invalid_token) | トークンの期限切れ、取り消し、形式の誤り | トークンを取り直す。RFC 6750 では、このエラーに 401 を返すとしている |
| 401(ヘッダなし) | ヘッダ名や方式の書き間違い(Bearer と Basic、キーのヘッダ名) | サービスのドキュメントと、送ったヘッダを見比べる |
403(insufficient_scope) | トークンの権限(スコープ)が足りない | トークンをもらうときに頼んだ権限を見直す。RFC 6750 では、このエラーに 403 を返すとしている |
| 403(認証は通っている) | ロールや権限の割り当てがない | API 側で、その ID に権限を割り当てているか確かめる |
| 署名のエラー | 端末の時刻のずれ、署名に含めるヘッダの違い | 時刻を合わせる(SigV4 は時刻から5分が目安) |
| 証明書が届かない | 途中の L7 の機器で TLS が終わっている | 証明書を確かめる場所まで、TLS がつながっているかを見る |
まとめ
| 項目 | ポイント |
|---|---|
| 確かめること | 認証(誰か)で失敗すると 401、認可(何をしてよいか)で失敗すると 403 |
| Basic | パスワードを毎回送る。Base64 は暗号ではない。新しく選ばない |
| API キー | 手軽だが長く使う秘密。ヘッダ名はサービスごと。重要なものはキーだけで守らない |
| Bearer トークン | 期限と範囲が限られたトークンを Authorization: Bearer で送る |
| 署名 | 秘密の鍵を送らず、署名で送り主と改ざんを確かめる(AWS SigV4、Webhook) |
| クライアント証明書 | TLS の段階で相手を確かめる。途中で TLS を終わらせる機器に注意 |
| ワークロード ID | 基盤に身元を保証してもらい、アプリに秘密を置かない |
参考にした資料
この記事は、次の標準と公式ドキュメントで内容を確かめて書きました。仕様や対応状況は変わることがあるので、最新の情報はリンク先で確かめてください。
- RFC 7617: The ‘Basic’ HTTP Authentication Scheme(IETF):Basic 認証の例、TLS なしでは安全でないこと
- RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage(IETF):invalid_token は 401、insufficient_scope は 403、クエリでの受け渡しを避けること
- RFC 8705: OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens(IETF):mTLS によるクライアント認証
- REST Security Cheat Sheet(OWASP):API キーだけに頼らないこと、URL に秘密を入れないこと、401 と 403
- Deprecation of Basic authentication in Exchange Online(Microsoft Learn):Basic 認証の廃止と、OAuth のアクセストークンの利点、SMTP AUTH の予定
- Subscriptions in Azure API Management(Microsoft Learn):Ocp-Apim-Subscription-Key、キーがバックエンドに渡ること、ほかの保護方法
- How to secure APIs using client certificate authentication in API Management(Microsoft Learn):クライアント証明書の検証ポリシー、Application Gateway の注意
- Workload identity federation concepts(Microsoft Learn):外部のトークンを Entra ID のアクセストークンと引き換える6つの手順、issuer・subject・audience の一致、使える場面
- Deploy to Azure Functions by using GitHub Actions(Microsoft Learn):OIDC とフェデレーションで GitHub にシークレットを置かないこと
- How managed identities for Azure resources work with Azure virtual machines(Microsoft Learn):VM の中からトークンをもらうしくみ
- AWS Signature Version 4 for API requests・Create a signed AWS API request(AWS):SigV4 のしくみ、改ざん対策と5分の時刻、Authorization ヘッダの例
- Validating webhook deliveries(GitHub Docs):X-Hub-Signature-256 の作り方
- Authentication – Meraki Dashboard API v1(Cisco Meraki Developer Hub):API キーの送り方、権限と有効期限
あとがき
6つを並べてみて、方式の違いは「アプリにどんな秘密を持たせるか」の違いだと整理できました。パスワードをそのまま送る Basic から、秘密を持たないワークロード ID まで、新しい方式ほど漏れたときの影響を小さくする方向に進んでいます。ネットワークの立場では、mTLS が途中の L7 の機器で切れてしまう点が、設計のときにいちばん気をつけたいところだと感じました。
コメント