Skip to main content

SDK to consume cidi-auth and auth.back authentication services from Python apps

Project description

boolean-auth-sdk (Python) — Integración Django/DRF

SDK para que juzgado.back y otros proyectos Django/DRF consuman los servicios de autenticación cidi-auth y auth.back, que a su vez delegan la firma de tokens en tokens.back.

📱 Cliente (frontend/backend) ──▶ cidi-auth / auth.back ──▶ tokens.back (.well-known/jwks.json)
  • boolean_auth_sdk.AuthClient: cliente HTTP para login, refresh, logout, /user/me/, /user/by-cuil/.
  • boolean_auth_sdk.integrations.django_drf.JWTAuthentication: autenticación DRF lista para usar, con soporte de fallback local y extracción de payload completo.
  • boolean_auth_sdk.JWTVerifier: verificación manual via JWKS con headers tipo navegador (evita bloqueos de Cloudflare) + fallback local (PKCS#8 → extrae pública automáticamente).

Instalación

# Core + integración Django/DRF
pip install -e "./sdks/python[django]"

# Dependencias de desarrollo (pytest + responses) para correr tests del SDK
pip install -e "./sdks/python[dev]"

1. Configuración en Django (settings.py)

# URL al JWKS que expone tokens.back (mismo que usan auth.back / cidi-auth)
AUTH_SDK_JWKS_URL = "https://tokens.boolean.com.ar/.well-known/jwks.json"

# Algoritmos permitidos (por defecto RS256)
AUTH_SDK_ALGORITHMS = ["RS256"]

# (Opcional) Fallback local: PEM privado o público. Si es privado, se extrae la pública.
AUTH_SDK_LOCAL_SECRET = env.str("JWT_LOCAL_PEM", default=None)

# Prefijos aceptados en Authorization (case-insensitive)
AUTH_SDK_HEADER_PREFIXES = ["token", "bearer"]

# Si el token llega vía cookie HttpOnly
AUTH_SDK_COOKIE_NAME = "access_token"  # opcional

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "boolean_auth_sdk.integrations.django_drf.JWTAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticated",
    ],
}
  • JWTAuthentication deja request.user como SDKUser, con:
    • user_id, username, email, app_id, session_uuid
    • roles: lista de Role(role_code, role_name)
    • payload: claims completos del JWT
  • JWTRefreshAuthentication es idéntica pero fuerza token_type == "refresh".

2. Views y ViewSets

from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

class CasesViewSet(viewsets.ViewSet):
    permission_classes = []  # usa las globales (IsAuthenticated)

    def list(self, request):
        user = request.user  # SDKUser
        return Response({
            "user_id": user.user_id,
            "roles": [r.role_code for r in user.roles],
            "email": user.email,
            "payload": user.payload,
        })

    @action(detail=False, methods=["post"],
            authentication_classes=[JWTRefreshAuthentication])
    def refresh(self, request):
        # Token ya validado como refresh
        return Response({"message": "refresh validado"})
  • Se puede combinar con cualquier permiso (IsAuthenticated, personalizados, etc.).
  • JWTRefreshAuthentication útil para endpoints que aceptan sólo refresh tokens (ej: reinicio de sesión).

3. Mapear a django.contrib.auth.User

Si tu app necesita usuarios persistentes (grupos, staff, etc.), subclasá JWTAuthentication y sobreescribí get_user para sincronizar el payload con tu modelo.

from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from boolean_auth_sdk.integrations.django_drf import JWTAuthentication

ROLE_TO_GROUP = {
    "judge": "Juzgado",
    "prosecutor": "Procurador",
    "secretary": "Secretario",
    "auxiliar": "Auxiliar",
    "admin": "admin",
}


class DjangoUserJWTAuthentication(JWTAuthentication):
    def get_user(self, payload, token):
        User = get_user_model()
        user_id = payload.get("user_id") or payload.get("sub")
        email = payload.get("email")
        username = payload.get("username") or email or user_id

        user, _ = User.objects.get_or_create(username=username)
        user.email = email or user.email
        user.first_name = payload.get("first_name") or user.first_name
        user.last_name = payload.get("last_name") or user.last_name
        user.is_active = True
        user.save()

        user.groups.clear()
        for role in payload.get("roles", []):
            code = (role.get("role_code") or role.get("code") or "").lower()
            group_name = ROLE_TO_GROUP.get(code)
            if group_name:
                group, _ = Group.objects.get_or_create(name=group_name)
                user.groups.add(group)

        # Adjuntar payload completo para acceso posterior
        user.payload = payload
        user.roles = payload.get("roles", [])
        user.token = token
        return user

En settings.py reemplazá el path de la clase:

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "myproject.authentication.DjangoUserJWTAuthentication",
    ],
}

4. Endpoint de refresh + reemisión de tokens

Ejemplo de endpoint que usa el refresh token del header y reemite llamando a AuthClient.refresh():

from rest_framework.views import APIView
from rest_framework.response import Response
from boolean_auth_sdk import AuthClient
from boolean_auth_sdk.integrations.django_drf import JWTRefreshAuthentication

