Implement Redis namespace isolation for auth and MCP keys
This commit is contained in:
parent
4a081bc816
commit
34fe20efc4
4 changed files with 35 additions and 9 deletions
13
README.md
13
README.md
|
|
@ -520,6 +520,8 @@ The server is designed for horizontal scaling using Redis as the backbone:
|
|||
- **Automatic Cleanup**: No explicit cleanup required
|
||||
|
||||
#### Redis Key Structure
|
||||
|
||||
##### MCP Session Keys
|
||||
```
|
||||
session:{sessionId}:owner # Session ownership
|
||||
mcp:shttp:toserver:{sessionId} # Client→Server messages
|
||||
|
|
@ -527,6 +529,17 @@ mcp:shttp:toclient:{sessionId}:{requestId} # Server→Client responses
|
|||
mcp:control:{sessionId} # Control messages
|
||||
```
|
||||
|
||||
##### OAuth/Auth Keys
|
||||
```
|
||||
auth:client:{clientId} # OAuth client registrations
|
||||
auth:pending:{authCode} # Pending authorizations
|
||||
auth:installation:{accessToken} # Active MCP installations
|
||||
auth:exch:{authCode} # Token exchanges
|
||||
auth:refresh:{refreshToken} # Refresh tokens
|
||||
```
|
||||
|
||||
Note: The `auth:` prefix ensures complete namespace isolation between auth and MCP functions in both integrated and separate modes.
|
||||
|
||||
### Transport Methods
|
||||
|
||||
#### Streamable HTTP (Recommended)
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ Redis stores session ownership information using a structured key system.
|
|||
|
||||
### Redis Key Structure
|
||||
|
||||
#### MCP Session Keys (MCP Server)
|
||||
```
|
||||
session:{sessionId}:owner → userId # Session ownership
|
||||
mcp:shttp:toserver:{sessionId} → [pub/sub channel] # Client→Server messages (also indicates liveness)
|
||||
|
|
@ -134,6 +135,17 @@ mcp:shttp:toclient:{sessionId}:{requestId} → [pub/sub channel] # Server→Clie
|
|||
mcp:control:{sessionId} → [pub/sub channel] # Control messages
|
||||
```
|
||||
|
||||
#### Auth Keys (Auth Server)
|
||||
```
|
||||
auth:client:{clientId} → client registration # OAuth client registrations
|
||||
auth:pending:{authCode} → pending authorization # Pending auth (10 min TTL)
|
||||
auth:installation:{accessToken} → MCP installation # Active sessions (7 days TTL)
|
||||
auth:exch:{authCode} → token exchange # Token exchange (10 min TTL)
|
||||
auth:refresh:{refreshToken} → access token # Refresh tokens (7 days TTL)
|
||||
```
|
||||
|
||||
Note: The `auth:` prefix ensures complete isolation from MCP session keys, allowing both integrated and separate modes to work consistently.
|
||||
|
||||
### Redis Operations
|
||||
|
||||
| Operation | Key Pattern | Value | Purpose |
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import { logger } from "../src/utils/logger.js";
|
|||
|
||||
/**
|
||||
* Redis key prefixes for different data types
|
||||
* All auth-related keys use "auth:" prefix to avoid collision with MCP session keys
|
||||
*/
|
||||
export const REDIS_KEY_PREFIXES = {
|
||||
CLIENT_REGISTRATION: "client:",
|
||||
PENDING_AUTHORIZATION: "pending:",
|
||||
MCP_AUTHORIZATION: "mcp:",
|
||||
TOKEN_EXCHANGE: "exch:",
|
||||
REFRESH_TOKEN: "refresh:",
|
||||
CLIENT_REGISTRATION: "auth:client:",
|
||||
PENDING_AUTHORIZATION: "auth:pending:",
|
||||
MCP_AUTHORIZATION: "auth:installation:", // Changed from "mcp:" to avoid collision
|
||||
TOKEN_EXCHANGE: "auth:exch:",
|
||||
REFRESH_TOKEN: "auth:refresh:",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -124,8 +124,8 @@ describe("auth utils", () => {
|
|||
// instead of using exchangeToken which changes the value
|
||||
await saveTokenExchange(authCode, tokenExchange);
|
||||
|
||||
// Get the key used by saveTokenExchange
|
||||
const key = "exch:" + crypto.createHash("sha256").update(authCode).digest("hex");
|
||||
// Get the key used by saveTokenExchange (now with auth: prefix)
|
||||
const key = "auth:exch:" + crypto.createHash("sha256").update(authCode).digest("hex");
|
||||
|
||||
// Get the encrypted data
|
||||
const encryptedData = await mockRedis.get(key);
|
||||
|
|
@ -266,8 +266,8 @@ describe("auth utils", () => {
|
|||
|
||||
await revokeMcpInstallation(accessToken);
|
||||
|
||||
// Should have called getDel with the correct key
|
||||
expect(getDel).toHaveBeenCalledWith(expect.stringContaining("mcp:"));
|
||||
// Should have called getDel with the correct key (now auth:installation:)
|
||||
expect(getDel).toHaveBeenCalledWith(expect.stringContaining("auth:installation:"));
|
||||
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue