勝手に開いたブラウザが、別人のままログインを成功させた

Claudeで執筆しました

副業のある案件で、Google Apps Script(以下GAS)をGit管理に載せようとしていました。

それまでは、ブラウザのエディタにコードを手で貼っていたんです。 これがまた事故る。 長いコメント行を貼ると、エディタが親切に「次の行もコメントですよね?」と勝手に続けてくれて、コードが静かに壊れる(ありがとう、余計なお世話です) なので、claspという公式CLIでローカルからpushできるようにしたい。健全な話です。

健全なはずでした。 clasp loginを叩くまでは。

壁その1: パスキー本人確認は、人間の指を要求してくる

まず、作業用のアカウントは会社ドメイン(Google Workspace)です。 サインインの途中でパスキー本人確認が挟まる。 Touch IDを、人間が、押す。

ここは潔く諦めました。 自動化エージェントに指はありません(悲しいけど事実) 「ここだけは人にお願いする」と割り切って、本人にTouch IDを通してもらう。 これで終わると思っていたんです。

壁その2: 気づいたら、別人としてログインが「成功」していた

パスキーは通った。ログイン処理も走った。 ログを覗いたら、こう書いてありました。

「You are logged in as ○○(個人用アカウント)」

……誰? 入れたかったのは作業用アカウントです。 なのに、普段使いのブラウザにログイン済みだった個人用アカウントで、しれっとログインが成立していた。

エラーなら気づきます。赤い字が出るので。 でもこれは「成功」なんです。緑のチェックがついている。 一番タチが悪いやつでした。

なぜ、頼んでもいないブラウザが仕事をしたのか

原因はレース(競争)でした。

claspのログインは、こういう仕組みで動きます。

  • 手元に小さなサーバをこっそり立てる(localhostの適当なポート)
  • ブラウザでGoogleの同意画面を開かせる
  • 同意すると、Googleが「認証コード」を付けて手元のサーバに送り返してくる
  • サーバがそのコードを受け取って、トークンに交換する

問題は、この「ブラウザで開かせる」を、claspが既定ブラウザで勝手にやるところ。 自分は作業用アカウントで入れたくて、自動化用のブラウザで同意画面を操作していました。 ところが裏で、普段使いのブラウザが同じURLを勝手に開き、そこにログイン済みだった個人用アカウントで先に同意を完了させてしまった。

サーバは「最初に届いたコード」を掴みます。 どのブラウザから来たかなんて、区別しません。 早い者勝ち。そして負けたのは自分でした(自分が用意したブラウザなのに)

直し方: 競争そのものを消す

やったことは2つです。

まずclasp logout。間違ったアカウントの認証情報を消す。 そして今度は--no-localhostモードでログインする。

このモードは、clasp側にサーバを持たせません。 代わりに「同意したら、ブラウザのアドレスバーのURLをここに貼ってね」と待つ。 つまり、どのブラウザで通したコードを採用するかを、自分が指名できる。 既定ブラウザが裏で何をしようが、自分が貼らない限り関係ない。 早い者勝ちの土俵から降りる、という発想です。

……で、ここでもう一段こけました。

--no-localhostのリダイレクト先は、サーバのないlocalhost。 当然「このサイトにアクセスできません」のエラー画面になる。 そのエラー画面のアドレスバーに、欲しいコードは載っている。 なのに、エラー画面からはプログラムでURLを読み取れないんです(ブラウザの仕様上、詰んでいる)

なので最後は、自分でそのポートに小さなキャプチャ用サーバを立てました。 意図したブラウザ(作業用アカウント)でOAuthを通す。 リダイレクトが、今度は「ちゃんと待っている」自前サーバに届く。 コードをサーバ側で確実に拾って、claspに流し込む。

ログにこう出て、やっと終わりました。

「You are logged in as ○○(作業用アカウント)」

今度は、ちゃんと本人でした。

学び(同じ轍を踏みたくない人へ)

  • OAuthのlocalhostフローを自動化するときは「どのブラウザが先にリダイレクトを掴むか」を制御する。既定ブラウザの自動起動は、善意で横入りしてくる。
  • --no-localhost + 自前のキャプチャサーバで、採用するアカウントを自分の意図どおりに固定できる。競争を消すのが一番速い。
  • パスキーは人間の壁。ここは自動化を諦めて人に渡すのが正解(無理に突破しようとしない)
  • CLIツールは「1マシン=1ログイン」をグローバルに1つだけ持っていることが多い。複数アカウントを扱う現場では、着手前に「今どのアカウントで入っているか」を確認する癖が要ります。

ログインの自動化で本当に怖いのは、赤い失敗じゃない。緑の「成功」です。 それが誰の成功なのか、毎回ちゃんと見てあげてください。