class RefreshView(APIView):
    authentication_classes = [JWTRefreshAuthentication]
    permission_classes = []  # opcional: IsAuthenticated ya aplicada globalmente

    def post(self, request):
        refresh_token = request.auth  # el string pasado en Authorization
        client = AuthClient(settings.CIDI_AUTH_BASE_URL)
        tokens = client.refresh(refresh_token)
        return Response({
            "access_token": tokens.access_token,
            "refresh_token": tokens.refresh_token,
        })

5. Consumir los endpoints de auth desde Django

Para llamar a cidi-auth o auth.back desde tus views/services (por ejemplo, buscar usuarios por CUIL):

from boolean_auth_sdk import AuthClient

client = AuthClient(settings.CIDI_AUTH_BASE_URL, app_id=settings.CIDI_APP_ID)

def buscar_usuario_por_cuil(cuil: str, token: str):
    user = client.find_by_cuil(cuil, access_token=token)
    return user

def info_propia(token: str):
    return client.me(token)

AuthClient respeta el timeout (TOKEN_SIGN_SERVICE_TIMEOUT en config) y envía User-Agent tipo navegador.

6. Autenticación vía cookies

Si el frontend recibe tokens como cookies HttpOnly (access_token / refresh_token), configurá:

AUTH_SDK_COOKIE_NAME = "access_token"
REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] = [
    "boolean_auth_sdk.integrations.django_drf.JWTAuthentication",
]
  • Asegurate de configurar SESSION_COOKIE_SECURE, CSRF_COOKIE_SECURE, SameSite según tu despliegue.
  • JWTAuthentication intentará primero el header Authorization y luego la cookie.

7. Migrar desde un autenticador JWT existente

Checklist típico (ej. migración de authentication/cidi_jwt_authentication.py en juzgado.back):

  1. Agregar boolean_auth_sdk a requirements.txt / instalar editable.
  2. Configurar valores AUTH_SDK_* en settings.py (los mismos que usan cidi-auth / auth.back).
  3. Reemplazar DEFAULT_AUTHENTICATION_CLASSES por la clase del SDK (o subclase custom).
  4. Si tu autenticador antiguo re-hidrataba usuarios de Django, copiar la lógica a una subclase de JWTAuthentication.get_user().
  5. Actualizar tests para usar el nuevo flujo (o mockear JWTVerifier).

8. Verificación manual y scripts

from boolean_auth_sdk import JWTVerifier

verifier = JWTVerifier(
    jwks_url=settings.AUTH_SDK_JWKS_URL,
    local_secret=settings.AUTH_SDK_LOCAL_SECRET,
)

payload = verifier.verify(token, expected_token_type="access")
print(payload["user_id"], payload["roles"])
  • Si local_secret es un PEM privado RS*, se extrae la pública automáticamente.
  • TokenExpiredError / InvalidTokenError ayudan a distinguir expirados de inválidos.

9. Manejo de errores

Excepción Cuándo ocurre
AuthenticationError auth back devuelve 401/403 (credenciales inválidas)
HTTPError otro status HTTP (500, 404, etc.)
InvalidTokenError firma inválida / JWKS no coincide
TokenExpiredError el JWT está expirado

Consejos:

  • Revisa que AUTH_SDK_JWKS_URL apunte al .well-known/jwks.json de tokens.back (no al de cidi-auth).
  • Si Cloudflare bloquea el JWKS, verifica los headers (el SDK usa un User-Agent tipo Chrome).
  • Usá local_secret como fallback sólo mientras resuelves problemas de networking.

10. Referencia de settings

Setting Default Descripción
AUTH_SDK_JWKS_URL None (requerido) URL al JWKS (https://…/.well-known/jwks.json)
AUTH_SDK_ALGORITHMS ["RS256"] Algoritmos aceptados
AUTH_SDK_LOCAL_SECRET None PEM local (fallback)
AUTH_SDK_AUDIENCE None Audiencia esperada (si querés validar aud)
AUTH_SDK_HEADER_PREFIXES ["token", "bearer"] Prefijos aceptados en Authorization
AUTH_SDK_COOKIE_NAME None Nombre de cookie con el access token
AUTH_SDK_REQUIRED_TOKEN_TYPE None Forzado en subclases (ej. refresh)

11. Tests del SDK

cd sdks/python
pip install -e ".[dev]"
pytest

Usa responses + claves RSA realistas para validar JWKS, fallback local y errores.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

boolean_auth_sdk-0.1.0.tar.gz (15.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

boolean_auth_sdk-0.1.0-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

File details

Details for the file boolean_auth_sdk-0.1.0.tar.gz.

File metadata

  • Download URL: boolean_auth_sdk-0.1.0.tar.gz
  • Upload date:
  • Size: 15.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for boolean_auth_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 85468c4d2d5d07e9f507f7dd49f9f2b79b7d1399f6e350226975fc79cf563f81
MD5 98723f761ba3b9c530d973112df8962c
BLAKE2b-256 214fe2af1bf469fda24433769585c6972dbf744127ed386f435a17406ca1160c

See more details on using hashes here.

File details

Details for the file boolean_auth_sdk-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for boolean_auth_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 22b6a1e6b5940f2b7d847b86a9911f927ebe8afebfee63078f8bd1753c3a7ffb
MD5 ccd2c23f4f3e53ef38156338c26ded22
BLAKE2b-256 38c07384e7fa302e8810ded9a14eaad26d362bf71fcd9031f94d2408ff9117f2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page