In Chapter 2: Interactive Setup UI, we built a beautiful interface that shows a "Checking login statusβ¦" spinner. But currently, that spinner is just for show. It doesn't actually do anything.
How do we actually check if the user is logged into GitHub? And how do we get their credentials without making them copy-paste long, secret codes?
Imagine you are at a fancy hotel. You want the valet to park your car.
Most developers already have the GitHub CLI (gh) installed and logged in on their computer. This tool holds the "keys" to their GitHub account.
Instead of asking the user to generate a new key, our application acts like the Valet. It asks the local gh tool: "Hey, are you logged in? Can I borrow the token?"
This chapter explains how our Node.js application talks to other software installed on your computer.
Node.js is great, but it doesn't know how to talk to GitHub natively. However, it can hire a "subcontractor." We use a library called execa to run terminal commands (like gh auth status) from inside our code, just as if you typed them yourself.
stdout)When you run a command in your terminal, it prints text to the screen. This is called Standard Output. When our code runs the command, it "captures" this text into a string variable so we can read it.
We need a function that bridges the gap between our React UI (Chapter 2) and the System Tools (GitHub CLI).
We are implementing the logic inside checkLoginState in remote-setup.tsx.
We use execa to run commands. It takes the command name and a list of arguments.
import { execa } from 'execa';
// This runs: gh auth token
const { stdout } = await execa('gh', ['auth', 'token']);
gh auth token.stdout now contains the secret token string.
Before we ask for the token, we should check if the tool is even installed. We use a helper getGhAuthStatus.
import { getGhAuthStatus } from '../../utils/github/ghAuthStatus.js';
const ghStatus = await getGhAuthStatus();
if (ghStatus === 'not_installed') {
return { status: 'gh_not_installed' };
}
Terminal output often has invisible characters (like newlines) at the end. We must clean it up.
// stdout might be "gho_123xyz\n"
const tokenString = stdout.trim();
// Now it is "gho_123xyz"
What actually happens when the "Checking..." spinner spins? It's a relay race.
gh).
Let's look at the real code in remote-setup.tsx. This function performs the critical security handshake.
We verify the user's status in layers. If any layer fails, we stop early.
async function checkLoginState(): Promise<CheckResult> {
// 1. First, check if installed and authenticated generically
const ghStatus = await getGhAuthStatus();
if (ghStatus === 'not_installed') {
return { status: 'gh_not_installed' };
}
// ... check for 'not_authenticated' ...
This is the most critical part. We use specific settings in execa to ensure the token is read securely and not printed to the user's screen by accident.
// 2. If we are authenticated, get the actual token
const { stdout } = await execa('gh', ['auth', 'token'], {
stdout: 'pipe', // Capture output so we can read it
stderr: 'ignore', // Don't let errors leak to the console
timeout: 5000, // Don't wait forever if it hangs
reject: false // Don't crash if it fails
});
stdout: 'pipe': This directs the output into our variable, not the terminal screen.stderr: 'ignore': If gh complains, we ignore it to keep our UI clean.Finally, we wrap the raw string in a special object.
const trimmed = stdout.trim();
if (!trimmed) {
// Even if status said yes, if the token is empty, we fail.
return { status: 'gh_not_authenticated' };
}
// Success!
return {
status: 'has_gh_token',
token: new RedactedGithubToken(trimmed)
};
RedactedGithubToken: You might be wondering what this class is. We just grabbed a very sensitive secret (the OAuth token). We never want to accidentally print this to a log file or error message.We have successfully bridged the gap between our application and the user's local tools!
But now we are holding a "live grenade"βa raw access token. If we console.log this by mistake, it could end up in a log file that gets shared. How do we ensure this token remains safe while it travels through our app?
Next Chapter: Redacted Token Security
Generated by Code IQ