useApiKeyVerification.ts
hooks/useApiKeyVerification.ts
85
Lines
2678
Bytes
3
Exports
4
Imports
10
Keywords
What this is
This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.
Beginner explanation
This file is one piece of the larger system. Its name, directory, imports, and exports show where it fits. Start by reading the exports and related files first.
How it is used
Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.
Expert explanation
Architecturally, this file intersects with planner-verifier-agents, integrations. It contains 85 lines, 4 detected imports, and 3 detected exports.
Important relationships
Detected exports
VerificationStatusApiKeyVerificationResultuseApiKeyVerification
Keywords
setstatusnewstatusvalidapikeyhelpersourcegetanthropicapikeywithsourceinvalidusestateisanthropicauthenabledisclaudeaisubscriber
Detected imports
react../bootstrap/state.js../services/api/claude.js../utils/auth.js
Source notes
This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.
Full source
import { useCallback, useState } from 'react'
import { getIsNonInteractiveSession } from '../bootstrap/state.js'
import { verifyApiKey } from '../services/api/claude.js'
import {
getAnthropicApiKeyWithSource,
getApiKeyFromApiKeyHelper,
isAnthropicAuthEnabled,
isClaudeAISubscriber,
} from '../utils/auth.js'
export type VerificationStatus =
| 'loading'
| 'valid'
| 'invalid'
| 'missing'
| 'error'
export type ApiKeyVerificationResult = {
status: VerificationStatus
reverify: () => Promise<void>
error: Error | null
}
export function useApiKeyVerification(): ApiKeyVerificationResult {
const [status, setStatus] = useState<VerificationStatus>(() => {
if (!isAnthropicAuthEnabled() || isClaudeAISubscriber()) {
return 'valid'
}
// Use skipRetrievingKeyFromApiKeyHelper to avoid executing apiKeyHelper
// before trust dialog is shown (security: prevents RCE via settings.json)
const { key, source } = getAnthropicApiKeyWithSource({
skipRetrievingKeyFromApiKeyHelper: true,
})
// If apiKeyHelper is configured, we have a key source even though we
// haven't executed it yet - return 'loading' to indicate we'll verify later
if (key || source === 'apiKeyHelper') {
return 'loading'
}
return 'missing'
})
const [error, setError] = useState<Error | null>(null)
const verify = useCallback(async (): Promise<void> => {
if (!isAnthropicAuthEnabled() || isClaudeAISubscriber()) {
setStatus('valid')
return
}
// Warm the apiKeyHelper cache (no-op if not configured), then read from
// all sources. getAnthropicApiKeyWithSource() reads the now-warm cache.
await getApiKeyFromApiKeyHelper(getIsNonInteractiveSession())
const { key: apiKey, source } = getAnthropicApiKeyWithSource()
if (!apiKey) {
if (source === 'apiKeyHelper') {
setStatus('error')
setError(new Error('API key helper did not return a valid key'))
return
}
const newStatus = 'missing'
setStatus(newStatus)
return
}
try {
const isValid = await verifyApiKey(apiKey, false)
const newStatus = isValid ? 'valid' : 'invalid'
setStatus(newStatus)
return
} catch (error) {
// This happens when there an error response from the API but it's not an invalid API key error
// In this case, we still mark the API key as invalid - but we also log the error so we can
// display it to the user to be more helpful
setError(error as Error)
const newStatus = 'error'
setStatus(newStatus)
return
}
}, [])
return {
status,
reverify: verify,
error,
}
}