gcloud コマンドで認証してGoogle Drive APIを使うときの罠
はじめに:何をしようとしたか
ローカル環境でシェルスクリプトを組み、Google Driveの特定フォルダにある画像を順番に文字起こしする、というシンプルなCLIツールを作ろうとしたのが始まりでした。
当初の計画:
-
gcloud
CLIで認証する。 -
gcloud auth application-default print-access-token
で一時的なアクセストークンを取得する。 - そのトークンを使って
curl
でGoogle Drive APIを叩き、ファイルリストを取得したり、ファイルをダウンロードしたりする。 - ダウンロードした画像をGemini CLIに渡して文字起こしする。
一見、ローカル環境からGoogleのサービスを利用するごく標準的なアプローチのはずでした。
Insufficient Scopes
)
第1の壁:権限が足りない (まず最初にcurl
でAPIを叩くと、あっけなく403 PERMISSION_DENIED
エラーが返ってきました。
エラーメッセージ:
"Request had insufficient authentication scopes."
原因と解決策
これは「認証はできているが、許可されている操作の範囲(スコープ)にGoogle Driveの操作が含まれていない」という状態です。
gcloud auth application-default login
をただ実行しただけでは、Google Cloud Platform (GCP) サービス用の基本的なスコープしか付与されません。Google Drive APIを操作するには、専用のスコープを明示的に要求する必要がありました。
解決策:
--scopes
フラグを使って、GCPの基本スコープと、Google Driveの読み取りスコープの両方をカンマ区切りで指定して再度ログインする。
gcloud auth application-default login \
--scopes=https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/drive.readonly
📝 なぜ両方必要なのか?
--scopes
フラグはデフォルトのスコープに追加するのではなく、上書きします。そのため、drive.readonly
だけを指定すると、今度はgcloud
自体が機能するために必要なcloud-platform
スコープが消えてしまい、別のエラーが発生します。
Requires a Quota Project
)
第2の壁:どのプロジェクトの予算? (スコープ問題を解決し、再度APIを叩くと、またしても403 PERMISSION_DENIED
。しかし、エラーメッセージは変わっていました。
エラーメッセージ:
"The drive.googleapis.com API requires a quota project, which is not set by default."
原因と解決策
これは「APIの利用料金や使用量を、どのGCPプロジェクトの予算として計上すればいいか分からない」というエラーです。個人のPCからユーザー認証でAPIを使う場合、この「クォータプロジェクト」は自分で設定してあげる必要がありました。
解決策:
- APIを有効化: Google Cloudコンソールで、対象のプロジェクトに対して「Google Drive API」を有効にする。
-
クォータプロジェクトを設定:
gcloud
で、どのプロジェクトに紐付けるかを設定する。
# YOUR_PROJECT_IDを実際のプロジェクトIDに置き換える
gcloud auth application-default set-quota-project YOUR_PROJECT_ID
Consumer
プロジェクトの謎)
最後の壁:設定したはずなのに… (認証情報をリフレッシュし、設定ファイル(application_default_credentials.json
)にquota_project_id
が正しく書き込まれていることを確認。APIも有効になっている。これでOKのはず..なのに、何度やっても同じ「Quota Projectが必要」エラーが返ってくるのです。
万策尽きたかと思われましたが、エラーメッセージを注意深く見るとヒントが隠されていました。
エラーメッセージ内のdetails
:
"metadata": {
"service": "drive.googleapis.com",
"consumer": "projects/764086051850" // ← 謎のプロジェクト番号
}
APIサーバーがこのリクエストを処理しようとしたConsumerのプロジェクト番号が、私が設定したプロジェクト番号と違っていたのです。
なぜこの現象が起きるのか
これは、gcloud
がデフォルトで使う**「認証用の鍵(OAuth 2.0 クライアントID)」の所有者**に原因があります。
私たちがgcloud auth login
を実行する際、その認証プロセス自体が、Googleの管理する特殊なプロジェクト(この例では...764086051850
)に所属する「gcloud
ツール用の共通の鍵」を使って行われます。
通常、API側は利用者が設定した「クォータプロジェクト」を尊重してくれます。しかし、Google Drive APIのような一部のAPIでは、この認証フローが厳格で、クォータプロジェクト設定を無視して、認証に使われた「鍵」の所有者であるgcloud
のデフォルトプロジェクトを請求先と見なしてしまうのです。当然、そのプロジェクトではAPIが有効になっていないため、エラーが返され続けます。
最終的な解決策
根本的な解決策は、gcloud
の「共通の鍵」を使うのをやめ、自分自身のプロジェクトに所属する、自分専用の「鍵(OAuth 2.0 クライアントID)」を作成し、それを使って認証することです。
-
OAuth同意画面を設定する:
Cloudコンソールで、自分のプロジェクト用に認証画面の基本情報(アプリ名など)を設定します。これは、あなた専用の鍵を発行するための前提条件です。 -
OAuth 2.0 クライアントIDを作成する:
同じくCloudコンソールで、「アプリケーションの種類」を「デスクトップアプリ」として、新しいクライアントIDを作成します。作成後、クライアントIDとシークレットが書かれたJSONファイルをダウンロードします。 -
ダウンロードした自分専用の鍵で、再度認証する:
gcloud auth
コマンドに、ダウンロードしたJSONファイルを指定するオプションを追加して実行します。# /path/to/your/client_secret.json の部分を、ダウンロードしたファイルの実際のパスに置き換える gcloud auth application-default login \ --client-id-file=/path/to/your/client_secret.json \ --scopes=https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/drive.readonly
この手順で認証を行うと、認証プロセス全体があなたのプロジェクトに紐付きます。APIサーバー側から見ても、リクエストのConsumerはあなたのプロジェクトだと正しく認識され、認証が通るようになります。
まとめ
やりたいことは単純なはずなのに、小一時間溶かしました。
Discussion