---
name: load_claude_oauth_token
kind: function
lang: py
domain: core
version: "1.0.0"
purity: impure
signature: "def load_claude_oauth_token(credentials_path: str = \"\", refresh_if_expired: bool = True) -> str"
description: "Lee el access token OAuth de Claude Code desde ~/.claude/.credentials.json. Extrae claudeAiOauth.accessToken y verifica expiry (expiresAt en milisegundos). Si el token esta expirado y refresh_if_expired=True intenta un refresh best-effort via POST al endpoint OAuth de Anthropic; si el refresh falla devuelve el token actual con warning a stderr."
tags: [claude-direct, anthropic, oauth, credentials, token, auth]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [json, os, sys, time, pathlib.Path, httpx]
params:
  - name: credentials_path
    desc: "ruta absoluta o con ~ al archivo de credenciales. Default: ~/.claude/.credentials.json"
  - name: refresh_if_expired
    desc: "si True, intenta refrescar el token cuando expiresAt <= now. Default: True"
output: "el access token como string (sk-ant-oat-...). Nunca se imprime a stdout"
tested: true
tests:
  - "extrae accessToken de un credentials fixture"
  - "token no expirado no intenta refresh"
  - "token expirado con refresh_if_expired=False devuelve token igual"
  - "token expirado con refresh que falla devuelve token y escribe warning a stderr"
test_file_path: "python/functions/core/load_claude_oauth_token_test.py"
file_path: "python/functions/core/load_claude_oauth_token.py"
---

## Ejemplo

```python
import sys
sys.path.insert(0, "python/functions/core")
from load_claude_oauth_token import load_claude_oauth_token

# Lee desde ~/.claude/.credentials.json por defecto
token = load_claude_oauth_token()
print(token[:20] + "...")   # sk-ant-oat01-...

# Sin intento de refresh (evita llamada de red)
token = load_claude_oauth_token(refresh_if_expired=False)

# Ruta custom (ej. para testing con fixture)
token = load_claude_oauth_token(credentials_path="/tmp/fake_creds.json")
```

## Cuando usarla

Cuando vayas a hacer requests directos a `https://api.anthropic.com/v1/messages`
usando la cuenta Claude Max del usuario local (sin API key de pago separada).
Llama esta funcion primero; su resultado va en el header
`Authorization: Bearer <token>` de `stream_anthropic_messages`.

## Gotchas

- **Refresh best-effort**: el endpoint de refresh OAuth de Anthropic no esta
  documentado publicamente. El intento puede fallar silenciosamente — en ese
  caso se devuelve el token actual con un warning a stderr. La CLI `claude`
  mantiene el token fresco en background; si tienes Claude Code abierto,
  normalmente el token ya estara vigente.
- **expiresAt en milisegundos**: la estructura JSON usa ms-epoch, no s-epoch.
  `expiresAt / 1000 <= time.time()` es la comparacion correcta.
- **Nunca imprimir el token a stdout**: el token es una credencial OAuth.
  Esta funcion solo lo retorna; el caller decide como usarlo.
- El archivo `.credentials.json` solo existe si Claude Code esta instalado
  y el usuario ha hecho login. Si no existe lanza `FileNotFoundError`.
