Autenticação SSO e OAuth
Configure o login com Google, GitHub, HuggingFace e OIDC genérico no Potato. Restrinja o acesso por domínio de e-mail ou organização do GitHub e use SSO junto com o login local por senha.
Novo na v2.3.0
Por padrão, o Potato usa um login simples baseado em nome de usuário, no qual os anotadores digitam qualquer nome de usuário para entrar. Isso funciona para desenvolvimento local e projetos pequenos, mas implantações em produção precisam de autenticação adequada para impedir acesso não autorizado, confirmar a identidade dos anotadores e atender a requisitos institucionais.
O SSO é configurado em um só lugar. Defina authentication.method como oauth e liste um ou mais provedores em authentication.providers. Cada provedor ganha seu próprio botão na página de login.
O Potato tem metadados de endpoint embutidos para três provedores: google, github e huggingface. Qualquer outro nome de provedor é tratado como OIDC genérico e precisa de uma discovery_url.
Início rápido
Uma configuração mínima do 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}Defina os segredos no ambiente, e não no arquivo:
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 é uma chave de nível superior e não faz parte do bloco authentication. Defina-a ou defina POTATO_SECRET_KEY. Quando nenhuma das duas está presente, o Potato gera uma chave aleatória, o que significa que cada reinicialização invalida todas as sessões, e registra um aviso no log quando o OAuth está configurado sem ela.
O Potato atende duas rotas OAuth. /auth/login/<provider> inicia o fluxo e /auth/callback/<provider> recebe a resposta. O callback é a URL que você registra no provedor, então para o Google ela é https://your-domain.com/auth/callback/google. Não existe uma chave de configuração redirect_uri; a rota é derivada do nome do provedor.
Crie credenciais OAuth 2.0 do tipo "Web application" no Google Cloud Console e adicione https://your-domain.com/auth/callback/google como URI de redirecionamento autorizado. Para desenvolvimento local, http://localhost:8000/auth/callback/google é aceito.
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
allowed_domain: "umich.edu"allowed_domain recebe uma única string de domínio. Somente contas cujo e-mail pertence a esse domínio podem fazer login.
GitHub
Registre um OAuth app em GitHub Settings > Developer settings > OAuth Apps, com a URL de callback definida como 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 recebe um único nome de organização. Quando ele está definido, o Potato solicita o escopo read:org automaticamente, então você não precisa listar os escopos. O anotador precisa ter associação pública à organização para que a verificação a enxergue.
HuggingFace
Crie um aplicativo OAuth em huggingface.co/settings/applications.
authentication:
method: "oauth"
providers:
huggingface:
client_id: ${HF_CLIENT_ID}
client_secret: ${HF_CLIENT_SECRET}
user_identity_field: "username"O provedor HuggingFace se conecta ao endpoint de descoberta OIDC do HuggingFace e solicita openid profile email por padrão.
OIDC genérico
Qualquer nome de provedor diferente de google, github e huggingface é tratado como OIDC genérico e exige discovery_url. Dê a ele um display_name para que o botão de login fique legível.
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"A URL de callback a registrar no provedor segue a chave do provedor, então um bloco chamado oidc usa https://your-domain.com/auth/callback/oidc.
URLs de descoberta de provedores comuns:
| Provedor | URL de descoberta |
|---|---|
| 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 |
O padrão de scopes é ["openid", "email", "profile"].
Vários provedores
providers aceita quantas entradas você precisar, e cada uma exibe seu próprio botão de login.
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}Com user_identity_field: "email", alguém que entra pelo Google e depois pelo provedor da universidade com o mesmo endereço é o mesmo usuário do Potato e volta para as mesmas atribuições.
Identidade e registro automático
user_identity_field define qual claim do provedor se torna o nome de usuário no Potato. Aceita email, username, sub ou name, e o padrão é email. O valor importa porque os diretórios de saída dos anotadores recebem o nome do usuário, então alterá-lo no meio de um estudo separa o anotador do trabalho que ele já fez.
auto_register controla se o primeiro login bem-sucedido cria a conta no Potato. O padrão é 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: trueO controle de acesso passa pelo provedor, e não por uma lista de endereços na configuração. Para limitar quem pode fazer login, use allowed_domain no Google, allowed_org no GitHub ou os controles de grupos e de atribuição de aplicativos do seu provedor OIDC.
Modo misto
allow_local_login adiciona o formulário de usuário e senha abaixo dos botões de SSO. O padrão é false, então o SSO substitui o login local a menos que você o ative.
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: trueUma migração mantém os dois por um tempo. Transfira os anotadores e depois remova allow_local_login quando todos tiverem entrado pelo provedor. O modo misto também atende estudos que combinam anotadores da instituição com anotadores externos que não têm conta na sua instituição.
Contas locais no modo misto usam o mesmo hash PBKDF2 com salt de qualquer outra conta com senha. Veja Gerenciamento de senhas para os fluxos de redefinição.
Sessões
A duração da sessão é uma chave de nível superior, em dias:
session_lifetime_days: 7É uma secret_key estável que faz as sessões sobreviverem a uma reinicialização.
Acesso de administrador
Os endpoints de administração se autenticam com uma chave de API, e não pelo bloco OAuth:
admin_api_key: ${POTATO_ADMIN_API_KEY}O Potato lê admin_api_key primeiro da configuração e depois da variável de ambiente POTATO_ADMIN_API_KEY. Se nenhuma estiver definida, ele gera uma chave e a grava em admin_api_key.txt no diretório da tarefa. Quem faz a chamada a envia no cabeçalho X-API-Key.
HTTPS
Provedores OAuth exigem URIs de redirecionamento HTTPS em produção. localhost é isento, então o desenvolvimento via HTTP funciona sem certificado.
Atrás de um proxy reverso, repasse o esquema original, ou a URL de callback que o Potato monta usará http e o provedor a rejeitará:
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;
}Referência de configuração
| Chave | Tipo | Padrão | Descrição |
|---|---|---|---|
authentication.method | string | in_memory | in_memory, database, clerk ou oauth |
authentication.providers | dict | obrigatório para oauth | Uma entrada por provedor, indexada pelo nome do provedor |
authentication.user_identity_field | string | email | email, username, sub ou name |
authentication.allow_local_login | bool | false | Mostra o formulário de senha junto aos botões de SSO |
authentication.auto_register | bool | true | Cria a conta no Potato no primeiro login |
secret_key | string | aleatório | Nível superior. Um valor estável é necessário para sessões persistentes |
session_lifetime_days | int | 7 | Duração da sessão, no nível superior |
admin_api_key | string | gerada | Chave de nível superior para os endpoints de administração |
Chaves por provedor:
| Chave | Tipo | Obrigatória | Descrição |
|---|---|---|---|
client_id | string | sim | Fornecido pelo provedor |
client_secret | string | sim | Fornecido pelo provedor |
discovery_url | string | para OIDC genérico | Endpoint de descoberta OIDC |
display_name | string | não | Texto do botão de login |
allowed_domain | string | não | Restringe a um domínio de e-mail |
allowed_org | string | não | Restringe a uma organização do GitHub |
scopes | list | não | Padrão ["openid", "email", "profile"] |
Exemplo 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"Solução de problemas
O provedor rejeita o URI de redirecionamento. O URI registrado no provedor precisa corresponder exatamente a /auth/callback/<provider>. O esquema e qualquer caminho final contam para a correspondência, então um proxy que não repassa X-Forwarded-Proto produz um callback http que o provedor rejeita.
Todos são desconectados depois de uma reinicialização. secret_key não está definida, então o Potato gerou uma nova na inicialização.
Uma restrição por organização do GitHub rejeita um membro. A associação dele à organização é privada. Ou ele a torna pública, ou você remove allowed_org e controla o acesso de outra forma.
A validação falha com "providers is required". method: "oauth" precisa de pelo menos uma entrada em providers. O valor do método é oauth, não o nome de um provedor.
Leitura adicional
- Gerenciamento de senhas -- contas locais, hashing e fluxos de redefinição
- Login sem senha -- acesso só com nome de usuário para tarefas abertas
- Integração com MTurk -- autenticação em plataformas de crowdsourcing
- Painel de administração -- gerenciamento de usuários e permissões
Para detalhes de implementação, consulte a documentação fonte.