Skip to content

Commit 2822e63

Browse files
authored
Fix Claude OAuth dedup for multi-org accounts (#20)
1 parent f311871 commit 2822e63

5 files changed

Lines changed: 599 additions & 49 deletions

File tree

src/auth/claude/mod.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,73 @@ mod tests {
498498
assert!(!ps.exists(Tool::Claude, "alias"));
499499
}
500500

501+
#[test]
502+
#[cfg(all(unix, not(target_os = "macos")))]
503+
fn oauth_duplicate_identity_allows_same_email_with_different_org() {
504+
let _g = crate::SPAWN_LOCK.lock().unwrap_or_else(|p| p.into_inner());
505+
let _storage = EnvVarGuard::set("AISW_CLAUDE_AUTH_STORAGE", "file");
506+
use std::fs;
507+
use std::os::unix::fs::PermissionsExt;
508+
509+
let dir = tempdir().unwrap();
510+
let home = dir.path().join("home");
511+
let bin_dir = dir.path().join("bin");
512+
fs::create_dir_all(&home).unwrap();
513+
fs::create_dir_all(&bin_dir).unwrap();
514+
let _home = EnvVarGuard::set("HOME", &home);
515+
let bin = bin_dir.join("claude");
516+
fs::write(
517+
&bin,
518+
"#!/bin/sh\n\
519+
mkdir -p \"$HOME/.claude\"\n\
520+
printf '%s' '{\"oauthToken\":\"tok\",\"account\":{\"email\":\"burak@example.com\"}}' > \"$HOME/.claude/.credentials.json\"\n\
521+
printf '%s' '{\"oauthAccount\":{\"emailAddress\":\"burak@example.com\",\"organizationUuid\":\"org-b\"}}' > \"$HOME/.claude.json\"\n",
522+
)
523+
.unwrap();
524+
fs::set_permissions(&bin, fs::Permissions::from_mode(0o755)).unwrap();
525+
526+
let (ps, cs) = stores(dir.path());
527+
ps.create(Tool::Claude, "work").unwrap();
528+
ps.write_file(
529+
Tool::Claude,
530+
"work",
531+
CREDENTIALS_FILE,
532+
br#"{"oauthToken":"tok","account":{"email":"burak@example.com"}}"#,
533+
)
534+
.unwrap();
535+
ps.write_file(
536+
Tool::Claude,
537+
"work",
538+
OAUTH_ACCOUNT_FILE,
539+
br#"{"emailAddress":"burak@example.com","organizationUuid":"org-a"}"#,
540+
)
541+
.unwrap();
542+
cs.add_profile(
543+
Tool::Claude,
544+
"work",
545+
ProfileMeta {
546+
added_at: Utc::now(),
547+
auth_method: AuthMethod::OAuth,
548+
credential_backend: CredentialBackend::File,
549+
label: None,
550+
},
551+
)
552+
.unwrap();
553+
554+
oauth::add_oauth_with(
555+
&ps,
556+
&cs,
557+
"alias",
558+
None,
559+
&bin,
560+
std::time::Duration::from_secs(2),
561+
TEST_POLL,
562+
)
563+
.unwrap();
564+
565+
assert!(ps.exists(Tool::Claude, "alias"));
566+
}
567+
501568
#[test]
502569
#[cfg(all(unix, not(target_os = "macos")))]
503570
fn oauth_flow_errors_when_claude_exits_without_credentials() {

0 commit comments

Comments
 (0)