From 72307fb7c3a25d82faaede0631c7c2eb5786d226 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Tue, 17 Feb 2026 00:05:22 +0000 Subject: [PATCH] Fix again, didn't work --- paskia/fastapi/oid.py | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/paskia/fastapi/oid.py b/paskia/fastapi/oid.py index 8737900..f59667f 100644 --- a/paskia/fastapi/oid.py +++ b/paskia/fastapi/oid.py @@ -16,7 +16,7 @@ from datetime import UTC, datetime from uuid import UUID import base64url -from fastapi import Body, Depends, FastAPI, HTTPException, Request +from fastapi import Depends, FastAPI, Form, HTTPException, Request from fastapi.responses import JSONResponse from fastapi.security import HTTPBearer @@ -99,13 +99,13 @@ def _parse_client_credentials( @app.post("/token") async def token( request: Request, - grant_type: str | None = Body(None, embed=False), - code: str | None = Body(None, embed=False), - redirect_uri: str | None = Body(None, embed=False), - client_id: str | None = Body(None, embed=False), - client_secret: str | None = Body(None, embed=False), - code_verifier: str | None = Body(None, embed=False), - refresh_token: str | None = Body(None, embed=False), + grant_type: str = Form(...), + code: str | None = Form(None), + redirect_uri: str | None = Form(None), + client_id: str | None = Form(None), + client_secret: str | None = Form(None), + code_verifier: str | None = Form(None), + refresh_token: str | None = Form(None), ): """OIDC Token endpoint. @@ -114,23 +114,21 @@ async def token( - grant_type=refresh_token: Refresh access token using sid Supports client_secret_post and client_secret_basic authentication. + Per RFC 6749 Section 4.1.3: MUST use POST with application/x-www-form-urlencoded. """ - # Parse form data (OAuth uses application/x-www-form-urlencoded) - content_type = request.headers.get("content-type", "") - if "application/x-www-form-urlencoded" in content_type: - form = await request.form() - grant_type = form.get("grant_type", grant_type) - code = form.get("code", code) - redirect_uri = form.get("redirect_uri", redirect_uri) - client_id = form.get("client_id", client_id) - client_secret = form.get("client_secret", client_secret) - code_verifier = form.get("code_verifier", code_verifier) - refresh_token = form.get("refresh_token", refresh_token) - # Validate grant_type is present - if not grant_type: + # RFC 6749: Token endpoint MUST NOT accept query parameters + if request.url.query: return JSONResponse( - {"error": "invalid_request", "error_description": "Missing grant_type"}, + {"error": "invalid_request", "error_description": "Query parameters not allowed"}, + status_code=400, + ) + + # RFC 6749: MUST use application/x-www-form-urlencoded + content_type = request.headers.get("content-type", "") + if "application/x-www-form-urlencoded" not in content_type: + return JSONResponse( + {"error": "invalid_request", "error_description": "Content-Type must be application/x-www-form-urlencoded"}, status_code=400, )