Move to remote HTTP safely
Authenticate and authorize requests
Protect a remote server by validating who sent a token, who it is for, when it expires, and what it permits.
8 minute lesson
Authentication establishes who the caller is. Authorization decides what that caller may do.
For remote HTTP, an MCP server acts as an OAuth resource server. The HTTP layer must verify the bearer token before MCP dispatch. createMcpHandler() does not derive trusted identity from the request header.
The v2 SDK provides a web-standard gate:
import { requireBearerAuth } from '@modelcontextprotocol/server'
const gate = requireBearerAuth({
verifier,
requiredScopes: ['notes:read'],
resourceMetadataUrl
})
async function fetchMcp(request: Request) {
const auth = await gate(request)
if (auth instanceof Response) return auth
return handler.fetch(request, { authInfo: auth })
}
The omitted verifier must validate the token’s signature or introspection result, issuer, audience, expiry, and revocation status. The SDK gate checks the bearer shape, expiry, and required scopes around that verifier.
Audience is critical. Reject a valid token minted for another service. If the MCP server calls a downstream API, obtain a separate token for that API. Passing the caller’s token through creates a confused-deputy boundary.
Return 401 when the token is missing or invalid. Return 403 when the identity is valid but lacks the required scope. Advertise protected resource metadata so compatible clients can discover the authorization server.
Use HTTPS. Keep tokens out of URLs, source code, analytics, tool results, and logs.
The course dataset may be public only because every note is practice data. Replace it with private notes and authorization becomes a release blocker, not a later improvement.
Lesson completed