axauth 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -84
- package/dist/auth/adapter.d.ts +27 -13
- package/dist/auth/agents/claude-code-storage.js +1 -2
- package/dist/auth/agents/claude-code.js +13 -9
- package/dist/auth/agents/codex-config.js +1 -1
- package/dist/auth/agents/codex.js +14 -12
- package/dist/auth/agents/copilot-storage.js +1 -2
- package/dist/auth/agents/copilot.js +13 -9
- package/dist/auth/agents/gemini-auth-check.d.ts +3 -3
- package/dist/auth/agents/gemini-auth-check.js +32 -45
- package/dist/auth/agents/gemini-storage.d.ts +2 -4
- package/dist/auth/agents/gemini-storage.js +4 -12
- package/dist/auth/agents/gemini.js +28 -16
- package/dist/auth/agents/opencode-schema.d.ts +24 -0
- package/dist/auth/agents/opencode-schema.js +42 -0
- package/dist/auth/agents/opencode.js +29 -10
- package/dist/auth/registry.d.ts +45 -8
- package/dist/auth/registry.js +90 -7
- package/dist/auth/resolve-config-directory.d.ts +11 -7
- package/dist/auth/resolve-config-directory.js +12 -8
- package/dist/auth/types.d.ts +26 -8
- package/dist/auth/types.js +20 -1
- package/dist/cli.js +17 -4
- package/dist/commands/auth.d.ts +4 -11
- package/dist/commands/auth.js +12 -74
- package/dist/commands/install-credentials.d.ts +15 -0
- package/dist/commands/install-credentials.js +76 -0
- package/dist/commands/validate-agent.d.ts +14 -0
- package/dist/commands/validate-agent.js +22 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,46 +1,35 @@
|
|
|
1
1
|
# axauth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Unified authentication management for AI coding agents.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
axauth
|
|
7
|
+
axauth provides a consistent interface for managing credentials across multiple AI coding agent CLIs. It abstracts away the differences between agent-specific credential storage mechanisms (macOS Keychain, file-based storage, environment variables) and provides:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
- **Auth status detection** - Check which agents are authenticated and via which method
|
|
10
|
+
- **Credential extraction** - Extract tokens for API calls or export/import workflows
|
|
11
|
+
- **Portable credential export** - Encrypted credential files for CI/CD and backup
|
|
12
|
+
- **Multi-storage support** - Keychain (macOS), file storage, and environment variables
|
|
11
13
|
|
|
12
14
|
## Supported Agents
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
| Agent | CLI | Provider | Auth Methods |
|
|
17
|
+
| ----------- | ---------- | --------- | ------------------------------------------ |
|
|
18
|
+
| Claude Code | `claude` | Anthropic | OAuth (keychain/file), `ANTHROPIC_API_KEY` |
|
|
19
|
+
| Codex CLI | `codex` | OpenAI | ChatGPT OAuth, `OPENAI_API_KEY` |
|
|
20
|
+
| Gemini CLI | `gemini` | Google | OAuth, `GEMINI_API_KEY` |
|
|
21
|
+
| OpenCode | `opencode` | Sst | Multi-provider OAuth |
|
|
22
|
+
| Copilot CLI | `copilot` | GitHub | OAuth, `GH_TOKEN`/`GITHUB_TOKEN` |
|
|
18
23
|
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
import { checkAuth, getAgentAccessToken, extractCredentials } from "axauth";
|
|
23
|
-
|
|
24
|
-
// Check auth status for an agent
|
|
25
|
-
const status = checkAuth("claude-code");
|
|
26
|
-
if (status.authenticated) {
|
|
27
|
-
console.log(`Authenticated via ${status.method}`);
|
|
28
|
-
}
|
|
24
|
+
## Installation
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Extract full credentials for export
|
|
37
|
-
const creds = extractCredentials("claude-code");
|
|
38
|
-
if (creds) {
|
|
39
|
-
// creds.accessToken, creds.refreshToken, etc.
|
|
40
|
-
}
|
|
26
|
+
```bash
|
|
27
|
+
npm install axauth
|
|
28
|
+
# or
|
|
29
|
+
pnpm add axauth
|
|
41
30
|
```
|
|
42
31
|
|
|
43
|
-
## CLI
|
|
32
|
+
## CLI Usage
|
|
44
33
|
|
|
45
34
|
```bash
|
|
46
35
|
# List agents and their auth status
|
|
@@ -48,29 +37,31 @@ axauth list
|
|
|
48
37
|
axauth list --json
|
|
49
38
|
|
|
50
39
|
# Get access token for an agent (outputs raw token for piping)
|
|
51
|
-
axauth token --agent claude
|
|
40
|
+
axauth token --agent claude
|
|
52
41
|
|
|
53
42
|
# Export credentials to encrypted file
|
|
54
|
-
axauth export --agent claude
|
|
55
|
-
axauth export --agent claude
|
|
56
|
-
|
|
57
|
-
# Remove credentials (agent will prompt for login)
|
|
58
|
-
axauth remove-credentials --agent claude-code
|
|
43
|
+
axauth export --agent claude --output creds.json
|
|
44
|
+
axauth export --agent claude --output creds.json --no-password
|
|
59
45
|
|
|
60
46
|
# Install credentials from exported file
|
|
61
|
-
axauth install-credentials --agent claude
|
|
47
|
+
axauth install-credentials --agent claude --input creds.json
|
|
48
|
+
axauth install-credentials --agent claude --input creds.json --config-dir /tmp/config
|
|
49
|
+
|
|
50
|
+
# Remove credentials (agent will prompt for login on next use)
|
|
51
|
+
axauth remove-credentials --agent claude
|
|
52
|
+
axauth remove-credentials --agent claude --config-dir /tmp/config
|
|
62
53
|
```
|
|
63
54
|
|
|
64
|
-
|
|
55
|
+
### Pipeline Examples
|
|
65
56
|
|
|
66
57
|
The CLI outputs TSV format for easy processing with standard Unix tools:
|
|
67
58
|
|
|
68
59
|
```bash
|
|
69
60
|
# List all agents and their auth status
|
|
70
61
|
axauth list
|
|
71
|
-
# AGENT
|
|
72
|
-
# claude
|
|
73
|
-
# codex
|
|
62
|
+
# AGENT STATUS METHOD
|
|
63
|
+
# claude authenticated OAuth (max)
|
|
64
|
+
# codex authenticated ChatGPT OAuth
|
|
74
65
|
# ...
|
|
75
66
|
|
|
76
67
|
# Filter to show only authenticated agents
|
|
@@ -79,68 +70,194 @@ axauth list | tail -n +2 | awk -F'\t' '$2 == "authenticated"'
|
|
|
79
70
|
# Count agents by status
|
|
80
71
|
axauth list | tail -n +2 | cut -f2 | sort | uniq -c
|
|
81
72
|
|
|
82
|
-
# Extract agent names as a list
|
|
83
|
-
axauth list | tail -n +2 | cut -f1
|
|
84
|
-
|
|
85
73
|
# Check if a specific agent is authenticated
|
|
86
|
-
axauth list --json | jq -e '.[] | select(.agentId == "claude
|
|
74
|
+
axauth list --json | jq -e '.[] | select(.agentId == "claude") | .authenticated'
|
|
87
75
|
|
|
88
|
-
#
|
|
89
|
-
curl -s -H "Authorization: Bearer $(axauth token --agent claude
|
|
76
|
+
# Use token with curl
|
|
77
|
+
curl -s -H "Authorization: Bearer $(axauth token --agent claude)" \
|
|
90
78
|
-H "anthropic-beta: oauth-2025-04-20" \
|
|
91
79
|
https://api.anthropic.com/api/oauth/usage | jq .
|
|
92
80
|
```
|
|
93
81
|
|
|
94
|
-
##
|
|
82
|
+
## Library API
|
|
95
83
|
|
|
84
|
+
```typescript
|
|
85
|
+
import {
|
|
86
|
+
// Core operations
|
|
87
|
+
checkAuth, // Check single agent auth status
|
|
88
|
+
checkAllAuth, // Check all agents' auth status
|
|
89
|
+
getAgentAccessToken, // Get access token for an agent
|
|
90
|
+
extractRawCredentials, // Extract full credentials for export
|
|
91
|
+
installCredentials, // Install credentials to storage
|
|
92
|
+
removeCredentials, // Remove credentials from storage
|
|
93
|
+
|
|
94
|
+
// Credential utilities
|
|
95
|
+
getAccessToken, // Extract token from credential object
|
|
96
|
+
credentialsToEnvironment, // Convert credentials to env vars
|
|
97
|
+
getCredentialsEnvironmentVariableName, // Get AX_*_CREDENTIALS var name
|
|
98
|
+
installCredentialsFromEnvironmentVariable, // Install from env var (CI/CD)
|
|
99
|
+
|
|
100
|
+
// Adapter access
|
|
101
|
+
getAdapter, // Get adapter for an agent
|
|
102
|
+
getAllAdapters, // Get all adapters
|
|
103
|
+
getCapabilities, // Check adapter capabilities
|
|
104
|
+
} from "axauth";
|
|
105
|
+
|
|
106
|
+
// Types
|
|
107
|
+
import type {
|
|
108
|
+
AgentCli, // "claude" | "codex" | "gemini" | "opencode" | "copilot"
|
|
109
|
+
AuthStatus, // { agentId, authenticated, method?, details? }
|
|
110
|
+
Credentials, // { agent, type, data }
|
|
111
|
+
AuthAdapter, // Adapter interface
|
|
112
|
+
AdapterCapabilities, // { keychain, file, environment, installApiKey }
|
|
113
|
+
} from "axauth";
|
|
96
114
|
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
|
|
116
|
+
### Examples
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { checkAuth, getAgentAccessToken, getCapabilities } from "axauth";
|
|
120
|
+
|
|
121
|
+
// Check auth status for an agent
|
|
122
|
+
const status = checkAuth("claude");
|
|
123
|
+
if (status.authenticated) {
|
|
124
|
+
console.log(`Authenticated via ${status.method}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Get access token for API calls
|
|
128
|
+
const token = getAgentAccessToken("claude");
|
|
129
|
+
if (token) {
|
|
130
|
+
// Use token for API calls
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Check adapter capabilities
|
|
134
|
+
const caps = getCapabilities("gemini");
|
|
135
|
+
if (!caps.keychain) {
|
|
136
|
+
console.log("Gemini requires file storage on this platform");
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Adapter Pattern
|
|
141
|
+
|
|
142
|
+
Each agent implements the `AuthAdapter` interface, hiding storage complexity:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { getAdapter } from "axauth";
|
|
146
|
+
|
|
147
|
+
const adapter = getAdapter("claude");
|
|
148
|
+
|
|
149
|
+
// All adapters have the same interface
|
|
150
|
+
const status = adapter.checkAuth();
|
|
151
|
+
const creds = adapter.extractRawCredentials();
|
|
152
|
+
const token = adapter.getAccessToken(creds);
|
|
153
|
+
const envVars = adapter.credentialsToEnvironment(creds);
|
|
154
|
+
|
|
155
|
+
// Check what the adapter supports
|
|
156
|
+
console.log(adapter.capabilities);
|
|
157
|
+
// { keychain: true, file: true, environment: true, installApiKey: false }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Adapter Capabilities
|
|
161
|
+
|
|
162
|
+
Each agent adapter declares its storage capabilities:
|
|
163
|
+
|
|
164
|
+
| Agent | Keychain | File | Environment | Install API Key |
|
|
165
|
+
| -------- | :------: | :--: | :---------: | :-------------: |
|
|
166
|
+
| claude | macOS | Yes | Yes | No (env-only) |
|
|
167
|
+
| codex | macOS | Yes | Yes | No (env-only) |
|
|
168
|
+
| gemini | macOS | Yes | Yes | No (env-only) |
|
|
169
|
+
| opencode | No | Yes | Yes | No |
|
|
170
|
+
| copilot | macOS | Yes | Yes | No (env-only) |
|
|
171
|
+
|
|
172
|
+
**Notes:**
|
|
173
|
+
|
|
174
|
+
- **Keychain**: macOS Keychain support (not available on Linux/Windows)
|
|
175
|
+
- **File**: File-based credential storage
|
|
176
|
+
- **Environment**: Can read credentials from environment variables
|
|
177
|
+
- **Install API Key**: Whether API keys can be installed (vs. read from env only)
|
|
178
|
+
|
|
179
|
+
## Credential Export Format
|
|
180
|
+
|
|
181
|
+
Exported credentials are encrypted with AES-256-GCM:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"version": 1,
|
|
186
|
+
"agent": "claude",
|
|
187
|
+
"ciphertext": "<base64>",
|
|
188
|
+
"salt": "<base64>",
|
|
189
|
+
"iv": "<base64>",
|
|
190
|
+
"tag": "<base64>"
|
|
191
|
+
}
|
|
117
192
|
```
|
|
118
193
|
|
|
119
|
-
|
|
194
|
+
- Key derivation: PBKDF2 with SHA-256, 100,000 iterations
|
|
195
|
+
- Use `--no-password` for CI/CD (uses a default password)
|
|
196
|
+
- Files are written with `0o600` permissions
|
|
197
|
+
|
|
198
|
+
## Environment Variables
|
|
199
|
+
|
|
200
|
+
For CI/CD workflows, credentials can be passed via environment variables:
|
|
201
|
+
|
|
202
|
+
| Agent | Credential Env Var |
|
|
203
|
+
| -------- | ------------------------- |
|
|
204
|
+
| claude | `AX_CLAUDE_CREDENTIALS` |
|
|
205
|
+
| codex | `AX_CODEX_CREDENTIALS` |
|
|
206
|
+
| gemini | `AX_GEMINI_CREDENTIALS` |
|
|
207
|
+
| copilot | `AX_COPILOT_CREDENTIALS` |
|
|
208
|
+
| opencode | `AX_OPENCODE_CREDENTIALS` |
|
|
209
|
+
|
|
210
|
+
Use `installCredentialsFromEnvironmentVariable()` to install credentials from these variables programmatically.
|
|
120
211
|
|
|
121
|
-
|
|
122
|
-
| ----------- | ------------------------------------------ |
|
|
123
|
-
| claude-code | OAuth (keychain/file) or ANTHROPIC_API_KEY |
|
|
124
|
-
| codex | ChatGPT OAuth or OPENAI_API_KEY |
|
|
125
|
-
| gemini | OAuth or GEMINI_API_KEY |
|
|
126
|
-
| opencode | Multi-provider OAuth |
|
|
212
|
+
## Config Directory Requirements
|
|
127
213
|
|
|
128
|
-
|
|
214
|
+
Some agents require specific directory name suffixes:
|
|
129
215
|
|
|
130
|
-
|
|
216
|
+
| Agent | Directory Requirement | Example |
|
|
217
|
+
| -------- | ------------------------ | -------------------- |
|
|
218
|
+
| claude | Any name | `/tmp/my-config` |
|
|
219
|
+
| codex | Any name | `/tmp/my-config` |
|
|
220
|
+
| gemini | Must end with `.gemini` | `/tmp/home/.gemini` |
|
|
221
|
+
| copilot | Must end with `.copilot` | `/tmp/home/.copilot` |
|
|
222
|
+
| opencode | Must end with `opencode` | `/tmp/data/opencode` |
|
|
131
223
|
|
|
132
|
-
|
|
133
|
-
# Rule: `axauth` Usage
|
|
224
|
+
## Architecture
|
|
134
225
|
|
|
135
|
-
|
|
226
|
+
axauth follows the adapter pattern with a functional core:
|
|
136
227
|
|
|
137
|
-
Use `axauth` to manage AI agent credentials. Check auth status with `axauth list`,
|
|
138
|
-
get tokens with `axauth token`, and export/import credentials for CI/CD workflows.
|
|
139
228
|
```
|
|
229
|
+
src/
|
|
230
|
+
├── index.ts # Public API exports
|
|
231
|
+
├── cli.ts # CLI entry point
|
|
232
|
+
├── crypto.ts # AES-256-GCM encryption
|
|
233
|
+
├── commands/
|
|
234
|
+
│ └── auth.ts # CLI command handlers
|
|
235
|
+
└── auth/
|
|
236
|
+
├── adapter.ts # AuthAdapter interface
|
|
237
|
+
├── types.ts # AuthStatus, Credentials types
|
|
238
|
+
├── registry.ts # Adapter registry and unified operations
|
|
239
|
+
└── agents/ # Agent-specific adapters
|
|
240
|
+
├── claude-code.ts
|
|
241
|
+
├── claude-code-storage.ts
|
|
242
|
+
├── codex.ts
|
|
243
|
+
├── codex-storage.ts
|
|
244
|
+
├── codex-config.ts
|
|
245
|
+
├── gemini.ts
|
|
246
|
+
├── gemini-storage.ts
|
|
247
|
+
├── gemini-auth-check.ts
|
|
248
|
+
├── copilot.ts
|
|
249
|
+
├── copilot-storage.ts
|
|
250
|
+
├── copilot-auth-check.ts
|
|
251
|
+
└── opencode.ts
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Related Packages
|
|
140
255
|
|
|
141
|
-
|
|
256
|
+
axauth is part of the [a╳point](https://axpoint.dev) ecosystem:
|
|
142
257
|
|
|
143
|
-
|
|
258
|
+
- **axshared** - Shared types and agent metadata
|
|
259
|
+
- **axconfig** - Permission and configuration management
|
|
260
|
+
- **axrun** - Agent execution and output normalization
|
|
144
261
|
|
|
145
262
|
## License
|
|
146
263
|
|
package/dist/auth/adapter.d.ts
CHANGED
|
@@ -25,23 +25,34 @@ interface OperationResult {
|
|
|
25
25
|
* - `undefined`: Use the `_source` marker in credentials, or default to file
|
|
26
26
|
*/
|
|
27
27
|
interface InstallOptions {
|
|
28
|
-
/** Storage type for default location (ignored if
|
|
28
|
+
/** Storage type for default location (ignored if configDir is set) */
|
|
29
29
|
storage?: StorageType;
|
|
30
|
-
/** Custom
|
|
31
|
-
|
|
30
|
+
/** Custom config directory (forces file storage, keychain not available) */
|
|
31
|
+
configDir?: string;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Options for credential removal.
|
|
35
35
|
*
|
|
36
|
-
* When `
|
|
37
|
-
* Keychain credentials are not affected (keychain is only for
|
|
36
|
+
* When `configDir` is provided, only the credentials file in that directory
|
|
37
|
+
* is removed. Keychain credentials are not affected (keychain is only for
|
|
38
|
+
* default location).
|
|
38
39
|
*
|
|
39
|
-
* When `
|
|
40
|
+
* When `configDir` is not provided, credentials are removed from all default
|
|
40
41
|
* locations (keychain and/or default file path).
|
|
41
42
|
*/
|
|
42
43
|
interface RemoveOptions {
|
|
43
|
-
/** Custom
|
|
44
|
-
|
|
44
|
+
/** Custom config directory (removes only this location, not keychain) */
|
|
45
|
+
configDir?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Options for token extraction.
|
|
49
|
+
*
|
|
50
|
+
* Some agents (like opencode) support multiple providers. Use the `provider`
|
|
51
|
+
* option to specify which provider's token to extract.
|
|
52
|
+
*/
|
|
53
|
+
interface TokenOptions {
|
|
54
|
+
/** Provider ID for multi-provider agents (e.g., "anthropic", "openai") */
|
|
55
|
+
provider?: string;
|
|
45
56
|
}
|
|
46
57
|
/** Capabilities that an adapter supports */
|
|
47
58
|
interface AdapterCapabilities {
|
|
@@ -95,10 +106,10 @@ interface AuthAdapter {
|
|
|
95
106
|
/**
|
|
96
107
|
* Remove credentials from storage.
|
|
97
108
|
*
|
|
98
|
-
* When `options.
|
|
99
|
-
* Keychain credentials are not affected.
|
|
109
|
+
* When `options.configDir` is provided, only the credentials file in that
|
|
110
|
+
* directory is removed. Keychain credentials are not affected.
|
|
100
111
|
*
|
|
101
|
-
* When `options.
|
|
112
|
+
* When `options.configDir` is not provided, credentials are removed from all
|
|
102
113
|
* default locations (keychain and/or default file path).
|
|
103
114
|
*/
|
|
104
115
|
removeCredentials(options?: RemoveOptions): OperationResult;
|
|
@@ -107,8 +118,11 @@ interface AuthAdapter {
|
|
|
107
118
|
*
|
|
108
119
|
* Returns the primary access token (OAuth token or API key) from
|
|
109
120
|
* the credential data. Returns undefined if no token found.
|
|
121
|
+
*
|
|
122
|
+
* For multi-provider agents (like opencode), use `options.provider`
|
|
123
|
+
* to specify which provider's token to extract.
|
|
110
124
|
*/
|
|
111
|
-
getAccessToken(creds: Credentials): string | undefined;
|
|
125
|
+
getAccessToken(creds: Credentials, options?: TokenOptions): string | undefined;
|
|
112
126
|
/**
|
|
113
127
|
* Convert credentials to environment variables.
|
|
114
128
|
*
|
|
@@ -118,4 +132,4 @@ interface AuthAdapter {
|
|
|
118
132
|
*/
|
|
119
133
|
credentialsToEnvironment(creds: Credentials): Record<string, string>;
|
|
120
134
|
}
|
|
121
|
-
export type { AdapterCapabilities, AuthAdapter, InstallOptions, OperationResult, RemoveOptions, };
|
|
135
|
+
export type { AdapterCapabilities, AuthAdapter, InstallOptions, OperationResult, RemoveOptions, TokenOptions, };
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { userInfo } from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
7
|
-
import { claudeCodeConfigReader } from "axconfig";
|
|
8
7
|
import { deleteFile, loadJsonFile, saveJsonFile } from "../file-storage.js";
|
|
9
8
|
import { getResolvedConfigDirectory } from "../resolve-config-directory.js";
|
|
10
9
|
import { deleteFromKeychain, loadFromKeychain, saveToKeychain, } from "../keychain.js";
|
|
@@ -15,7 +14,7 @@ function getUsername() {
|
|
|
15
14
|
}
|
|
16
15
|
/** Get default credentials file path */
|
|
17
16
|
function getDefaultCredsFilePath() {
|
|
18
|
-
return path.join(getResolvedConfigDirectory(
|
|
17
|
+
return path.join(getResolvedConfigDirectory("claude"), ".credentials.json");
|
|
19
18
|
}
|
|
20
19
|
/** Load OAuth credentials from keychain */
|
|
21
20
|
function loadKeychainCreds() {
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Supports OAuth via keychain (macOS) or file, and API key via env var.
|
|
5
5
|
*/
|
|
6
|
+
import path from "node:path";
|
|
6
7
|
import { isMacOS } from "../keychain.js";
|
|
7
8
|
import { deleteFileCreds, deleteKeychainCreds, getDefaultCredsFilePath, loadFileCreds, loadKeychainCreds, saveFileCreds, saveKeychainCreds, } from "./claude-code-storage.js";
|
|
8
9
|
const AGENT_ID = "claude";
|
|
10
|
+
const CREDS_FILE_NAME = ".credentials.json";
|
|
9
11
|
/** Claude Code authentication adapter */
|
|
10
12
|
const claudeCodeAdapter = {
|
|
11
13
|
agentId: AGENT_ID,
|
|
@@ -77,17 +79,18 @@ const claudeCodeAdapter = {
|
|
|
77
79
|
};
|
|
78
80
|
}
|
|
79
81
|
const { _source, ...oauthData } = creds.data;
|
|
80
|
-
// Custom
|
|
81
|
-
if (options?.
|
|
82
|
-
|
|
82
|
+
// Custom config directory forces file storage (keychain only for default location)
|
|
83
|
+
if (options?.configDir) {
|
|
84
|
+
const targetPath = path.join(options.configDir, CREDS_FILE_NAME);
|
|
85
|
+
if (saveFileCreds(oauthData, targetPath)) {
|
|
83
86
|
return {
|
|
84
87
|
ok: true,
|
|
85
|
-
message: `Installed credentials to ${
|
|
88
|
+
message: `Installed credentials to ${targetPath}`,
|
|
86
89
|
};
|
|
87
90
|
}
|
|
88
91
|
return {
|
|
89
92
|
ok: false,
|
|
90
|
-
message: `Failed to install credentials to ${
|
|
93
|
+
message: `Failed to install credentials to ${targetPath}`,
|
|
91
94
|
};
|
|
92
95
|
}
|
|
93
96
|
// Default location: use storage option or _source marker
|
|
@@ -114,10 +117,11 @@ const claudeCodeAdapter = {
|
|
|
114
117
|
};
|
|
115
118
|
},
|
|
116
119
|
removeCredentials(options) {
|
|
117
|
-
// Custom
|
|
118
|
-
if (options?.
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
// Custom config directory: only remove that specific file (no keychain)
|
|
121
|
+
if (options?.configDir) {
|
|
122
|
+
const targetPath = path.join(options.configDir, CREDS_FILE_NAME);
|
|
123
|
+
if (deleteFileCreds(targetPath)) {
|
|
124
|
+
return { ok: true, message: `Removed ${targetPath}` };
|
|
121
125
|
}
|
|
122
126
|
return {
|
|
123
127
|
ok: true,
|
|
@@ -8,7 +8,7 @@ import { codexConfigReader } from "axconfig";
|
|
|
8
8
|
import { getResolvedConfigDirectory } from "../resolve-config-directory.js";
|
|
9
9
|
/** Get the codex home directory */
|
|
10
10
|
function getCodexHome() {
|
|
11
|
-
return getResolvedConfigDirectory(
|
|
11
|
+
return getResolvedConfigDirectory("codex");
|
|
12
12
|
}
|
|
13
13
|
/** Get auth file path */
|
|
14
14
|
function getAuthFilePath() {
|
|
@@ -10,6 +10,7 @@ import { checkAuth, extractRawCredentials } from "./codex-auth-check.js";
|
|
|
10
10
|
import { getAuthFilePath, getCodexHome, updateConfigStorage, } from "./codex-config.js";
|
|
11
11
|
import { buildAuthContent, deleteFileCreds, deleteKeychainCreds, saveFileCreds, saveKeychainCreds, } from "./codex-storage.js";
|
|
12
12
|
const AGENT_ID = "codex";
|
|
13
|
+
const CREDS_FILE_NAME = "auth.json";
|
|
13
14
|
/** Codex authentication adapter */
|
|
14
15
|
const codexAdapter = {
|
|
15
16
|
agentId: AGENT_ID,
|
|
@@ -23,24 +24,24 @@ const codexAdapter = {
|
|
|
23
24
|
extractRawCredentials,
|
|
24
25
|
installCredentials(creds, options) {
|
|
25
26
|
const authContent = buildAuthContent(creds.type, creds.data);
|
|
26
|
-
// Custom
|
|
27
|
-
if (options?.
|
|
28
|
-
|
|
29
|
-
if (!ensureDirectory(parentDirectory)) {
|
|
27
|
+
// Custom config directory forces file storage (keychain only for default location)
|
|
28
|
+
if (options?.configDir) {
|
|
29
|
+
if (!ensureDirectory(options.configDir)) {
|
|
30
30
|
return {
|
|
31
31
|
ok: false,
|
|
32
|
-
message: `Failed to create directory ${
|
|
32
|
+
message: `Failed to create directory ${options.configDir}`,
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
const targetPath = path.join(options.configDir, CREDS_FILE_NAME);
|
|
36
|
+
if (saveFileCreds(authContent, targetPath)) {
|
|
36
37
|
return {
|
|
37
38
|
ok: true,
|
|
38
|
-
message: `Installed credentials to ${
|
|
39
|
+
message: `Installed credentials to ${targetPath}`,
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
42
|
return {
|
|
42
43
|
ok: false,
|
|
43
|
-
message: `Failed to install credentials to ${
|
|
44
|
+
message: `Failed to install credentials to ${targetPath}`,
|
|
44
45
|
};
|
|
45
46
|
}
|
|
46
47
|
// Default location: use storage option or _source marker
|
|
@@ -72,10 +73,11 @@ const codexAdapter = {
|
|
|
72
73
|
return { ok: false, message: "Failed to install credentials to file" };
|
|
73
74
|
},
|
|
74
75
|
removeCredentials(options) {
|
|
75
|
-
// Custom
|
|
76
|
-
if (options?.
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
// Custom config directory: only remove that specific file (no keychain)
|
|
77
|
+
if (options?.configDir) {
|
|
78
|
+
const targetPath = path.join(options.configDir, CREDS_FILE_NAME);
|
|
79
|
+
if (deleteFileCreds(targetPath)) {
|
|
80
|
+
return { ok: true, message: `Removed ${targetPath}` };
|
|
79
81
|
}
|
|
80
82
|
return {
|
|
81
83
|
ok: true,
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { existsSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
9
9
|
import path from "node:path";
|
|
10
|
-
import { copilotConfigReader } from "axconfig";
|
|
11
10
|
import { ensureDirectory, loadJsonFile, saveJsonFile, } from "../file-storage.js";
|
|
12
11
|
import { deleteFromKeychain, isMacOS, loadFromKeychain, saveToKeychain, } from "../keychain.js";
|
|
13
12
|
import { getResolvedConfigDirectory } from "../resolve-config-directory.js";
|
|
@@ -15,7 +14,7 @@ const KEYCHAIN_SERVICE = "copilot-cli";
|
|
|
15
14
|
const DEFAULT_HOST = "https://github.com";
|
|
16
15
|
/** Get the copilot config directory */
|
|
17
16
|
function getConfigDirectory() {
|
|
18
|
-
return getResolvedConfigDirectory(
|
|
17
|
+
return getResolvedConfigDirectory("copilot");
|
|
19
18
|
}
|
|
20
19
|
/** Get the default config file path */
|
|
21
20
|
function getConfigFilePath() {
|
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
* Supports OAuth via keychain (macOS) or file, and GitHub token via env var.
|
|
5
5
|
* Also supports GitHub CLI (`gh auth login`) as a fallback.
|
|
6
6
|
*/
|
|
7
|
+
import path from "node:path";
|
|
7
8
|
import { ensureDirectory } from "../file-storage.js";
|
|
8
9
|
import { isMacOS } from "../keychain.js";
|
|
9
10
|
import { findFirstAvailableToken } from "./copilot-auth-check.js";
|
|
10
11
|
import { deleteFileToken, deleteKeychainToken, deleteTokenFromPath, getConfigDirectory, getConfigFilePath, saveFileToken, saveKeychainToken, saveTokenToPath, } from "./copilot-storage.js";
|
|
11
12
|
const AGENT_ID = "copilot";
|
|
13
|
+
const CREDS_FILE_NAME = "token.json";
|
|
12
14
|
/** Copilot CLI authentication adapter */
|
|
13
15
|
const copilotAdapter = {
|
|
14
16
|
agentId: AGENT_ID,
|
|
@@ -58,17 +60,18 @@ const copilotAdapter = {
|
|
|
58
60
|
if (!token) {
|
|
59
61
|
return { ok: false, message: "No access token found in credentials" };
|
|
60
62
|
}
|
|
61
|
-
// Custom
|
|
62
|
-
if (options?.
|
|
63
|
-
|
|
63
|
+
// Custom config directory forces file storage
|
|
64
|
+
if (options?.configDir) {
|
|
65
|
+
const targetPath = path.join(options.configDir, CREDS_FILE_NAME);
|
|
66
|
+
if (saveTokenToPath(token, targetPath)) {
|
|
64
67
|
return {
|
|
65
68
|
ok: true,
|
|
66
|
-
message: `Installed credentials to ${
|
|
69
|
+
message: `Installed credentials to ${targetPath}`,
|
|
67
70
|
};
|
|
68
71
|
}
|
|
69
72
|
return {
|
|
70
73
|
ok: false,
|
|
71
|
-
message: `Failed to install credentials to ${
|
|
74
|
+
message: `Failed to install credentials to ${targetPath}`,
|
|
72
75
|
};
|
|
73
76
|
}
|
|
74
77
|
// Default location: use storage option or _source marker
|
|
@@ -102,10 +105,11 @@ const copilotAdapter = {
|
|
|
102
105
|
return { ok: false, message: "Failed to install credentials to file" };
|
|
103
106
|
},
|
|
104
107
|
removeCredentials(options) {
|
|
105
|
-
// Custom
|
|
106
|
-
if (options?.
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
// Custom config directory: only remove that specific file
|
|
109
|
+
if (options?.configDir) {
|
|
110
|
+
const targetPath = path.join(options.configDir, CREDS_FILE_NAME);
|
|
111
|
+
if (deleteTokenFromPath(targetPath)) {
|
|
112
|
+
return { ok: true, message: `Removed ${targetPath}` };
|
|
109
113
|
}
|
|
110
114
|
return {
|
|
111
115
|
ok: true,
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gemini CLI authentication checking.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Uses priority-ordered credential discovery: env → keychain → file.
|
|
5
5
|
*/
|
|
6
6
|
/** Credential source for auth method display */
|
|
7
|
-
type CredentialSource = "keychain" | "file" | "api-key" | "vertex-ai"
|
|
7
|
+
type CredentialSource = "keychain" | "file" | "api-key" | "vertex-ai";
|
|
8
8
|
/** Result of finding available credentials */
|
|
9
9
|
interface CredentialResult {
|
|
10
10
|
source: CredentialSource;
|
|
11
11
|
method: string;
|
|
12
12
|
data?: Record<string, unknown>;
|
|
13
13
|
}
|
|
14
|
-
/** Find credentials
|
|
14
|
+
/** Find credentials using priority-ordered discovery: env → keychain → file */
|
|
15
15
|
declare function findCredentials(): CredentialResult | undefined;
|
|
16
16
|
export { findCredentials };
|