voicecc 1.1.10 → 1.1.11
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/dashboard/routes/auth.ts +22 -18
- package/package.json +1 -1
package/dashboard/routes/auth.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Claude Code authentication routes.
|
|
3
3
|
*
|
|
4
4
|
* Supports two auth flows:
|
|
5
|
-
* 1. OAuth PKCE flow via claude.ai (recommended
|
|
5
|
+
* 1. OAuth PKCE flow via claude.ai (recommended -- enables cloud MCP servers)
|
|
6
6
|
* 2. Manual token paste via `claude setup-token` (fallback)
|
|
7
7
|
*
|
|
8
8
|
* - GET / -- probe auth status
|
|
@@ -25,12 +25,12 @@ const PROBE_TIMEOUT_MS = 5_000;
|
|
|
25
25
|
|
|
26
26
|
const OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
27
27
|
const OAUTH_AUTH_URL = "https://claude.ai/oauth/authorize";
|
|
28
|
-
const OAUTH_TOKEN_URL = "https://claude.
|
|
28
|
+
const OAUTH_TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
|
|
29
29
|
const OAUTH_REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
|
|
30
30
|
const OAUTH_SCOPES = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers";
|
|
31
31
|
|
|
32
32
|
// ============================================================================
|
|
33
|
-
// PKCE STATE (single-user dashboard
|
|
33
|
+
// PKCE STATE (single-user dashboard -- one pending flow at a time)
|
|
34
34
|
// ============================================================================
|
|
35
35
|
|
|
36
36
|
let pendingPkce: { codeVerifier: string; state: string; createdAt: number } | null = null;
|
|
@@ -51,25 +51,30 @@ function generatePkce(): { codeVerifier: string; codeChallenge: string } {
|
|
|
51
51
|
return { codeVerifier, codeChallenge };
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
/**
|
|
55
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Exchange an authorization code for tokens using the PKCE verifier.
|
|
56
|
+
* @param code - The authorization code from the OAuth callback
|
|
57
|
+
* @param codeVerifier - The PKCE code_verifier generated at flow start
|
|
58
|
+
* @param state - The OAuth state parameter (required by the token endpoint)
|
|
59
|
+
* @returns Token response with access_token, refresh_token, expires_in
|
|
60
|
+
*/
|
|
61
|
+
async function exchangeCodeForTokens(code: string, codeVerifier: string, state: string): Promise<{
|
|
56
62
|
access_token: string;
|
|
57
63
|
refresh_token: string;
|
|
58
64
|
expires_in: number;
|
|
59
65
|
scope?: string;
|
|
60
66
|
}> {
|
|
61
|
-
const body = new URLSearchParams({
|
|
62
|
-
grant_type: "authorization_code",
|
|
63
|
-
code,
|
|
64
|
-
code_verifier: codeVerifier,
|
|
65
|
-
client_id: OAUTH_CLIENT_ID,
|
|
66
|
-
redirect_uri: OAUTH_REDIRECT_URI,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
67
|
const res = await fetch(OAUTH_TOKEN_URL, {
|
|
70
68
|
method: "POST",
|
|
71
|
-
headers: { "Content-Type": "application/
|
|
72
|
-
body:
|
|
69
|
+
headers: { "Content-Type": "application/json" },
|
|
70
|
+
body: JSON.stringify({
|
|
71
|
+
grant_type: "authorization_code",
|
|
72
|
+
code,
|
|
73
|
+
state,
|
|
74
|
+
code_verifier: codeVerifier,
|
|
75
|
+
client_id: OAUTH_CLIENT_ID,
|
|
76
|
+
redirect_uri: OAUTH_REDIRECT_URI,
|
|
77
|
+
}),
|
|
73
78
|
});
|
|
74
79
|
|
|
75
80
|
if (!res.ok) {
|
|
@@ -96,7 +101,6 @@ interface AuthStatus {
|
|
|
96
101
|
async function getAuthStatus(): Promise<AuthStatus> {
|
|
97
102
|
return new Promise((resolve) => {
|
|
98
103
|
execFile(CLAUDE_BIN, ["auth", "status"], { timeout: PROBE_TIMEOUT_MS }, (err, stdout, stderr) => {
|
|
99
|
-
// Try parsing stdout first, then stderr (some versions write JSON to stderr on exit 1)
|
|
100
104
|
const output = stdout?.trim() || stderr?.trim() || "";
|
|
101
105
|
try {
|
|
102
106
|
const json = JSON.parse(output);
|
|
@@ -140,7 +144,7 @@ export function authRoutes(): Hono {
|
|
|
140
144
|
return c.json(await getAuthStatus());
|
|
141
145
|
});
|
|
142
146
|
|
|
143
|
-
/** Start an OAuth PKCE flow
|
|
147
|
+
/** Start an OAuth PKCE flow -- returns the authorization URL. */
|
|
144
148
|
app.post("/oauth/start", async (c) => {
|
|
145
149
|
const { codeVerifier, codeChallenge } = generatePkce();
|
|
146
150
|
const state = base64url(randomBytes(32));
|
|
@@ -184,7 +188,7 @@ export function authRoutes(): Hono {
|
|
|
184
188
|
}
|
|
185
189
|
|
|
186
190
|
try {
|
|
187
|
-
const tokens = await exchangeCodeForTokens(code.trim(), pendingPkce.codeVerifier);
|
|
191
|
+
const tokens = await exchangeCodeForTokens(code.trim(), pendingPkce.codeVerifier, pendingPkce.state);
|
|
188
192
|
pendingPkce = null;
|
|
189
193
|
|
|
190
194
|
const scopes = tokens.scope
|