From 20e142d5947540b8991835bc1101fbfb8eb39a07 Mon Sep 17 00:00:00 2001 From: "guys-inc-ops[bot]" <321481384+guys-inc-ops[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2026 00:04:20 +0000 Subject: [PATCH] Show the device code in the sign-in dialog Sign-in is broken in 3.5.0 for anyone who signs in from inside the app. The browser opens to github.com/login/device, which asks for a code, and the application never shows one. There are two sign-in surfaces. The welcome flow renders through ui/lib/sign-in.tsx and AuthenticationForm, which #26 taught to display the code. The dialog - the one reached by re-authenticating, which is what happens when a token is invalidated - renders through ui/sign-in/sign-in.tsx and was missed. It ignored state.deviceFlow entirely and printed the old copy promising a redirect back to GitHub Desktop, which no longer happens. A user's log shows it exactly: "initializing OAuth device flow", then "opening in browser: https://github.com/login/device", then nothing until the abandoned poll dies minutes later. The request was always fine. The code was fetched, stored in state, and never rendered. Visible in the published bundle: "device-flow-user-code" and "Enter this code at" each appear once, for the welcome flow, and the dialog's misleading redirect sentence appears alongside them. After this change they appear twice and the redirect sentence is gone, confirmed by building. The styles were scoped to .sign-in-form, the welcome form's class, so even once the dialog rendered the code it would have been unstyled. They are now unscoped, because the code is shown from two places. The standing copy is also corrected where it still described the redirect flow, including on the existing-account warning step that reuses it. --- app/src/ui/sign-in/sign-in.tsx | 25 +++++++++++++++++---- app/styles/ui/_device-flow.scss | 40 +++++++++++++++++---------------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/app/src/ui/sign-in/sign-in.tsx b/app/src/ui/sign-in/sign-in.tsx index d9ab5d2d54..ffc2306487 100644 --- a/app/src/ui/sign-in/sign-in.tsx +++ b/app/src/ui/sign-in/sign-in.tsx @@ -36,9 +36,8 @@ const DefaultTitle = 'Sign in' const browserSignInInfoContent = (

- Your browser will redirect you back to GitHub Desktop once you've signed in. - If your browser asks for your permission to launch GitHub Desktop, please - allow it. + Your browser will open so you can approve this sign-in. Come back here for + the code you'll need to enter.

) @@ -188,10 +187,28 @@ export class SignIn extends React.Component {

) : undefined + // Sign in is the OAuth device flow: the user has to type a short code into + // their browser, so this is the one place it can be read from. Until the + // code arrives there is nothing to show but what is about to happen. + const { deviceFlow } = state + return ( {credentialHelperInfo} - {browserSignInInfoContent} + {deviceFlow ? ( + <> +

+ Enter this code at {deviceFlow.verificationURI} to + finish signing in. Keep this window open — it'll continue + automatically once you approve. +

+
+ {deviceFlow.userCode} +
+ + ) : ( + browserSignInInfoContent + )}
) } diff --git a/app/styles/ui/_device-flow.scss b/app/styles/ui/_device-flow.scss index 6979cf82c0..fe5ea2bda2 100644 --- a/app/styles/ui/_device-flow.scss +++ b/app/styles/ui/_device-flow.scss @@ -1,27 +1,29 @@ // Sign in uses the OAuth device flow: the user is shown a short code to type // into their browser. The code has to be effortless to read and transcribe, so // it gets a monospace face, generous tracking and a lot of size. -.sign-in-form { - .device-flow-instructions { - margin-bottom: var(--spacing); - color: var(--text-secondary-color); - } +// +// Deliberately not scoped to a container. The code is shown from two places - +// the welcome flow's form and the sign-in dialog - and scoping this to the +// first is what left the second with no styles for it at all. +.device-flow-instructions { + margin-bottom: var(--spacing); + color: var(--text-secondary-color); +} - .device-flow-user-code { - font-family: var(--font-family-monospace); - font-size: var(--font-size-xl); - font-weight: var(--font-weight-semibold); +.device-flow-user-code { + font-family: var(--font-family-monospace); + font-size: var(--font-size-xl); + font-weight: var(--font-weight-semibold); - // Digits and letters are easy to confuse when they're packed together. - letter-spacing: 0.2em; - text-align: center; - user-select: text; + // Digits and letters are easy to confuse when they're packed together. + letter-spacing: 0.2em; + text-align: center; + user-select: text; - padding: var(--spacing) var(--spacing-double); - margin-bottom: var(--spacing-double); + padding: var(--spacing) var(--spacing-double); + margin-bottom: var(--spacing-double); - border: var(--base-border); - border-radius: var(--border-radius); - background: var(--box-alt-background-color, var(--box-background-color)); - } + border: var(--base-border); + border-radius: var(--border-radius); + background: var(--box-alt-background-color, var(--box-background-color)); }