diff --git a/gatehouse_app/__init__.py b/gatehouse_app/__init__.py index dd77dce..e3b9cc5 100644 --- a/gatehouse_app/__init__.py +++ b/gatehouse_app/__init__.py @@ -111,12 +111,14 @@ def setup_middleware(app): def register_blueprints(app): """Register application blueprints.""" from gatehouse_app.api import register_api_blueprints - from gatehouse_app.api.oidc import oidc_bp + from gatehouse_app.api.oidc import oidc_bp, oidc_discovery_bp register_api_blueprints(app) - # Register OIDC blueprint at root level - app.register_blueprint(oidc_bp) + # Register OIDC discovery at root level (OIDC spec requirement: .well-known must be at root) + app.register_blueprint(oidc_discovery_bp) + # Register OIDC blueprint at /api/v1/oidc (conforms to API versioning standard) + app.register_blueprint(oidc_bp, url_prefix="/api/v1/oidc") def register_error_handlers(app): diff --git a/gatehouse_app/api/oidc.py b/gatehouse_app/api/oidc.py index f09e4cb..ce564f3 100644 --- a/gatehouse_app/api/oidc.py +++ b/gatehouse_app/api/oidc.py @@ -71,9 +71,12 @@ def _fetch_oidc_params(oidc_session_id: str, *, consume: bool = False) -> dict | return params -# Create OIDC blueprint registered at root level +# Create OIDC blueprint registered at /api/v1/oidc oidc_bp = Blueprint("oidc", __name__) +# Create a separate blueprint for OIDC discovery (registered at root level per OIDC spec) +oidc_discovery_bp = Blueprint("oidc_discovery", __name__) + # ============================================================================ # Helper Functions @@ -84,13 +87,13 @@ def get_oidc_config(): base_url = current_app.config.get("OIDC_ISSUER_URL", "http://localhost:5000") return { "issuer": base_url, - "authorization_endpoint": f"{base_url}/oidc/authorize", - "token_endpoint": f"{base_url}/oidc/token", - "userinfo_endpoint": f"{base_url}/oidc/userinfo", - "jwks_uri": f"{base_url}/oidc/jwks", - "registration_endpoint": f"{base_url}/oidc/register", - "revocation_endpoint": f"{base_url}/oidc/revoke", - "introspection_endpoint": f"{base_url}/oidc/introspect", + "authorization_endpoint": f"{base_url}/api/v1/oidc/authorize", + "token_endpoint": f"{base_url}/api/v1/oidc/token", + "userinfo_endpoint": f"{base_url}/api/v1/oidc/userinfo", + "jwks_uri": f"{base_url}/api/v1/oidc/jwks", + "registration_endpoint": f"{base_url}/api/v1/oidc/register", + "revocation_endpoint": f"{base_url}/api/v1/oidc/revoke", + "introspection_endpoint": f"{base_url}/api/v1/oidc/introspect", "scopes_supported": ["openid", "profile", "email", "roles"], "response_types_supported": ["code"], "response_modes_supported": ["query"], @@ -244,7 +247,7 @@ def parse_basic_auth(): # Discovery Endpoint # ============================================================================ -@oidc_bp.route("/.well-known/openid-configuration", methods=["GET"]) +@oidc_discovery_bp.route("/.well-known/openid-configuration", methods=["GET"]) def oidc_discovery(): """OpenID Connect Discovery endpoint.