From c8cfbb02bdcb34733509544690d4e597dc07aaac Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 8 Dec 2025 14:41:01 -0500 Subject: [PATCH] internal/docs: document UserID for session hijacking prevention Update our Session Hijacking mitigation documentation to describe the new TokenInfo.UserID field and how the streamable transport uses it to bind sessions to users. Fixes #571 --- docs/protocol.md | 15 ++++++++++++--- internal/docs/protocol.src.md | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/docs/protocol.md b/docs/protocol.md index 6d22c4b5..034882d8 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -316,9 +316,18 @@ If you create your own with If you are using Go 1.24 or above, we recommend using [`crypto/rand.Text`](https://pkg.go.dev/crypto/rand#Text) -- _Binding session IDs to user information_. This is an application requirement, out of scope -for the SDK. You can create your own session IDs by setting -[`ServerOptions.GetSessionID`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.GetSessionID). +- _Binding session IDs to user information_. The SDK supports this mitigation through +[`TokenInfo.UserID`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/auth#TokenInfo.UserID). +When a [`TokenVerifier`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/auth#TokenVerifier) +sets `UserID` on the returned `TokenInfo`, the streamable transport will: + 1. Store the user ID when a new session is created. + 2. Verify that subsequent requests to that session include a token with the same `UserID`. + 3. Reject requests with a 403 Forbidden if the user ID doesn't match. + + **Recommendation**: If your `TokenVerifier` can extract a user identifier from the token + (such as a `sub` claim in a JWT, or a user ID associated with an API key), set + `TokenInfo.UserID` to enable this protection. This prevents an attacker with a valid + token from hijacking another user's session by guessing or obtaining their session ID. ## Utilities diff --git a/internal/docs/protocol.src.md b/internal/docs/protocol.src.md index b0874ccf..29f7e362 100644 --- a/internal/docs/protocol.src.md +++ b/internal/docs/protocol.src.md @@ -242,9 +242,18 @@ If you create your own with If you are using Go 1.24 or above, we recommend using [`crypto/rand.Text`](https://pkg.go.dev/crypto/rand#Text) -- _Binding session IDs to user information_. This is an application requirement, out of scope -for the SDK. You can create your own session IDs by setting -[`ServerOptions.GetSessionID`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.GetSessionID). +- _Binding session IDs to user information_. The SDK supports this mitigation through +[`TokenInfo.UserID`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/auth#TokenInfo.UserID). +When a [`TokenVerifier`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/auth#TokenVerifier) +sets `UserID` on the returned `TokenInfo`, the streamable transport will: + 1. Store the user ID when a new session is created. + 2. Verify that subsequent requests to that session include a token with the same `UserID`. + 3. Reject requests with a 403 Forbidden if the user ID doesn't match. + + **Recommendation**: If your `TokenVerifier` can extract a user identifier from the token + (such as a `sub` claim in a JWT, or a user ID associated with an API key), set + `TokenInfo.UserID` to enable this protection. This prevents an attacker with a valid + token from hijacking another user's session by guessing or obtaining their session ID. ## Utilities