1
>
/*---------------------------------------------------------------------------------------------
claudeProxyAuth.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import type * as http from 'http';
7
>
8
>
/**
9
>
* Result of {@link parseProxyBearer}. `valid` is `true` only when the
10
>
* `Authorization` header contains `Bearer <expectedNonce>.<sessionId>`
11
>
* with a non-empty `sessionId`.
12
>
*
13
>
* Phase 2 deliberately does NOT accept the legacy `Bearer <nonce>` (no
14
>
* dot) format that the Copilot extension's `extractSessionId` accepts —
15
>
* the agent host always issues full `nonce.sessionId` tokens.
16
>
*/
17
>
export interface ProxyBearerAuth {
18
>
readonly valid: boolean;
19
>
readonly sessionId: string | undefined;
20
>
}
21
>
22
>
const INVALID: ProxyBearerAuth = Object.freeze({ valid: false, sessionId: undefined });
23
>
24
>
/**
25
>
* Parses + validates the inbound Bearer token on Claude proxy requests.
26
>
*
27
>
* Accepts only `Authorization: Bearer <nonce>.<sessionId>` where the
28
>
* leading nonce equals `expectedNonce` and `sessionId` is non-empty.
29
>
* The `x-api-key` header is ignored to prevent a user's
30
>
* `ANTHROPIC_API_KEY` env var from interfering with proxy auth.
31
>
*
32
>
* Rejects (returns `{ valid: false, sessionId: undefined }`):
33
>
* - missing or non-`Bearer` `Authorization`
34
>
* - `Bearer <nonce>` (no dot)
35
>
* - `Bearer <nonce>.` (empty sessionId)
36
>
* - `Bearer <wrong-nonce>.<sessionId>`
37
>
*/
38
>
export function parseProxyBearer(headers: http.IncomingHttpHeaders, expectedNonce: string): ProxyBearerAuth {
39
const authHeader = headers['authorization'];
40
if (typeof authHeader !== 'string' || !authHeader.startsWith('Bearer ')) {