Files
dify/api/controllers/openapi/__init__.py
GareArc 71e9e8dda6 feat(api): lift SSO branch device-flow handlers to /openapi/v1 (Phase D.15-16)
The four EE-only SSO handlers (sso_initiate, sso_complete,
approval_context, approve_external) move from controllers/oauth_device_sso.py
to controllers/openapi/oauth_device/. Each is registered on openapi_bp
via @bp.route at the canonical path:

  /openapi/v1/oauth/device/sso-initiate
  /openapi/v1/oauth/device/sso-complete
  /openapi/v1/oauth/device/approval-context
  /openapi/v1/oauth/device/approve-external

sso-complete moves under /oauth/device/ from its previous orphan path
/v1/device/sso-complete; the IdP-side ACS callback URL hardcoded in
sso_initiate now points to the canonical path. Operators must
re-register the ACS callback with each IdP before Phase F deletes the
legacy alias.

oauth_device_sso.py shrinks to a thin re-mount file: same legacy bp
with attach_anti_framing applied, four bp.add_url_rule() calls binding
the legacy paths to the imported view functions. Same handler runs
for both mounts — no duplicated logic.

attach_anti_framing(openapi_bp) added in controllers/openapi/__init__.py
so X-Frame-Options + frame-ancestors CSP cover the canonical paths too.

Plan: docs/superpowers/plans/2026-04-26-openapi-migration.md (in difyctl repo).
2026-04-27 00:00:24 -07:00

45 lines
1.4 KiB
Python

from flask import Blueprint
from flask_restx import Namespace
from libs.device_flow_security import attach_anti_framing
from libs.external_api import ExternalApi
bp = Blueprint("openapi", __name__, url_prefix="/openapi/v1")
attach_anti_framing(bp)
api = ExternalApi(
bp,
version="1.0",
title="OpenAPI",
description="User-scoped programmatic API (bearer auth)",
)
openapi_ns = Namespace("openapi", description="User-scoped operations", path="/")
from . import account, index
from .oauth_device import approval_context as oauth_device_approval_context
from .oauth_device import approve as oauth_device_approve
from .oauth_device import approve_external as oauth_device_approve_external
from .oauth_device import code as oauth_device_code
from .oauth_device import deny as oauth_device_deny
from .oauth_device import lookup as oauth_device_lookup
from .oauth_device import sso_complete as oauth_device_sso_complete
from .oauth_device import sso_initiate as oauth_device_sso_initiate
from .oauth_device import token as oauth_device_token
__all__ = [
"account",
"index",
"oauth_device_approval_context",
"oauth_device_approve",
"oauth_device_approve_external",
"oauth_device_code",
"oauth_device_deny",
"oauth_device_lookup",
"oauth_device_sso_complete",
"oauth_device_sso_initiate",
"oauth_device_token",
]
api.add_namespace(openapi_ns)