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
- Ensure the authorization flow always appends a valid state to the /login URL.
- Start the OAuth flow from the proper authorize endpoint so the server generates and forwards state.
- Do not deep-link /login without going through the authorize step.
- 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
- Always start OAuth at the authorize endpoint so state is generated.
- Never deep-link /login without state.
- Ensure proxies preserve query parameters.
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
- Missing state parameter
- Missing state parameter
- Missing username, password, or state parameter
- Invalid parameter types
- OAuth error: {self.callback_data['error']}
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/463c490cc880bc17.
Report an issue: GitHub.