Autenticación SSO y OAuth
Configura el inicio de sesión con Google, GitHub, HuggingFace y OIDC genérico en Potato. Restringe el acceso por dominio de correo u organización de GitHub, y combina SSO con el inicio de sesión local con contraseña.
Nuevo en v2.3.0
De forma predeterminada, Potato usa un inicio de sesión simple basado en nombre de usuario, en el que los anotadores escriben cualquier nombre de usuario para entrar. Eso sirve para el desarrollo local y los proyectos pequeños, pero los despliegues en producción necesitan una autenticación adecuada para impedir el acceso no autorizado, confirmar la identidad de los anotadores y cumplir los requisitos institucionales.
El SSO se configura en un solo lugar. Establece authentication.method en oauth y enumera uno o más proveedores bajo authentication.providers. Cada proveedor tiene su propio botón en la página de inicio de sesión.
Potato incluye metadatos de endpoints integrados para tres proveedores: google, github y huggingface. Cualquier otro nombre de proveedor se trata como OIDC genérico y necesita una discovery_url.
Inicio rápido
Una configuración mínima de Google:
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
user_identity_field: "email"
secret_key: ${POTATO_SECRET_KEY}Define los secretos en el entorno y no en el archivo:
export GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="your-client-secret"
export POTATO_SECRET_KEY="$(python3 -c 'import secrets; print(secrets.token_hex(32))')"secret_key es una clave de nivel superior y no forma parte del bloque authentication. Defínela, o define POTATO_SECRET_KEY. Si no hay ninguna de las dos, Potato genera una clave aleatoria, lo que significa que cada reinicio invalida todas las sesiones, y registra una advertencia cuando OAuth está configurado sin ella.
Potato sirve dos rutas OAuth. /auth/login/<provider> inicia el flujo y /auth/callback/<provider> recibe la respuesta. El callback es la URL que registras en el proveedor, así que para Google es https://your-domain.com/auth/callback/google. No existe una clave de configuración redirect_uri; la ruta se deriva del nombre del proveedor.
Crea credenciales OAuth 2.0 de tipo "Web application" en la Google Cloud Console y añade https://your-domain.com/auth/callback/google como URI de redireccionamiento autorizada. Para el desarrollo local se acepta http://localhost:8000/auth/callback/google.
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
allowed_domain: "umich.edu"allowed_domain recibe una sola cadena de dominio. Solo pueden iniciar sesión las cuentas cuyo correo pertenece a ese dominio.
GitHub
Registra una OAuth app en GitHub Settings > Developer settings > OAuth Apps, con la URL de callback establecida en https://your-domain.com/auth/callback/github.
authentication:
method: "oauth"
providers:
github:
client_id: ${GITHUB_CLIENT_ID}
client_secret: ${GITHUB_CLIENT_SECRET}
allowed_org: "my-research-lab"allowed_org recibe un solo nombre de organización. Cuando está definido, Potato solicita automáticamente el scope read:org, así que no necesitas enumerar los scopes tú mismo. El anotador debe tener una membresía pública en la organización para que la comprobación la vea.
HuggingFace
Crea una aplicación OAuth en huggingface.co/settings/applications.
authentication:
method: "oauth"
providers:
huggingface:
client_id: ${HF_CLIENT_ID}
client_secret: ${HF_CLIENT_SECRET}
user_identity_field: "username"El proveedor de HuggingFace se conecta al endpoint de descubrimiento OIDC de HuggingFace y solicita openid profile email de forma predeterminada.
OIDC genérico
Cualquier nombre de proveedor distinto de google, github y huggingface se trata como OIDC genérico y requiere discovery_url. Dale un display_name para que el botón de inicio de sesión sea legible.
authentication:
method: "oauth"
providers:
oidc:
display_name: "University SSO"
discovery_url: "https://sso.university.edu/.well-known/openid-configuration"
client_id: ${OIDC_CLIENT_ID}
client_secret: ${OIDC_CLIENT_SECRET}
scopes:
- "openid"
- "email"
- "profile"La URL de callback que registras en el proveedor sigue la clave del proveedor, así que un bloque llamado oidc usa https://your-domain.com/auth/callback/oidc.
URL de descubrimiento de proveedores habituales:
| Proveedor | URL de descubrimiento |
|---|---|
| Okta | https://your-org.okta.com/.well-known/openid-configuration |
| Azure AD | https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration |
| Auth0 | https://your-domain.auth0.com/.well-known/openid-configuration |
| Keycloak | https://keycloak.example.com/realms/{realm}/.well-known/openid-configuration |
scopes tiene como valor predeterminado ["openid", "email", "profile"].
Varios proveedores
providers admite tantas entradas como necesites, y cada una muestra su propio botón de inicio de sesión.
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
github:
client_id: ${GITHUB_CLIENT_ID}
client_secret: ${GITHUB_CLIENT_SECRET}
oidc:
display_name: "University SSO"
discovery_url: "https://sso.university.edu/.well-known/openid-configuration"
client_id: ${OIDC_CLIENT_ID}
client_secret: ${OIDC_CLIENT_SECRET}Con user_identity_field: "email", una persona que inicia sesión con Google y más tarde con el proveedor de la universidad usando la misma dirección es el mismo usuario de Potato, y vuelve a sus mismas asignaciones.
Identidad y registro automático
user_identity_field decide qué claim del proveedor se convierte en el nombre de usuario de Potato. Acepta email, username, sub o name, y su valor predeterminado es email. El valor importa porque los directorios de salida de los anotadores llevan el nombre del usuario, así que cambiarlo a mitad de un estudio separa a un anotador de su trabajo anterior.
auto_register controla si un primer inicio de sesión correcto crea la cuenta de Potato. Su valor predeterminado es true.
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
allowed_domain: "umich.edu"
user_identity_field: "email"
auto_register: trueEl control de acceso pasa por el proveedor y no por una lista de direcciones en la configuración. Para limitar quién puede iniciar sesión, usa allowed_domain en Google, allowed_org en GitHub, o los controles de grupos y asignación de aplicaciones de tu proveedor OIDC.
Modo mixto
allow_local_login añade el formulario de usuario y contraseña debajo de los botones de SSO. Su valor predeterminado es false, así que el SSO sustituye al inicio de sesión local a menos que lo actives.
require_password: true
user_config:
allow_all_users: true
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
allow_local_login: trueUna migración usa ambos durante un tiempo. Pasa a los anotadores al proveedor y luego elimina allow_local_login cuando todos hayan iniciado sesión a través de él. El modo mixto también sirve para estudios que combinan anotadores de la institución con anotadores externos que no tienen cuenta en tu institución.
Las cuentas locales en modo mixto usan el mismo hash PBKDF2 con sal que cualquier otra cuenta con contraseña. Consulta Gestión de contraseñas para los flujos de restablecimiento.
Sesiones
La duración de la sesión es una clave de nivel superior, en días:
session_lifetime_days: 7Una secret_key estable es lo que permite que las sesiones sobrevivan a un reinicio.
Acceso de administrador
Los endpoints de administración se autentican con una clave de API y no mediante el bloque OAuth:
admin_api_key: ${POTATO_ADMIN_API_KEY}Potato lee admin_api_key primero de la configuración y después de la variable de entorno POTATO_ADMIN_API_KEY. Si ninguna está definida, genera una clave y la escribe en admin_api_key.txt en el directorio de la tarea. Quien llama la presenta en el encabezado X-API-Key.
HTTPS
Los proveedores OAuth exigen URI de redireccionamiento HTTPS en producción. localhost está exento, así que el desarrollo sobre HTTP funciona sin certificado.
Detrás de un proxy inverso, reenvía el esquema original, o la URL de callback que construye Potato usará http y el proveedor la rechazará:
location / {
proxy_pass http://localhost:8000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}Referencia de configuración
| Clave | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
authentication.method | string | in_memory | in_memory, database, clerk o oauth |
authentication.providers | dict | obligatorio para oauth | Una entrada por proveedor, con el nombre del proveedor como clave |
authentication.user_identity_field | string | email | email, username, sub o name |
authentication.allow_local_login | bool | false | Muestra el formulario de contraseña junto a los botones de SSO |
authentication.auto_register | bool | true | Crea la cuenta de Potato en el primer inicio de sesión |
secret_key | string | aleatorio | De nivel superior. Se necesita un valor estable para que las sesiones persistan |
session_lifetime_days | int | 7 | Duración de la sesión, de nivel superior |
admin_api_key | string | generado | Clave de nivel superior para los endpoints de administración |
Claves por proveedor:
| Clave | Tipo | Obligatoria | Descripción |
|---|---|---|---|
client_id | string | sí | Proporcionado por el proveedor |
client_secret | string | sí | Proporcionado por el proveedor |
discovery_url | string | para OIDC genérico | Endpoint de descubrimiento OIDC |
display_name | string | no | Texto del botón de inicio de sesión |
allowed_domain | string | no | Restringe a un dominio de correo |
allowed_org | string | no | Restringe a una organización de GitHub |
scopes | list | no | Valor predeterminado ["openid", "email", "profile"] |
Ejemplo completo
annotation_task_name: "Annotation Project"
task_dir: "."
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
allowed_domain: "umich.edu"
user_identity_field: "email"
auto_register: true
secret_key: ${POTATO_SECRET_KEY}
session_lifetime_days: 7
admin_api_key: ${POTATO_ADMIN_API_KEY}
data_files:
- "data/instances.jsonl"
item_properties:
id_key: id
text_key: text
annotation_schemes:
- annotation_type: radio
name: sentiment
description: "What is the sentiment of this text?"
labels: [Positive, Neutral, Negative]
output_annotation_dir: "output/"
export_annotation_format: "jsonl"Solución de problemas
El proveedor rechaza la URI de redireccionamiento. La URI registrada en el proveedor debe coincidir exactamente con /auth/callback/<provider>. El esquema y cualquier ruta final cuentan para la coincidencia, así que un proxy que no reenvía X-Forwarded-Proto produce un callback http que el proveedor rechaza.
Todos pierden la sesión tras un reinicio. secret_key no está definida, así que Potato generó una nueva al arrancar.
Una restricción por organización de GitHub rechaza a un miembro. Su membresía en la organización es privada. O la hace pública, o eliminas allowed_org y controlas el acceso de otra forma.
La validación falla con "providers is required". method: "oauth" necesita al menos una entrada bajo providers. El valor del método es oauth, no el nombre de un proveedor.
Lecturas adicionales
- Gestión de contraseñas -- cuentas locales, hash y flujos de restablecimiento
- Inicio de sesión sin contraseña -- acceso solo con nombre de usuario para tareas abiertas
- Integración de crowdsourcing -- autenticación en plataformas de crowdsourcing
- Panel de administración -- gestión de usuarios y permisos
Para detalles de implementación, consulta la documentación fuente.