microsoft/semantic-kernel · warning · HTTPException

Missing state parameter

Error message

Missing state parameter

What it means

Raised as HTTPException(400) by the login_page_handler in mcp_simple_auth's auth_server.py when the /login GET request lacks a 'state' query parameter. The state parameter ties the login page to an in-flight authorization request; without it the server cannot render a valid login form and rejects the request.

Source

Thrown at python/samples/demos/mcp_with_oauth/server/mcp_simple_auth/auth_server.py:88

        required_scopes=[auth_settings.mcp_scope],
        resource_server_url=None,
    )

    # Create OAuth routes
    routes = create_auth_routes(
        provider=oauth_provider,
        issuer_url=mcp_auth_settings.issuer_url,
        service_documentation_url=mcp_auth_settings.service_documentation_url,
        client_registration_options=mcp_auth_settings.client_registration_options,
        revocation_options=mcp_auth_settings.revocation_options,
    )

    # Add login page route (GET)
    async def login_page_handler(request: Request) -> Response:
        """Show login form."""
        state = request.query_params.get("state")
        if not state:
            raise HTTPException(400, "Missing state parameter")
        return await oauth_provider.get_login_page(state)

    routes.append(Route("/login", endpoint=login_page_handler, methods=["GET"]))

    # Add login callback route (POST)
    async def login_callback_handler(request: Request) -> Response:
        """Handle simple authentication callback."""
        return await oauth_provider.handle_login_callback(request)

    routes.append(Route("/login/callback", endpoint=login_callback_handler, methods=["POST"]))

    # Add token introspection endpoint (RFC 7662) for Resource Servers
    async def introspect_handler(request: Request) -> Response:
        """
        Token introspection endpoint for Resource Servers.

        Resource Servers call this endpoint to validate tokens without
        needing direct access to token storage.

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Ensure the authorization flow always appends a valid state to the /login URL.
  2. Start the OAuth flow from the proper authorize endpoint so the server generates and forwards state.
  3. Do not deep-link /login without going through the authorize step.
  4. Check reverse proxies / load balancers are not stripping query parameters.

Example fix

// before
# user opens http://host/login directly

// after
# start at the authorize endpoint; server redirects to /login?state=<generated>
Defensive patterns

Strategy: validation

Validate before calling

state = request.query_params.get('state')
if not state:
    return PlainTextResponse('Missing state. Start the flow at /authorize.', status_code=400)
await oauth_provider.get_login_page(state)

Type guard

def has_state_param(request) -> bool:
    return bool(request.query_params.get('state'))

Prevention

When it happens

Trigger: A GET /login request without ?state=...; the client/initiator omitted the state parameter when constructing the login URL; a user navigated directly to /login manually.

Common situations: Browser bookmarks hitting /login directly; a misconfigured client building the auth URL; the state was dropped by a redirect/proxy.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/463c490cc880bc17. Report an issue: GitHub.