Minted JWT Mode
This page describes the minted-jwt mode for the engine REST authentication of the REST API MCP Plugin.
In minted-jwt mode, the MCP server translates the validated external identity into a freshly minted, short-lived CIB seven JWT, signed with the shared secret cibseven.webclient.authentication.jwtSecret. This is exactly the token format that the engine REST API already accepts from the CIB seven webapp, for example with the Composite authentication provider.
Use this mode when the user id in the inbound token cannot be matched to the user id stored in the engine, which makes passthrough mode impossible. A typical case is Microsoft Entra ID with LDAP: the token provides the UPN (preferred_username), while the engine stores the sAMAccountName. The MCP server resolves the right user id and puts it into the minted JWT, which the engine REST API accepts like any other CIB seven JWT.
- The engine REST API needs no OAuth2 configuration.
- The engine REST API never sees the external token, so the audience concern of the passthrough mode does not apply.
- The configured identity provider (for example, LDAP) stays authoritative for groups and authorizations.
cibseven:
mcp:
engine-rest:
auth: minted-jwt
minted-jwt:
resolver: graph # or: claim | static
ttl-seconds: 60
webclient:
authentication:
jwtSecret: ${CIBSEVEN_JWT_SECRET}
Resolving the User Id
The CIB seven user id placed into the minted JWT is produced by an UserIdResolver. The following resolvers are available:
claim (default)
Reads the claim configured in cibseven.mcp.engine-rest.minted-jwt.user-id-claim (default preferred_username) directly from the inbound token.
This is only correct if the claim value equals the user id stored in the engine exactly, including case. Verify this before relying on it, for example with:
SELECT DISTINCT USER_ID_ FROM ACT_RU_AUTHORIZATION
graph
It resolves the immutable Microsoft Entra ID object id (oid) to the on-premises sAMAccountName via Microsoft Graph. Results are cached for 8 hours. Use this resolver when no Entra ID claim matches the stored user id 1:1, which is the common case for LDAP-based production environments.
It requires an OAuth2 client registration named graph using the client_credentials grant, with the application permission User.Read.All granted with admin consent. The required OAuth2AuthorizedClientManager is provided automatically when resolver is set to graph:
spring:
security:
oauth2:
client:
registration:
graph:
client-id: ${GRAPH_CLIENT_ID}
client-secret: ${GRAPH_CLIENT_SECRET}
authorization-grant-type: client_credentials
scope: https://graph.microsoft.com/.default
provider: entra
provider:
entra:
token-uri: https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token
Required dependency
The graph resolver needs spring-boot-starter-oauth2-client on the classpath of the host application.
static
Ignores the caller’s identity and always uses the user id configured in cibseven.mcp.engine-rest.minted-jwt.static.user-id. This is the easiest way to try out minted-jwt mode locally, as it requires neither a Graph registration nor a claim mapping.
Use the static resolver for development and testing only: every caller is impersonated as the configured user.
Custom Resolver
A host application can provide its own UserIdResolver bean, which overrides the built-in resolvers.
Security Considerations
Impersonation capability
In minted-jwt mode the (internet-reachable) MCP server holds the shared secret and can therefore mint a token for any user id, including administrators. To limit this risk:
- Keep the secret in a real secret store, never in the container image or the source repository.
- Plan for secret rotation.
- Keep the token lifetime short (60 seconds by default).
- Isolate the engine REST API at network level, so that only the MCP server and the webapp can reach it.
Network Exposure
When the MCP server is used with claude.ai, the connection is established from Anthropic’s cloud over the public internet. The MCP endpoint must therefore be publicly reachable; restrict inbound traffic to Anthropic’s IP ranges. The engine REST API itself stays internal.