fix: resolve OAuth compatibility issues for login-flow deployment
- Drop OIDC fork: comment out third_party/oidc mount, use upstream v1.16.3 from app store (fixes consent redirect race, PR #631) - Support client_secret_basic auth: add _extract_basic_auth() helper so TS MCP SDK can authenticate at token endpoint (RFC 6749 §2.3.1) - Multi-issuer JWT validation: accept tokens with internal Docker issuer (http://app:80) or public URL (NEXTCLOUD_PUBLIC_ISSUER_URL) since AS proxy obtains tokens server-to-server - Introspection fallback: try token introspection when JWT verification fails, supporting both JWT and opaque token types - Register all tool scopes in DCR: add semantic:read, collectives:read, collectives:write to OIDC client allowed_scopes so tokens include them and semantic search tools are visible to authenticated clients - Auto-create Astrolabe OAuth client: new app-hook creates OIDC client and stores credentials in config.php so the "Authorize via OAuth" button works without manual setup Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
3cf4c777ed
commit
fe8799a133
@@ -24,10 +24,10 @@ import logging
|
||||
import os
|
||||
import secrets
|
||||
import time
|
||||
from base64 import urlsafe_b64encode
|
||||
from base64 import b64decode, urlsafe_b64encode
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
from urllib.parse import urlencode
|
||||
from urllib.parse import unquote, urlencode
|
||||
from urllib.parse import urlparse as parse_url
|
||||
|
||||
import jwt
|
||||
@@ -905,6 +905,19 @@ async def _oauth_callback_as_proxy(
|
||||
return RedirectResponse(redirect_url, status_code=302)
|
||||
|
||||
|
||||
def _extract_basic_auth(request: Request) -> tuple[str | None, str | None]:
|
||||
"""Extract client_id and client_secret from HTTP Basic Auth header (RFC 6749 §2.3.1)."""
|
||||
auth_header = request.headers.get("authorization", "")
|
||||
if not auth_header.startswith("Basic "):
|
||||
return None, None
|
||||
try:
|
||||
decoded = b64decode(auth_header[6:]).decode("utf-8")
|
||||
client_id, _, client_secret = decoded.partition(":")
|
||||
return unquote(client_id), unquote(client_secret) if client_secret else None
|
||||
except Exception:
|
||||
return None, None
|
||||
|
||||
|
||||
def _verify_pkce_s256(code_verifier: str, code_challenge: str) -> bool:
|
||||
"""Verify PKCE S256 code_verifier against stored code_challenge.
|
||||
|
||||
@@ -958,6 +971,10 @@ async def _token_authorization_code(request: Request, form) -> JSONResponse:
|
||||
code_verifier = form.get("code_verifier")
|
||||
client_id = form.get("client_id")
|
||||
|
||||
# RFC 6749 §2.3.1: clients may authenticate via HTTP Basic Auth
|
||||
if not client_id:
|
||||
client_id, _ = _extract_basic_auth(request)
|
||||
|
||||
logger.debug(
|
||||
"AS proxy token: received code=%s client_id=%s redirect_uri=%s "
|
||||
"code_verifier=%s",
|
||||
|
||||
Reference in New Issue
Block a user