Last active
October 3, 2025 09:17
-
-
Save affix/0f37f44a82488ec4137de9a9a62c14c7 to your computer and use it in GitHub Desktop.
A greesemonkey/tampermonkey/*monkey script to automatically login to github orgs using SSO
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 Github Auto SSO | |
| // @namespace Violentmonkey Scripts | |
| // @match https://github.com/* | |
| // @grant none | |
| // @version 2.0.0 | |
| // @author Keiran Smith <opensource@keiran.scot> | |
| // @description Automatically login to mutiple orgs in Github | |
| // ==/UserScript== | |
| (function () { | |
| 'use strict'; | |
| const selectors = [ | |
| '[partial-name*="global-sso-banner"] button', // fallback, just in case | |
| ]; | |
| function findTarget() { | |
| for (const sel of selectors) { | |
| const el = document.querySelector(sel); | |
| if (el) return el; | |
| } | |
| return null; | |
| } | |
| function clickLikeAHuman(el) { | |
| const rect = el.getBoundingClientRect(); | |
| const x = rect.left + Math.min(10, rect.width / 2); | |
| const y = rect.top + Math.min(10, rect.height / 2); | |
| const base = { bubbles: true, cancelable: true, composed: true, view: window, clientX: x, clientY: y }; | |
| el.scrollIntoView({ block: 'center', inline: 'center' }); | |
| if (typeof el.focus === 'function') el.focus({ preventScroll: true }); | |
| try { el.dispatchEvent(new PointerEvent('pointerdown', { ...base, pointerId: 1, isPrimary: true })); } catch {} | |
| el.dispatchEvent(new MouseEvent('mousedown', base)); | |
| try { el.dispatchEvent(new PointerEvent('pointerup', { ...base, pointerId: 1, isPrimary: true })); } catch {} | |
| el.dispatchEvent(new MouseEvent('mouseup', base)); | |
| el.dispatchEvent(new MouseEvent('click', base)); | |
| } | |
| let done = false; | |
| function tryClick() { | |
| if (done) return; | |
| const el = findTarget(); | |
| if (el && !el.disabled) { | |
| console.log('[AutoSSO] clicking:', el.tagName, el.textContent.trim()); | |
| clickLikeAHuman(el); | |
| done = true; | |
| disconnectAll(); | |
| } | |
| } | |
| const observers = []; | |
| function observe(doc) { | |
| const obs = new MutationObserver(tryClick); | |
| obs.observe(doc, { childList: true, subtree: true }); | |
| observers.push(obs); | |
| } | |
| function disconnectAll() { observers.forEach(o => o.disconnect()); } | |
| tryClick(); | |
| observe(document); | |
| window.addEventListener('pjax:end', () => { done = false; tryClick(); }); | |
| window.addEventListener('turbo:load', () => { done = false; tryClick(); }); | |
| window.addEventListener('turbo:render', () => { done = false; tryClick(); }); | |
| const start = Date.now(); | |
| const interval = setInterval(() => { | |
| if (done || Date.now() - start > 15000) { clearInterval(interval); return; } | |
| tryClick(); | |
| }, 400); | |
| })(); | |
| (function () { | |
| 'use strict'; | |
| console.log("[AutoSSO] Finding Links"); | |
| const selector = 'a[role="menuitem"][href^="/orgs/"][href*="/sso"]'; | |
| let done = false; | |
| function clickAll() { | |
| const links = document.querySelectorAll(selector); | |
| links.forEach(link => { | |
| if (!link.dataset._autoClicked) { | |
| console.log('[AutoSSO] clicking org link:', link.href); | |
| link.dataset._autoClicked = "true"; | |
| link.click(); | |
| return; | |
| } | |
| }); | |
| } | |
| const observer = new MutationObserver(clickAll); | |
| observer.observe(document.body, { childList: true, subtree: true }); | |
| clickAll(); | |
| window.addEventListener('pjax:end', clickAll); | |
| window.addEventListener('turbo:load', clickAll); | |
| window.addEventListener('turbo:render', clickAll); | |
| const start = Date.now(); | |
| const interval = setInterval(() => { | |
| if (done || Date.now() - start > 15000) { clearInterval(interval); return; } | |
| clickAll(); | |
| }, 400); | |
| })(); | |
| var isSSOPage = window.location.href.indexOf("sso") > 0 | |
| if(isSSOPage) { | |
| document.querySelector(".btn-primary").click(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment