Skip to content

Configurar autenticação ​

O nene2-python suporta autenticação por Bearer Token e API Key, ambas implementadas como middleware e habilitadas via variáveis de ambiente.

Bearer Token ​

Habilitar ​

Adicione ao seu arquivo .env:

dotenv
BEARER_TOKEN_ENABLED=true
BEARER_TOKENS=["token1","token2","token3"]

Comportamento ​

  • Toda requisição deve incluir Authorization: Bearer <token>
  • Os tokens são comparados com secrets.compare_digest (seguro contra timing attacks)
  • Tokens inválidos retornam 401 Unauthorized (Problem Details RFC 9457)

Exemplo ​

bash
curl -H "Authorization: Bearer token1" http://localhost:8080/notes

API Key ​

Habilitar ​

dotenv
API_KEY_ENABLED=true
API_KEYS=["key1","key2"]

Comportamento ​

  • Toda requisição deve incluir X-Api-Key: <key>
  • Chaves inválidas retornam 401 Unauthorized

Exemplo ​

bash
curl -H "X-Api-Key: key1" http://localhost:8080/notes

Usando ambos ao mesmo tempo (condição AND) ​

Quando ambos os middlewares são adicionados via add_middleware, as requisições precisam passar pelas duas verificações (condição AND). Um Bearer token sozinho ou uma API key sozinha resultarão em 401.

Autenticação alternativa (Bearer Token OU API Key) ​

Se quiser aceitar qualquer um — Bearer token ou API key, o que estiver presente — os middlewares embutidos não conseguem expressar isso. Implemente um middleware customizado que reutilize os verificadores existentes:

python
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.requests import Request
from starlette.responses import Response

from nene2.auth import LocalTokenVerifier
from nene2.auth.exceptions import TokenVerificationException
from nene2.http.problem_details import problem_details_response

class EitherOrAuthMiddleware(BaseHTTPMiddleware):
    def __init__(self, app, *, bearer_tokens: list[str], api_keys: list[str],
                 exclude_paths: list[str] | None = None) -> None:
        super().__init__(app)
        self._bearer = LocalTokenVerifier(bearer_tokens)
        self._api_key = LocalTokenVerifier(api_keys)
        self._exclude_paths = set(exclude_paths or [])

    async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
        if request.url.path in self._exclude_paths:
            return await call_next(request)

        auth = request.headers.get("Authorization", "")
        if auth.startswith("Bearer "):
            try:
                if self._bearer.verify(auth[len("Bearer "):]):
                    return await call_next(request)
            except TokenVerificationException:
                pass

        api_key = request.headers.get("X-Api-Key", "")
        if api_key:
            try:
                if self._api_key.verify(api_key):
                    return await call_next(request)
            except TokenVerificationException:
                pass

        return problem_details_response(
            "unauthorized", "Unauthorized", 401,
            "A valid Bearer token or X-Api-Key header is required.",
        )

Desabilitando auth nos testes ​

python
from nene2.config import AppSettings
from fastapi.testclient import TestClient
from example.app import create_app

client = TestClient(create_app(AppSettings(bearer_token_enabled=False)))

TokenVerifier customizado (ex: JWT) ​

Implemente TokenVerifierProtocol e lance TokenVerificationException em caso de falha.

python
from nene2.auth import TokenVerificationException, TokenVerifierProtocol
import jwt

class JwtTokenVerifier:
    def __init__(self, secret: str) -> None:
        self._secret = secret

    def verify(self, token: str) -> bool:
        try:
            jwt.decode(token, self._secret, algorithms=["HS256"])
            return True
        except jwt.InvalidTokenError as exc:
            raise TokenVerificationException(str(exc)) from exc

Passe seu verificador diretamente para o BearerTokenMiddleware.

Carregando tokens de variáveis de ambiente ​

Use LocalTokenVerifier.from_env() para evitar o boilerplate de split e strip toda vez:

dotenv
# .env
BEARER_TOKENS=token-a,token-b,token-c
python
from nene2.auth import BearerTokenMiddleware, LocalTokenVerifier

app.add_middleware(
    BearerTokenMiddleware,
    verifier=LocalTokenVerifier.from_env("BEARER_TOKENS"),
)

Uma variável não definida ou vazia produz uma allowlist vazia — todas as requisições são negadas.

Excluindo caminhos da autenticação ​

Use exclude_paths para ignorar auth em health checks e API docs:

python
app.add_middleware(
    BearerTokenMiddleware,
    verifier=LocalTokenVerifier.from_env("BEARER_TOKENS"),
    exclude_paths=["/docs", "/openapi.json", "/redoc", "/health"],
)

O ApiKeyAuthMiddleware suporta o mesmo parâmetro.

Servidor MCP — falhe rápido em token ausente ​

Quando um servidor MCP chama uma API protegida por Bearer via HttpxMcpClient, valide o token na inicialização em vez de descobrir um token ausente em tempo de chamada:

python
import os
from nene2.mcp.http_client import HttpxMcpClient

token = os.getenv("MCP_BEARER_TOKEN")
if not token:
    raise RuntimeError("MCP_BEARER_TOKEN is not set — cannot call the authenticated API.")
client = HttpxMcpClient(token)

TokenIssuer customizado (ex: JWT) ​

Implemente TokenIssuerProtocol para emitir tokens (ex: para um endpoint de login).

python
from nene2.auth import TokenIssuerProtocol
import jwt

class JwtTokenIssuer:
    def __init__(self, secret: str) -> None:
        self._secret = secret

    def issue(self, claims: dict[str, object]) -> str:
        return jwt.encode(claims, self._secret, algorithm="HS256")

Lançado sob a Licença MIT.