Last active
October 2, 2026 08:41
-
-
Save warrenseine/70e9d9725091be4d532b4c45e6fb9ba8 to your computer and use it in GitHub Desktop.
Approve gcloud sign-in
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Approve gcloud sign-in | |
| // @namespace http://tampermonkey.net/ | |
| // @version 2026-10-02 | |
| // @description Click through the Google passkey and consent screens for gcloud and application-default credentials | |
| // @author Warren Seine | |
| // @match https://accounts.google.com/signin/oauth/* | |
| // @match https://accounts.google.com/v3/signin/challenge/pk/* | |
| // @icon https://www.google.com/s2/favicons?sz=64&domain=cloud.google.com | |
| // @run-at document-idle | |
| // @grant none | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // Only the Google-owned clients that `gcloud auth login` and | |
| // `gcloud auth application-default login` sign in with. Any other app keeps | |
| // its consent screen: approving one blindly is how consent phishing works. | |
| const TRUSTED_CLIENTS = new Set([ | |
| // Google Cloud SDK | |
| '32555940559.apps.googleusercontent.com', | |
| // Google Auth Library (application-default credentials) | |
| '764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com', | |
| ]); | |
| // "Allow" grants the listed scopes; "Continue" confirms a client that already | |
| // holds some of them, or starts the passkey prompt. | |
| const APPROVE = new Set(['Allow', 'Continue']); | |
| // The consent page renders its buttons after load. Give up rather than click | |
| // on a page that has been sitting open. | |
| const TIMEOUT = 15000; | |
| // No client in the URL means the page cannot be attributed, so nothing is | |
| // clicked. | |
| function clientId() { | |
| const params = new URLSearchParams(document.location.search); | |
| if (params.has('client_id')) return params.get('client_id'); | |
| // Google sometimes asks for a passkey before the consent screen. That page | |
| // names no client itself, but carries the consent URL as its continue link. | |
| try { | |
| const next = new URL(params.get('continue')); | |
| if (next.origin === 'https://accounts.google.com' && next.pathname.startsWith('/signin/oauth/')) { | |
| return next.searchParams.get('client_id'); | |
| } | |
| } catch (error) { | |
| /* no continue link */ | |
| } | |
| return null; | |
| } | |
| if (!TRUSTED_CLIENTS.has(clientId())) return; | |
| const since = Date.now(); | |
| function approve() { | |
| const button = [...document.querySelectorAll('button')] | |
| .find(b => APPROVE.has(b.textContent.trim())); | |
| if (button) { | |
| clearInterval(poll); | |
| button.click(); | |
| } else if (Date.now() - since > TIMEOUT) { | |
| clearInterval(poll); | |
| } | |
| } | |
| const poll = setInterval(approve, 300); | |
| approve(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment