JWT-authenticated MCP servers with login flows
Your API issues JWTs after a username/password login. Here's how to configure Cast to handle the full token lifecycle.
JWT vs OAuth β what's different here?
Cast's Bearer Token mode is for static tokens stored once. For APIs that issue short-lived JWTs after a username/password login, you combine Bearer auth with Custom Params: Cast uses the credentials to call your login endpoint, obtains a JWT, and injects it as Authorization: Bearer <token> on every tool call β refreshing transparently before expiry.
1. Start the test server in jwt mode
cd cast-mcp/test-server npx ts-node src/index.ts --mode jwt --port 3456
π JWT login endpoint: POST http://localhost:3456/auth/login
Sample credentials:
username: admin password: password
username: alice password: alice123
π Refresh endpoint: POST http://localhost:3456/auth/refreshTokens are short-lived (15 min). The refresh token lasts 7 days. Cast handles both.
2. Create a workspace and upload the spec
New workspace β Upload β http://localhost:3456/openapi.json.
3. Configure auth β Bearer Token
Switch to Configure. Select Bearer Token. Leave the token value empty β we acquire the token dynamically via the login endpoint configured in the next step.
API Base URL
Bearer Token
Authorization: Bearer <token>
API Key Header
X-Api-Key: <key>
Custom Headers
Any header name + value
OAuth 2.0
PKCE Β· DCR support
Bearer Token
Stored encrypted β never visible after saving.
The key insight: you're not entering a static token here. You're telling Cast "use Bearer auth" so it knows which header to inject. The actual token comes from the login flow below.
4. Add custom injection params
Next to the Save button is a sliders icon β click it to open Custom Params. These are workspace-level key/value pairs Cast stores encrypted and makes available at request time. Add the three params below.
Custom params are stored encrypted with AES-256-GCM β same as all other secrets in Cast. They are injected server-side and never exposed to MCP clients.
How Cast acquires and caches the token
{
"username": "admin",
"password": "password"
}
// Response
{
"accessToken": "eyJ...",
"refreshToken": "...",
"expiresIn": 900
}Cast caches the access token in Redis for expiresIn β 30 seconds, then re-authenticates automatically. If the server issues a refresh token, Cast uses it to extend the session without a full re-login.
5. Enable tools
listItems
/api/items
createItem
/api/items
listUsers
/api/users
getStats
/api/stats
deleteItem
/api/items/{id}
6. Connect and test
{
"mcpServers": {
"test-jwt": {
"command": "npx",
"args": [
"-y",
"mcp-remote@latest",
"https://mcp.getcast.io/test-jwt-cmpquev5h000a"
]
}
}
}On the first tool call, Cast logs in, gets a token, and immediately calls the tool β all in one round trip from the client's perspective. Open the Logs tab to see both the login request and the tool call in sequence.
After 15 minutes, the access token expires. Cast calls POST /auth/refresh automatically. Your MCP client never notices.