CourseModel Context Protocol · Module 11: Capstone · part 78 of 83
Part 78 · Module 11: Capstone

Topic 5: Securing it

8 min read·22 Sept 2026

Bearer tokens and audience validation over HTTP

Over HTTP the server is reachable by anything on the network, so it acts as an OAuth 2.1 resource server: it never issues tokens, it only checks them. The check that matters most here is the audience (aud claim): the server URL a token was issued for. Without it, a token Nare's host obtained for some other MCP server (say, a calendar server that trusts the same identity provider) would also open her notes. This is the excerpt from Module 7 that does the check.

python
# Excerpt from notes_assistant/auth.py, lines 35 to 55, dedented (method of JWTTokenVerifier)
async def verify_token(self, token: str) -> AccessToken | None:
    try:
        claims = jwt.decode(
            token,
            self.key,
            algorithms=self.algorithms,
            audience=self.audience,
            issuer=self.issuer,
            options={"require": ["exp", "iss", "aud", "sub"]},
        )
    except jwt.InvalidTokenError as exc:
        # Log the reason, never the token itself.
        logger.warning("rejected token: %s", type(exc).__name__)
        return None
    return AccessToken(
        token=token,
        client_id=str(claims.get("client_id", claims["sub"])),
        scopes=str(claims.get("scope", "")).split(),
        expires_at=int(claims["exp"]),
        resource=self.audience,
    )

Code explained

The rest of this course is yours to keep

This course is bought on its own, once, and stays readable afterwards, including the parts added to it later.