Autorização gerenciada por empresa com ID-JAG
Este guia explica a Enterprise-Managed Authorization, uma extensão da especificação de autorização MCP para empresas: o provedor de identidade corporativo (IdP) decide quais servidores MCP um funcionário pode usar, e o cliente MCP obtém seus tokens sem um login via navegador em cada servidor. O Casdoor assume qualquer um dos papéis:
- O servidor de autorização dos servidores MCP: O Casdoor aceita os ID-JAGs de um IdP corporativo confiável para a organização.
- O IdP corporativo: O Casdoor emite ID-JAGs para servidores MCP cujo servidor de autorização confia nele.
Resultados da aprendizagem
- Entenda o fluxo e o que é um ID-JAG.
- Permita que uma organização do Casdoor confie nos ID-JAGs de um IdP corporativo.
- Emita ID-JAGs a partir do Casdoor.
O que você precisa
- Acesso de administrador global ao console de administração do Casdoor
- Um cliente MCP que suporte a extensão, por exemplo, Claude Team ou Enterprise com Okta Cross App Access
Como funciona
Um ID-JAG (Identity Assertion JWT Authorization Grant) é um JWT de curta duração assinado pelo IdP. Ele afirma: este usuário pode usar este cliente neste servidor de autorização. Ele é definido em draft-ietf-oauth-identity-assertion-authz-grant, e a extensão MCP io.modelcontextprotocol/enterprise-managed-authorization baseia-se nele. Veja Enterprise-Managed Authorization.
O usuário nunca vê a página de login do Casdoor. Quando o IdP bloqueia o usuário, por exemplo, após ele deixar a empresa, o cliente não recebe novos ID-JAGs, nem novos tokens de acesso.
Aceitar ID-JAGs no Casdoor
Confiar no IdP
-
No console de administração do Casdoor, vá para User Management > Organizations e abra a organização dos usuários, por exemplo,
acme. -
Opcionalmente, ative Use organization issuer, para que a organização tenha seu próprio emissor,
https://your-casdoor.com/orgs/acme. Caso contrário, o emissor será o global,https://your-casdoor.com. -
Em Trusted ID-JAG issuers, adicione uma linha:
Column Value Issuer O issdos ID-JAGs, por exemplo,https://acme.okta.comJWKS URL O conjunto de chaves do IdP. Se você deixá-lo vazio, o Casdoor lê jwks_uride<issuer>/.well-known/openid-configurationUser Como encontrar o usuário na organização: {email}(o padrão) usa a claimemail,{sub}usa a claimsub, qualquer{claim}usa aquela claim. O Casdoor faz a correspondência contra o nome de usuário, email, telefone e ID -
Salve a organização. Apenas um administrador global pode alterar os emissores confiáveis.
No IdP, dê ao Casdoor o emissor da organização como audiência dos ID-JAGs, e as URLs dos servidores MCP como recursos. Para um servidor atrás do MCP gateway, isso é https://your-casdoor.com/api/server/acme/<server-name>.
Deixe o cliente usar a concessão
O cliente resgata o ID-JAG no endpoint de token usando a concessão de portador JWT (urn:ietf:params:oauth:grant-type:jwt-bearer), portanto, o tipo de concessão deve ser permitido para sua aplicação:
- Claude: Seu documento de metadados de ID de cliente
https://claude.ai/oauth/mcp-oauth-client-metadatalista a concessão. Ative Enable dynamic client registration para a organização, para que o Casdoor aceite o documento. Veja Connect Claude. - Uma aplicação que você criar: Adicione JWT Bearer aos seus Grant types.
O que o cliente envia
curl -X POST https://your-casdoor.com/api/login/oauth/access_token \
-d grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \
-d client_id=<client-id> \
-d client_secret=<client-secret> \
-d assertion=<ID-JAG>
O Casdoor responde com um token de acesso cuja audiência é o resource do ID-JAG:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 604800,
"scope": "openid profile"
}
O que o Casdoor verifica
| Verificação | Regra |
|---|---|
| Tipo | O cabeçalho do JWT tem typ: oauth-id-jag+jwt. Outras asserções passam pela concessão de portador JWT comum |
| Cliente | Um cliente confidencial se autentica, com seu segredo de cliente ou private_key_jwt. Um cliente público de um documento de metadados de ID de cliente, como o Claude, não tem segredo e envia apenas client_id |
| Audiência | aud é o emissor de uma organização com seu próprio emissor, ou o emissor global, que representa a organização da aplicação do cliente |
| Emissor e assinatura | iss é um emissor confiável dessa organização, e a chave com o kid do cabeçalho em seu JWKS verifica a assinatura |
| Validade | exp e iat estão presentes e são válidos, com um minuto de tolerância |
| Vínculo do cliente | client_id é igual ao ID do cliente do cliente que o resgata |
| Uso único | O Casdoor aceita cada jti de um emissor uma única vez |
| Usuário | O usuário encontrado através de User existe na organização, não está bloqueado e pode fazer login na aplicação do cliente |
| Escopo | Um scope na solicitação deve ser um subconjunto do scope do ID-JAG. Sem um, o token obtém o escopo do ID-JAG |
| Recurso | resource, quando presente, torna-se a audiência do token de acesso |
Um cliente que se registrou automaticamente (DCR) ou usa um documento de metadados de ID de cliente pode usar a concessão de portador JWT apenas com um ID-JAG.
Erros
| Error | Cause |
|---|---|
invalid_client | Um cliente confidencial não se autenticou |
invalid_grant | O ID-JAG falhou em uma das verificações: audiência incorreta, emissor não confiável, assinatura inválida, expirado, emitido para outro cliente, usado anteriormente, ou o usuário não existe |
invalid_scope | A solicitação pede um escopo que o ID-JAG não concede |
invalid_target | O resource do ID-JAG não é uma URI absoluta |
unsupported_grant_type | O JWT Bearer não está entre os tipos de concessão da aplicação do cliente |
Os metadados do servidor de autorização anunciam o suporte: grant_types_supported contém urn:ietf:params:oauth:grant-type:jwt-bearer, e authorization_grant_profiles_supported contém urn:ietf:params:oauth:grant-profile:id-jag.
Emitir ID-JAGs pelo Casdoor
Quando o Casdoor é o IdP da empresa, um cliente troca o token de ID do usuário por um ID-JAG no endpoint de token do Casdoor, usando a troca de tokens (RFC 8693):
curl -X POST https://your-casdoor.com/api/login/oauth/access_token \
-d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \
-d client_id=<client-id> \
-d client_secret=<client-secret> \
-d requested_token_type=urn:ietf:params:oauth:token-type:id-jag \
-d subject_token=<ID token of the user> \
-d subject_token_type=urn:ietf:params:oauth:token-type:id_token \
-d audience=https://mcp-as.example.com \
-d resource=https://mcp.example.com/mcp \
-d scope="openid profile"
{
"issued_token_type": "urn:ietf:params:oauth:token-type:id-jag",
"access_token": "eyJ0eXAiOiJvYXV0aC1pZC1qYWcrand0Ii...",
"token_type": "N_A",
"expires_in": 300,
"scope": "openid profile"
}
Configure-o da seguinte forma:
- Adicione Token Exchange aos Grant types da aplicação do cliente.
- Registre o servidor MCP na página LLM AI > MCP Servers da organização do usuário, com sua URL como
resource, e selecione uma Application que o represente. Sem umresource, o Casdoor encontra a aplicação peloaudience, como um client ID ou nome da aplicação. - Conceda acesso aos usuários: adicione uma permissão com Resource type
Application, a aplicação do servidor como recurso, e EffectAllow. O Casdoor emite um ID-JAG apenas para um usuário coberto por uma permissãoAllow, então uma aplicação sem concedida permanece fechada.
O ID-JAG é válido por 5 minutos. Seu aud é o audience da solicitação, client_id é o client ID da aplicação solicitante, e ele carrega o email do usuário, o resource e o scope. O servidor de autorização do servidor MCP deve confiar no emissor do Casdoor, e o cliente deve usar o mesmo client ID lá, por exemplo, a URL do documento de metadados do seu client ID.