--- description: "Autorização OAuth opt-in no Streamable HTTP do tdmcp, com PKCE S256 e consentimento nativo fail-closed no TouchDesigner." --- # OAuth, PKCE & consentimento no TouchDesigner O tdmcp pode proteger o endpoint Streamable HTTP `/mcp` com um authorization server opt-in no processo Node. O Node é dono de discovery, registro de clientes, authorization codes e tokens. O TouchDesigner só apresenta uma decisão limitada **Allow / Deny** na inbox não modal de Interactions. Codes, verifier PKCE, state OAuth e bearer tokens nunca entram no projeto TD. Esse modo atende um deployment tdmcp de owner único. Para identidade compartilhada, federada ou multiusuário, use um authorization server/IdP externo. ## Compatibilidade e modos `TDMCP_HTTP_AUTH_MODE` aceita: | Modo | Significado | | --- | --- | | `auto` | Default compatível: usa `static` quando `TDMCP_HTTP_AUTH_TOKEN` existe; caso contrário, `none`. OAuth nunca é ativado implicitamente. | | `none` | Sem bearer no HTTP. O startup recusa um token estático que seria ignorado. | | `static` | Bearer pré-compartilhado legado. Isso não é OAuth. | | `oauth` | Authorization code com PKCE S256 obrigatório. O startup recusa token estático. | | `hybrid` | Migração explícita que aceita access tokens OAuth e o bearer estático configurado. | Não existe downgrade silencioso: combinações inválidas falham no startup. O bearer do bridge (`TDMCP_BRIDGE_TOKEN`) é outra credencial e continua autenticando as requests REST do Node para o TD. ## Setup local em loopback HTTP sem TLS só é aceito como exceção explícita de desenvolvimento em loopback numérico. `localhost`, bind wildcard e HTTP fora de loopback são recusados. ```bash export TDMCP_TRANSPORT=http export TDMCP_HTTP_HOST=127.0.0.1 export TDMCP_HTTP_PORT=3939 export TDMCP_HTTP_AUTH_MODE=oauth export TDMCP_PUBLIC_BASE_URL=http://127.0.0.1:3939 export TDMCP_OAUTH_ALLOW_INSECURE_LOOPBACK=1 export TDMCP_BRIDGE_TOKEN='segredo-separado-do-bridge' tdmcp ``` Uso público/produção exige uma origem HTTPS canônica em `TDMCP_PUBLIC_BASE_URL`, Host externo exato, diretório de estado privado e terminação TLS num reverse proxy confiável na mesma máquina. O listener HTTP do Node continua em loopback numérico; binds OAuth wildcard/LAN falham no startup para impedir exposição cleartext direta. ## Política de clientes e redirects A Wave 11 expõe Dynamic Client Registration limitado somente para clientes públicos: - authorization code e refresh token rotativo; - `token_endpoint_auth_method: "none"`; - scope exato `tdmcp:access` e resource exato `/mcp`; - `code_challenge_method=S256` obrigatório; PKCE plain ou ausente é recusado; - callbacks HTTP em loopback numérico com porta explícita; - callbacks fora de loopback somente em HTTPS e em origins listadas em `TDMCP_OAUTH_REDIRECT_ORIGINS`. Clientes públicos registrados têm **sete dias de validade de inatividade por default** (limitada internamente entre uma hora e 365 dias). O relógio começa no registro e avança na emissão/renovação de tokens relevante para segurança, não num lookup de cliente não autenticado. Ao vencer, um cliente sem token vivo é podado. No limite de 128 clientes, um novo registro primeiro remove o cliente tokenless mais antigo; qualquer cliente que ainda seja dono de access/refresh token não vencido e não revogado é preservado. Essa validade existe na construção da policy deste código-fonte, não como variável de ambiente documentada. O DCR não autenticado usa um bucket de recarga contínua por origem opaca (20 registros/hora por default), sob um teto global separado de 16 vezes essa taxa, limitado a 3.600. O estado é limitado a 256 origens e expira após duas horas. Requests diretas usam o peer numérico do socket. Headers de forwarding só são aceitos quando o peer imediato e cada hop de proxy removido estão fixados em `TDMCP_OAUTH_TRUSTED_PROXY_HOPS`; forwarding ambíguo, não numérico, não confiável ou divergente do host/protocolo canônico falha fechado. As chaves por origem são hashes locais do processo e nunca são retornadas ou registradas. Client ID Metadata Documents não entram nesta wave. DCR é o caminho suportado para registro de cliente público; clientes que exigem CIMD dependem de uma wave posterior com threat model próprio. O discovery do resource existe somente em `/.well-known/oauth-protected-resource/mcp`; o endpoint legado na raiz retorna 404 intencionalmente. Metadata do authorization server fica em `/.well-known/oauth-authorization-server`. ## Consentimento nativo e falhas Abrir `/authorize` devolve imediatamente uma página pequena `202`; a request original não fica aberta aguardando o TouchDesigner. A inbox do TD mostra nome limitado e autoafirmado do cliente, redirect, resource e scope com choices exatas **Allow / Deny**. Somente um **Allow** consumido e vinculado ao alvo pode criar o code. O contrato fail-closed mapeia close, timeout, disconnect, consumo duplicado, fila cheia, Perform Mode, UI ausente/headless, erro de agendamento ou shutdown do Node para **Deny**. Uma sandbox descartável TD 2025.32820 passou Allow, Deny, timeout, close, disconnect e negação em Perform Mode pelo transporte de callback nativo. TD realmente headless, clique físico do ponteiro e deployment HTTPS/TLS de produção seguem UNVERIFIED. Panic, blackout e emergências nunca esperam consentimento OAuth. `TDMCP_BRIDGE_ALLOW_EXEC=0` segue suportado porque o fluxo usa routes estruturadas e autenticadas, não `/api/exec`. O diretório OAuth guarda metadata pública de clientes e digests HMAC de access/refresh tokens em arquivos privados e promovidos atomicamente. Tokens raw, authorization codes e consentimentos pendentes não são persistidos. Access tokens duram 15 minutos por default; refresh tokens duram 30 dias e rotacionam a cada uso. ## Exemplos de evidência ```json { "status": "PASS", "evidence": "o fluxo offline emitiu token com scope somente após Allow simulado; o DCR podou rows tokenless vencidas, removeu a tokenless mais antiga na capacidade e reteve a owner de token vivo" } ``` ```json { "status": "FAIL", "evidence": "o startup recusou oauth junto com bearer estático em vez de fazer downgrade silencioso" } ``` ```json { "status": "UNVERIFIED", "reason": "o prompt TD-native integrado final não foi exercitado numa sandbox descartável nova", "checks": ["Allow e Deny no TD 2025.32820", "UI Perform/headless", "deployment HTTPS de produção"] } ``` Prova offline não é prova live no TouchDesigner. Mantenha as linhas finais como UNVERIFIED até uma sandbox isolada executar o fluxo sem alerta de thread conflict. ## Referência de configuração Veja [Variáveis de ambiente](/pt/reference/environment) para limites de body, origins de redirect, paths de estado e TTLs limitados. Hoje não existe variável de ambiente pública para a inatividade do cliente registrado. `tdmcp status` informa somente o modo HTTP resolvido; nunca imprime tokens ou o bearer do bridge.