feat(auth): support redirect-uri in manual flows (#398) (thanks @salmonumbrella)

This commit is contained in:
Peter Steinberger 2026-03-08 00:57:49 +00:00
parent 5ea6d607fb
commit efffd2dcd7
3 changed files with 51 additions and 0 deletions

View File

@ -4,6 +4,7 @@
### Added
- Auth: add `--access-token` / `GOG_ACCESS_TOKEN` for direct access-token auth in headless or CI flows, bypassing stored refresh tokens. (#419) — thanks @mmkal.
- Auth: add `auth add --redirect-uri` for manual/remote OAuth flows, so custom callback hosts can be reused across the printed auth URL, state cache, and code exchange. (#398) — thanks @salmonumbrella.
- Sheets: add `sheets insert` to insert rows/columns into a sheet. (#203) — thanks @andybergon.
- Sheets: add `sheets links` (alias `hyperlinks`) to list cell links from ranges, including rich-text links. (#374) — thanks @omothm.
- Sheets: add `sheets create --parent` to place new spreadsheets in a Drive folder. (#424) — thanks @ManManavadaria.

View File

@ -491,6 +491,9 @@ type AuthAddCmd struct {
func formatRemoteStep2Instruction(services []googleauth.Service, c *AuthAddCmd) string {
parts := []string{"--remote", "--step", "2", "--auth-url", "<redirect-url>"}
if redirectURI := strings.TrimSpace(c.RedirectURI); redirectURI != "" {
parts = append(parts, "--redirect-uri", redirectURI)
}
if len(services) > 0 {
serialized := make([]string, 0, len(services))
for _, service := range services {

View File

@ -802,6 +802,53 @@ func TestAuthAddCmd_RemoteStep1_PassesRedirectURI(t *testing.T) {
}
}
func TestAuthAddCmd_RemoteStep1_ReplaysRedirectURIInGuidance(t *testing.T) {
origManualURL := manualAuthURL
origAuth := authorizeGoogle
origKeychain := ensureKeychainAccess
t.Cleanup(func() {
manualAuthURL = origManualURL
authorizeGoogle = origAuth
ensureKeychainAccess = origKeychain
})
manualAuthURL = func(context.Context, googleauth.AuthorizeOptions) (googleauth.ManualAuthURLResult, error) {
return googleauth.ManualAuthURLResult{URL: "https://example.com/auth"}, nil
}
authorizeGoogle = func(context.Context, googleauth.AuthorizeOptions) (string, error) {
t.Fatal("authorizeGoogle should not be called in remote step 1")
return "", nil
}
ensureKeychainAccess = func() error {
t.Fatal("keychain access should not be checked in remote step 1")
return nil
}
stderr := captureStderr(t, func() {
_ = captureStdout(t, func() {
if err := Execute([]string{
"auth",
"add",
"user@example.com",
"--services",
"gmail",
"--remote",
"--step",
"1",
"--redirect-uri",
"https://molty2.tail8108.ts.net/oauth2/callback",
}); err != nil {
t.Fatalf("Execute: %v", err)
}
})
})
want := "--remote --step 2 --auth-url <redirect-url> --redirect-uri https://molty2.tail8108.ts.net/oauth2/callback --services gmail"
if !strings.Contains(stderr, want) {
t.Fatalf("expected replay guidance %q, got %q", want, stderr)
}
}
func TestAuthAddCmd_RemoteStep2_RejectsAuthCode(t *testing.T) {
err := Execute([]string{
"auth",