microsoft/semantic-kernel · warning · HTTPException

Missing state parameter

Error message

Missing state parameter

What it means

Raised as HTTPException(400) by SimpleAuthProvider.get_login_page when the state argument is falsy (empty string or None). The provider generates the login form HTML keyed to state; an empty state cannot be associated with the pending authorization, so it refuses to render.

Source

Thrown at python/samples/demos/mcp_with_oauth/server/mcp_simple_auth/simple_auth_provider.py:100

        # Store state mapping for callback
        self.state_mapping[state] = {
            "redirect_uri": str(params.redirect_uri),
            "code_challenge": params.code_challenge,
            "redirect_uri_provided_explicitly": str(params.redirect_uri_provided_explicitly),
            "client_id": client.client_id,
            "resource": params.resource,  # RFC 8707
        }

        # Build simple login URL that points to login page
        auth_url = f"{self.auth_callback_url}?state={state}&client_id={client.client_id}"

        return auth_url

    async def get_login_page(self, state: str) -> HTMLResponse:
        """Generate login page HTML for the given state."""
        if not state:
            raise HTTPException(400, "Missing state parameter")

        # Create simple login form HTML
        html_content = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <title>MCP Demo Authentication</title>
            <style>
                body {{ font-family: Arial, sans-serif; max-width: 500px; margin: 0 auto; padding: 20px; }}
                .form-group {{ margin-bottom: 15px; }}
                input {{ width: 100%; padding: 8px; margin-top: 5px; }}
                button {{ background-color: #4CAF50; color: white; padding: 10px 15px; border: none; cursor: pointer; }}
            </style>
        </head>
        <body>
            <h2>MCP Demo Authentication</h2>
            <p>This is a simplified authentication demo. Use the demo credentials below:</p>
            <p><strong>Username:</strong> demo_user<br>

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Ensure callers (login_page_handler) pass a non-empty state to get_login_page.
  2. Validate state at the HTTP boundary before reaching get_login_page (the route handlers already do this — confirm they are on the call path).
  3. Generate and persist state during the authorize step so it is always present.
  4. Return a user-facing error page instead of raising for known-empty state if appropriate.

Example fix

// before
await oauth_provider.get_login_page(state='')

// after
state = request.query_params.get('state')
if not state:
    raise HTTPException(400, 'Missing state parameter')
await oauth_provider.get_login_page(state=state)
Defensive patterns

Strategy: validation

Validate before calling

if not state:
    raise HTTPException(400, 'Missing state parameter')
await oauth_provider.get_login_page(state)

Type guard

def is_non_empty_state(state) -> bool:
    return isinstance(state, str) and bool(state.strip())

Prevention

When it happens

Trigger: get_login_page('') or get_login_page(None); the upstream handler passed an empty/missing state; state was coerced to empty during URL parsing.

Common situations: A handler that does not check state before calling get_login_page; URL parsing edge cases producing empty state; tests invoking get_login_page without state.

Related errors


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