mcp-authkit 0.2.2__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/PKG-INFO +1 -1
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcp_authkit.egg-info/PKG-INFO +1 -1
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/auth_routes.py +26 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/pyproject.toml +1 -1
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/tests/test_auth_routes.py +60 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/LICENSE +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/README.md +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcp_authkit.egg-info/SOURCES.txt +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcp_authkit.egg-info/dependency_links.txt +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcp_authkit.egg-info/requires.txt +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcp_authkit.egg-info/top_level.txt +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/__init__.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/auth_middleware.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/jwt_validator.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/__init__.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/credentials_provider.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/oauth_provider.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/templates/base.html +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/templates/credentials_entry.html +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/templates/credentials_error.html +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/templates/credentials_success.html +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/templates/oauth_error.html +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/templates/oauth_success.html +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/py.typed +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/store/__init__.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/store/base.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/store/encryption.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/store/factory.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/store/file_store.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/store/memory.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/store/redis_store.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/setup.cfg +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/tests/test_auth_middleware.py +0 -0
- {mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/tests/test_jwt_validator.py +0 -0
|
@@ -24,6 +24,7 @@ from __future__ import annotations
|
|
|
24
24
|
|
|
25
25
|
import logging
|
|
26
26
|
import time
|
|
27
|
+
from urllib.parse import urlencode
|
|
27
28
|
|
|
28
29
|
import httpx
|
|
29
30
|
from fastapi import APIRouter, Request
|
|
@@ -37,6 +38,7 @@ def oauth_meta_router(
|
|
|
37
38
|
server_base_url: str,
|
|
38
39
|
issuer_url: str,
|
|
39
40
|
client_id: str,
|
|
41
|
+
extra_authorize_params: dict[str, str] | None = None,
|
|
40
42
|
) -> APIRouter:
|
|
41
43
|
"""
|
|
42
44
|
Return an ``APIRouter`` with well-known OAuth metadata routes and a DCR
|
|
@@ -52,6 +54,26 @@ def oauth_meta_router(
|
|
|
52
54
|
``"https://login.microsoftonline.com/{tenant}/v2.0"``.
|
|
53
55
|
client_id
|
|
54
56
|
Pre-registered public client ID returned by the DCR façade.
|
|
57
|
+
extra_authorize_params
|
|
58
|
+
Optional extra query parameters appended to the
|
|
59
|
+
``authorization_endpoint`` in the
|
|
60
|
+
``/.well-known/oauth-authorization-server`` response. MCP clients
|
|
61
|
+
read that URL and use it verbatim when redirecting the user to the
|
|
62
|
+
OIDC provider, so any hint placed here is automatically forwarded.
|
|
63
|
+
|
|
64
|
+
Use this for provider-specific routing parameters that fall outside
|
|
65
|
+
the standard OAuth 2.0 / OIDC spec. For example, Okta's ``idp``
|
|
66
|
+
parameter bypasses the Okta login page and routes users directly to
|
|
67
|
+
a configured external Identity Provider::
|
|
68
|
+
|
|
69
|
+
app.include_router(oauth_meta_router(
|
|
70
|
+
server_base_url=settings.server_base_url,
|
|
71
|
+
issuer_url="https://your-org.okta.com/oauth2/default",
|
|
72
|
+
client_id=settings.okta_client_id,
|
|
73
|
+
extra_authorize_params={"idp": "0oaz2r21a8RBmZyOL0h7"},
|
|
74
|
+
))
|
|
75
|
+
|
|
76
|
+
Default: ``None`` (no extra params — fully retro-compatible).
|
|
55
77
|
"""
|
|
56
78
|
router = APIRouter()
|
|
57
79
|
base = server_base_url.rstrip("/")
|
|
@@ -85,6 +107,10 @@ def oauth_meta_router(
|
|
|
85
107
|
except Exception as exc:
|
|
86
108
|
logger.warning("Could not fetch OIDC metadata: %s", exc)
|
|
87
109
|
|
|
110
|
+
if extra_authorize_params:
|
|
111
|
+
sep = "&" if "?" in auth_ep else "?"
|
|
112
|
+
auth_ep += sep + urlencode(extra_authorize_params)
|
|
113
|
+
|
|
88
114
|
return JSONResponse(
|
|
89
115
|
{
|
|
90
116
|
"issuer": base,
|
|
@@ -85,6 +85,66 @@ def test_authorization_server_pkce_supported(client):
|
|
|
85
85
|
assert "S256" in data["code_challenge_methods_supported"]
|
|
86
86
|
|
|
87
87
|
|
|
88
|
+
def test_authorization_server_no_extra_params_by_default(client):
|
|
89
|
+
"""Default (extra_authorize_params=None) does not append any extra query params."""
|
|
90
|
+
data = client.get("/.well-known/oauth-authorization-server").json()
|
|
91
|
+
assert "idp=" not in data["authorization_endpoint"]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_authorization_server_extra_params_appended():
|
|
95
|
+
"""extra_authorize_params are appended to authorization_endpoint."""
|
|
96
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
97
|
+
|
|
98
|
+
app = FastAPI()
|
|
99
|
+
app.include_router(
|
|
100
|
+
oauth_meta_router(
|
|
101
|
+
server_base_url=SERVER,
|
|
102
|
+
issuer_url=ISSUER,
|
|
103
|
+
client_id=CLIENT_ID,
|
|
104
|
+
extra_authorize_params={"idp": "0oaz2r21a8RBmZyOL0h7"},
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
tc = TestClient(app, raise_server_exceptions=False)
|
|
108
|
+
|
|
109
|
+
oidc_doc = {
|
|
110
|
+
"authorization_endpoint": "https://org.okta.com/oauth2/default/v1/authorize",
|
|
111
|
+
"token_endpoint": "https://org.okta.com/oauth2/default/v1/token",
|
|
112
|
+
"jwks_uri": "https://org.okta.com/oauth2/default/v1/keys",
|
|
113
|
+
}
|
|
114
|
+
mock_resp = MagicMock()
|
|
115
|
+
mock_resp.status_code = 200
|
|
116
|
+
mock_resp.json.return_value = oidc_doc
|
|
117
|
+
mock_client = MagicMock()
|
|
118
|
+
mock_client.get = AsyncMock(return_value=mock_resp)
|
|
119
|
+
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
120
|
+
mock_client.__aexit__ = AsyncMock(return_value=None)
|
|
121
|
+
|
|
122
|
+
with patch("mcpauthkit.auth_routes.httpx.AsyncClient", return_value=mock_client):
|
|
123
|
+
data = tc.get("/.well-known/oauth-authorization-server").json()
|
|
124
|
+
|
|
125
|
+
assert "idp=0oaz2r21a8RBmZyOL0h7" in data["authorization_endpoint"]
|
|
126
|
+
# Standard OIDC fields are still present
|
|
127
|
+
assert data["token_endpoint"] == "https://org.okta.com/oauth2/default/v1/token"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_authorization_server_extra_params_fallback_no_oidc():
|
|
131
|
+
"""extra_authorize_params appended even when OIDC discovery is unreachable."""
|
|
132
|
+
app = FastAPI()
|
|
133
|
+
app.include_router(
|
|
134
|
+
oauth_meta_router(
|
|
135
|
+
server_base_url=SERVER,
|
|
136
|
+
issuer_url=ISSUER,
|
|
137
|
+
client_id=CLIENT_ID,
|
|
138
|
+
extra_authorize_params={"idp": "abc123", "prompt": "login"},
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
tc = TestClient(app, raise_server_exceptions=False)
|
|
142
|
+
data = tc.get("/.well-known/oauth-authorization-server").json()
|
|
143
|
+
auth_ep = data["authorization_endpoint"]
|
|
144
|
+
assert "idp=abc123" in auth_ep
|
|
145
|
+
assert "prompt=login" in auth_ep
|
|
146
|
+
|
|
147
|
+
|
|
88
148
|
def test_authorization_server_uses_oidc_config(client):
|
|
89
149
|
"""When OIDC discovery returns 200, its endpoints override the defaults."""
|
|
90
150
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/templates/credentials_entry.html
RENAMED
|
File without changes
|
{mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/templates/credentials_error.html
RENAMED
|
File without changes
|
{mcp_authkit-0.2.2 → mcp_authkit-0.2.3}/mcpauthkit/providers/templates/credentials_success.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|