-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: add token-exchange demo MCP server for testing against real identity providers #5730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| # Token Exchange (On-Behalf-Of) Demo MCP Server | ||
|
|
||
| A plain MCP resource server for exercising Bifrost's `token_exchange` MCP auth | ||
| type against a **real identity provider** — Okta, Microsoft Entra, Keycloak, | ||
| Auth0, or any generic OIDC provider. | ||
|
|
||
| ## What is This? | ||
|
|
||
| `token_exchange` moves the entire delegation dance into Bifrost and your | ||
| identity provider: on every tool call, Bifrost exchanges the caller's own | ||
| identity-provider token for one scoped to this server's audience and sends | ||
| only the exchanged token upstream. This server has no OAuth server logic of | ||
| its own — its only job is what a real internal MCP server behind token | ||
| exchange would actually do: **validate the bearer token it receives** and | ||
| prove whose identity arrived. | ||
|
|
||
| Validation is full OIDC discovery + JWKS signature verification + issuer + | ||
| audience checks via [`coreos/go-oidc`](https://github.com/coreos/go-oidc). | ||
| Nothing here trusts an unverified token; a missing, malformed, wrong-issuer, | ||
| or wrong-audience token is rejected with HTTP 401 before the MCP server ever | ||
| sees it. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| At your identity provider, register a dedicated application authorized to | ||
| perform token exchange (or the on-behalf-of grant) for an audience. See | ||
| [`docs/mcp/auth/token-exchange.mdx`](../../../docs/mcp/auth/token-exchange.mdx) | ||
| for provider-specific setup notes (Okta custom authorization servers, Entra's | ||
| `jwt-bearer` grant, etc.) — the exact steps vary by vendor. | ||
|
|
||
| You'll need: | ||
|
|
||
| - Your identity provider's **issuer URL** (its OIDC discovery document must | ||
| be reachable at `<issuer>/.well-known/openid-configuration`) | ||
| - The **audience** you registered the exchange application against | ||
| - The exchange application's **client ID**, for the Bifrost side | ||
| - The exchange application's **client secret**, for the Bifrost side — | ||
| optional, depending on your identity provider and whether the application | ||
| is registered as a public or confidential client | ||
|
|
||
| ## Running the Server | ||
|
|
||
| ### Prerequisites | ||
|
|
||
| ```bash | ||
| go 1.26.5+ | ||
| ``` | ||
|
|
||
| ### Start the Server | ||
|
|
||
| ```bash | ||
| # From this directory | ||
| TOKEN_EXCHANGE_ISSUER_URL="https://your-domain.okta.com/oauth2/your-auth-server-id" \ | ||
| TOKEN_EXCHANGE_AUDIENCE="api://your-mcp-server" \ | ||
| go run main.go | ||
| ``` | ||
|
|
||
| `TOKEN_EXCHANGE_ISSUER_URL` and `TOKEN_EXCHANGE_AUDIENCE` are both required — | ||
| the server fails fast at startup if either is missing, or if OIDC discovery | ||
| against the issuer fails. | ||
|
|
||
| `MCP_SERVER_PORT` optionally overrides the default port (`3004`). | ||
|
|
||
| Output: | ||
| ```text | ||
| token-exchange-demo-server listening on http://localhost:3004/ | ||
| Validating bearer tokens against issuer=https://your-domain.okta.com/oauth2/your-auth-server-id audience=api://your-mcp-server | ||
|
|
||
| Bifrost config: | ||
|
|
||
| { | ||
| "name": "token_exchange_demo", | ||
| "connection_type": "http", | ||
| "connection_string": "http://localhost:3004/", | ||
| "auth_type": "token_exchange", | ||
| "token_exchange": { | ||
| "audience": "api://your-mcp-server", | ||
| "client_id": "<your exchange application's client_id>", | ||
| "client_secret": "<your exchange application's client_secret>" | ||
| }, | ||
| "tools_to_execute": ["*"] | ||
| } | ||
| ``` | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| ## Connecting via Bifrost | ||
|
|
||
| Use the printed config above, filling in your exchange application's | ||
| `client_id` / `client_secret`. `auth_type: "token_exchange"` requires your | ||
| Bifrost deployment's identity-provider integration to be configured and | ||
| pointed at the same identity provider — see | ||
| [Token Exchange auth](../../../docs/mcp/auth/token-exchange.mdx#prerequisites). | ||
|
|
||
| ## Available Tools | ||
|
|
||
| ### 1. whoami | ||
|
|
||
| Returns the identity claims from the caller's exchanged token — the main | ||
| point of this server. A successful call proves the caller's own identity | ||
| reached this upstream server, not a shared credential. | ||
|
|
||
| ```json | ||
| { | ||
| "name": "whoami", | ||
| "arguments": {} | ||
| } | ||
| ``` | ||
|
|
||
| Response: | ||
| ```json | ||
| { | ||
| "sub": "00u1a2b3c4d5e6f7g8h9", | ||
| "email": "alice@example.com", | ||
| "name": "Alice Smith", | ||
| "aud": "api://your-mcp-server", | ||
| "iss": "https://your-domain.okta.com/oauth2/your-auth-server-id", | ||
| "exp": 1735689600 | ||
| } | ||
| ``` | ||
|
|
||
| ### 2. echo | ||
|
|
||
| Echoes back the input message, tagged with the caller's identity — useful | ||
| for seeing the delegated identity attached to an ordinary tool call, not just | ||
| `whoami`. | ||
|
|
||
| ```json | ||
| { | ||
| "name": "echo", | ||
| "arguments": { | ||
| "message": "Hello, World!" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Testing With Two Different Callers | ||
|
|
||
| The most useful check: call `whoami` as two different signed-in users (or | ||
| with two different bearer tokens) and confirm the response names a different | ||
| identity each time — that's the delegation working end-to-end, as opposed to | ||
| everyone hitting this server under one shared credential. | ||
|
|
||
| A caller with **no identity token at all** (e.g. a virtual-key-only request) | ||
| should fail before ever reaching this server — `token_exchange` has no | ||
| service-account fallback. | ||
|
|
||
| ## Implementation Notes | ||
|
|
||
| This example intentionally: | ||
|
|
||
| - ✅ Validates every request's bearer token via real OIDC discovery + JWKS | ||
| signature verification (issuer, audience, expiry) — no shortcuts | ||
| - ✅ Rejects with HTTP 401 on any validation failure, before the MCP server | ||
| processes the request | ||
| - ❌ Does NOT implement any OAuth authorization-server endpoints — that's | ||
| entirely Bifrost + your identity provider's job under `token_exchange` | ||
| - ❌ Does NOT cache or store anything about the caller — every request is | ||
| validated fresh, mirroring how Bifrost itself never persists a caller's | ||
| exchanged token to disk | ||
|
|
||
| ## See Also | ||
|
|
||
| - [Token Exchange (On-Behalf-Of) auth](../../../docs/mcp/auth/token-exchange.mdx) | ||
| - [MCP Authentication Overview](../../../docs/mcp/auth/overview.mdx) | ||
| - [oauth-demo-server](../oauth-demo-server) — the per-user OAuth counterpart, | ||
| which *is* a full authorization server, for when the upstream service runs | ||
| its own OAuth instead of trusting your identity provider | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| module token-exchange-demo-server | ||
|
|
||
| go 1.26.5 | ||
|
|
||
| require ( | ||
| github.com/coreos/go-oidc/v3 v3.16.0 | ||
| github.com/go-jose/go-jose/v4 v4.1.3 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
cd examples/mcps/token-exchange-demo-server
for module in \
github.com/go-jose/go-jose/v4 \
github.com/buger/jsonparser
do
echo "=== $module ==="
go list -m -u -json "$module"
go mod why -m "$module"
done
govulncheck ./...Repository: maximhq/bifrost Length of output: 2125 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '=== repository state ==='
git status --short
git diff --stat
git branch --all --no-color | head -50
printf '%s\n' '=== module files ==='
cat -n examples/mcps/token-exchange-demo-server/go.mod
printf '%s\n' '=== dependency references ==='
rg -n --hidden --glob '!vendor/**' \
'go-jose|jsonparser|mcp-go|jsonschema|go-oidc|Bearer|bearer|JWT|JWE|token' \
examples/mcps/token-exchange-demo-server
printf '%s\n' '=== stack metadata ==='
find .. -maxdepth 3 -type f \( -iname '*stack*' -o -name '.gitmodules' \) -printRepository: maximhq/bifrost Length of output: 14415 🌐 Web query:
💡 Result: The fixed version for the JWE decryption panic in github.com/go-jose/go-jose/v4 is v4.1.4 [1][2]. This vulnerability, tracked as GHSA-78h2-9frx-2jm8 and CVE-2026-34986, occurs when decrypting a JSON Web Encryption (JWE) object if the alg field specifies a key wrapping algorithm (excluding A128GCMKW, A192GCMKW, and A256GCMKW) and the encrypted_key field is empty [1][3][4]. The issue causes a panic during the key unwrap process, which can lead to a denial-of-service [1][4]. If updating to version 4.1.4 is not immediately possible, you can mitigate the risk by ensuring your application does not accept JWE tokens containing key wrapping algorithms if they are not required, or by pre-validating JWE objects to ensure the encrypted_key field is non-empty [1][3]. Citations:
🌐 Web query:
💡 Result: The denial of service vulnerability in github.com/buger/jsonparser version 1.1.1, identified as CVE-2026-32285 (also tracked as GO-2026-4514 and GHSA-6g7g-w4f8-9c9x), is fixed in version 1.1.2 [1][2][3]. This vulnerability occurs because the Delete function fails to properly validate offsets when processing malformed JSON input, which can result in a negative slice index, leading to a runtime panic and denial of service [1][2][4]. Users are advised to upgrade to version 1.1.2 or later to address this issue [1][2][3]. Citations:
🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
modroot="$(go env GOPATH)/pkg/mod"
printf '%s\n' '=== owning module requirements ==='
for f in \
"$modroot/github.com/coreos/go-oidc/v3@v3.16.0/go.mod" \
"$modroot/github.com/mark3labs/mcp-go@v0.43.2/go.mod" \
"$modroot/github.com/invopop/jsonschema@v0.13.0/go.mod" \
"$modroot/github.com/wk8/go-ordered-map/v2@v2.1.8/go.mod"
do
if test -f "$f"; then
echo "--- $f"
cat "$f"
fi
done
printf '%s\n' '=== vulnerable API usage in cached modules ==='
rg -n --glob '*.go' \
'jsonparser\.(Delete|Get|ArrayEach|ObjectEach|Parse|Set)|go-jose|jose\.(Parse|Decrypt|DecryptMulti|ParseEncrypted)|ParseEncrypted|Decrypt' \
"$modroot/github.com/coreos/go-oidc" \
"$modroot/github.com/mark3labs/mcp-go" \
"$modroot/github.com/invopop/jsonschema" \
"$modroot/github.com/wk8/go-ordered-map" 2>/dev/null || true
printf '%s\n' '=== vulnerable implementation excerpts ==='
rg -n -A35 -B10 \
'func Delete|func \(.*\) Decrypt|func \(.*\) DecryptMulti|func ParseEncrypted' \
"$modroot/github.com/buger/jsonparser@v1.1.1" \
"$modroot/github.com/go-jose/go-jose/v4@v4.1.3" 2>/dev/null || true
printf '%s\n' '=== available versions ==='
go list -m -versions github.com/buger/jsonparser
go list -m -versions github.com/go-jose/go-jose/v4Repository: maximhq/bifrost Length of output: 50373 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
modroot="$(go env GOPATH)/pkg/mod"
printf '%s\n' '=== application production imports and handlers ==='
sed -n '40,235p' examples/mcps/token-exchange-demo-server/main.go
printf '%s\n' '=== go-oidc token parsing path ==='
sed -n '190,245p' "$modroot/github.com/coreos/go-oidc/v3@v3.16.0/oidc/verify.go"
sed -n '1,55p' "$modroot/github.com/coreos/go-oidc/v3@v3.16.0/oidc/jose.go"
printf '%s\n' '=== jsonparser call sites in non-test cached code ==='
rg -n --glob '*.go' --glob '!**/*_test.go' \
'github.com/buger/jsonparser|jsonparser\.' \
"$modroot/github.com/mark3labs/mcp-go@v0.43.2" \
"$modroot/github.com/invopop/jsonschema@v0.13.0" \
"$modroot/github.com/wk8/go-ordered-map/v2@v2.1.8" \
"$modroot/github.com/mailru/easyjson@v0.7.7" 2>/dev/null || true
printf '%s\n' '=== all Delete call sites in the dependency graph ==='
rg -n --glob '*.go' --glob '!**/*_test.go' \
'jsonparser\.Delete|jsonparser\.Set|jsonparser\.ObjectEach|jsonparser\.ArrayEach' \
"$modroot/github.com/mark3labs/mcp-go@v0.43.2" \
"$modroot/github.com/invopop/jsonschema@v0.13.0" \
"$modroot/github.com/wk8/go-ordered-map/v2@v2.1.8" \
"$modroot/github.com/mailru/easyjson@v0.7.7" 2>/dev/null || true
printf '%s\n' '=== direct go-jose imports in application ==='
rg -n --glob '*.go' \
'github.com/go-jose/go-jose/v4|josejwt|ParseEncrypted|Decrypt' \
examples/mcps/token-exchange-demo-serverRepository: maximhq/bifrost Length of output: 12349 Update the vulnerable dependency pins before merge. Upgrade 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| github.com/mark3labs/mcp-go v0.43.2 | ||
| ) | ||
|
|
||
| require ( | ||
| github.com/bahlo/generic-list-go v0.2.0 // indirect | ||
| github.com/buger/jsonparser v1.1.1 // indirect | ||
| github.com/google/uuid v1.6.0 // indirect | ||
| github.com/invopop/jsonschema v0.13.0 // indirect | ||
| github.com/mailru/easyjson v0.7.7 // indirect | ||
| github.com/spf13/cast v1.7.1 // indirect | ||
| github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect | ||
| github.com/yosida95/uritemplate/v3 v3.0.2 // indirect | ||
| golang.org/x/oauth2 v0.28.0 // indirect | ||
| gopkg.in/yaml.v3 v3.0.1 // indirect | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= | ||
| github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= | ||
| github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= | ||
| github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= | ||
| github.com/coreos/go-oidc/v3 v3.16.0 h1:qRQUCFstKpXwmEjDQTIbyY/5jF00+asXzSkmkoa/mow= | ||
| github.com/coreos/go-oidc/v3 v3.16.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= | ||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
| github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= | ||
| github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= | ||
| github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= | ||
| github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= | ||
| github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | ||
| github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | ||
| github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | ||
| github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||
| github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= | ||
| github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= | ||
| github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= | ||
| github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | ||
| github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= | ||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||
| github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||
| github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= | ||
| github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= | ||
| github.com/mark3labs/mcp-go v0.43.2 h1:21PUSlWWiSbUPQwXIJ5WKlETixpFpq+WBpbMGDSVy/I= | ||
| github.com/mark3labs/mcp-go v0.43.2/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw= | ||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
| github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= | ||
| github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= | ||
| github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= | ||
| github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= | ||
| github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= | ||
| github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | ||
| github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= | ||
| github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= | ||
| github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= | ||
| github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= | ||
| golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= | ||
| golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= | ||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
Uh oh!
There was an error while loading. Please reload this page.