Skip to main content

HS256 with shared secret

Use HS256 when the token issuer and the MCP server share the same symmetric secret. The MCP server validates a Bearer token on every request — suitable for production when you control both sides of authentication.

Video walkthrough

When to use HS256

Use this method for private deployments where you issue JWTs yourself. For OAuth/OIDC providers with key rotation, RS256 with JWKS is the better fit.

1. Generate a shared secret

Create a strong random secret. Use the same value in superset_config.py and wherever you sign JWT tokens.

Option A — OpenSSL (recommended):

openssl rand -base64 42

Option B — Python:

python3 -c "import secrets; print(secrets.token_urlsafe(32))"

Copy the output and store it in a password manager or secrets vault. Example output:

K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=
Keep the secret private

Never commit MCP_JWT_SECRET to git, paste it in chat, or hardcode it in client apps. Treat it like a password.

2. Configure superset_config.py

Enable JWT validation and set a delegated Superset user for tool execution:

MCP_AUTH_ENABLED = True
MCP_DEV_USERNAME = "admin" # Superset user that runs MCP tool calls

MCP_JWT_ALGORITHM = "HS256"
MCP_JWT_SECRET = "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols="
MCP_JWT_ISSUER = "superset-mcp"
MCP_JWT_AUDIENCE = "superset-mcp-clients"

Replace the example secret with your own generated value. Set the issuer and audience to values you will also use when signing tokens — they must match exactly. MCP_DEV_USERNAME must be an existing Superset username (for example admin).

Superset 6.1.x requires MCP_DEV_USERNAME with JWT

In Superset 6.1.x, JWT authentication validates the Bearer token at the HTTP transport layer, but tool calls do not yet resolve the Superset user from JWT claims. You must set MCP_DEV_USERNAME so MCP tools can execute — all authenticated requests run as that user.

Per-user JWT identity mapping is fixed on the Superset master branch. Until you upgrade to a release that includes that fix, keep MCP_DEV_USERNAME set even when JWT auth is enabled.

Restart both processes after saving the config:

./run_superset.sh
./run_superset_mcp.sh

3. Generate a JWT for AI clients

The token must be signed with the same secret, algorithm, issuer, and audience. The sub claim must match an existing Superset username (for example admin).

Activate your Superset virtual environment and run:

import datetime
import jwt

SECRET = "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" # same as MCP_JWT_SECRET
ISSUER = "superset-mcp"
AUDIENCE = "superset-mcp-clients"
USERNAME = "admin" # must exist in Superset ab_user table

payload = {
"sub": USERNAME,
"iss": ISSUER,
"aud": AUDIENCE,
"exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=24),
}

token = jwt.encode(payload, SECRET, algorithm="HS256")
print(token)

Save as generate_mcp_token.py and run:

source /app/superset/superset_env/bin/activate
python generate_mcp_token.py

Copy the printed token — you will pass it as Authorization: Bearer <token> in your AI client config.

4. Connect an AI client

Pass the token to your AI client using mcp-remote. Remote HTTP endpoints require the --allow-http flag. See Claude or Cursor for full config examples.

Debugging auth failures

If tokens are rejected at the HTTP layer, enable server-side logging:

MCP_JWT_DEBUG_ERRORS = True

Check that iss, aud, and exp in the token match your config and that the token has not expired.

If initialize succeeds but tool calls fail with "No authenticated user found", confirm MCP_DEV_USERNAME is set to a valid Superset user and restart the MCP server.