# claude-key-helper.ps1 # # Invoked by Claude Code via the `apiKeyHelper` setting. Prints the API key for # the currently active preset to stdout and nothing else. # # Only presets whose auth mode is "vault" have a secret to emit. In anthropic # mode, or for a preset using an inline placeholder token (LM Studio), this # exits silently so no token can leak into a context that must not have one. # # The key is stored DPAPI-encrypted (CurrentUser scope), so decryption only # succeeds for the Windows account that ran `claude-mode set-key`. Reading the # .cred file as another user - or copying it to another machine - yields nothing. $ErrorActionPreference = 'Stop' try { $root = Join-Path $env:USERPROFILE '.claude-mode' $state = Get-Content -LiteralPath (Join-Path $root 'state.json') -Raw -Encoding UTF8 | ConvertFrom-Json if ($state.mode -eq 'anthropic') { exit 0 } if (-not $state.preset) { exit 0 } $presetPath = Join-Path $root ('presets\' + $state.preset + '.json') if (-not (Test-Path -LiteralPath $presetPath)) { exit 1 } $preset = Get-Content -LiteralPath $presetPath -Raw -Encoding UTF8 | ConvertFrom-Json $authMode = 'vault' $keyRef = 'openrouter' if ($preset.PSObject.Properties.Name -contains 'auth' -and $preset.auth) { if ($preset.auth.PSObject.Properties.Name -contains 'mode' -and $preset.auth.mode) { $authMode = [string]$preset.auth.mode } if ($preset.auth.PSObject.Properties.Name -contains 'keyRef' -and $preset.auth.keyRef) { $keyRef = [string]$preset.auth.keyRef } } if ($authMode -ne 'vault') { exit 0 } # inline token: nothing for us to emit $credPath = Join-Path $root ('vault\' + $keyRef + '.cred') if (-not (Test-Path -LiteralPath $credPath)) { exit 1 } $secure = ConvertTo-SecureString (Get-Content -LiteralPath $credPath -Raw).Trim() $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure) try { [Console]::Out.Write([Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)) } finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } } catch { exit 1 }