|
1 | 1 | from typing import Any, Literal |
| 2 | +from urllib.parse import urlparse |
2 | 3 |
|
3 | | -from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, field_validator |
| 4 | +from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, field_serializer, field_validator |
4 | 5 |
|
5 | 6 |
|
6 | 7 | class OAuthToken(BaseModel): |
@@ -123,6 +124,20 @@ class OAuthClientInformationFull(OAuthClientMetadata): |
123 | 124 | client_secret_expires_at: int | None = None |
124 | 125 |
|
125 | 126 |
|
| 127 | +def _serialize_canonical_server_uri(url: AnyHttpUrl) -> str: |
| 128 | + """Serialize root server URIs without the implicit trailing slash. |
| 129 | +
|
| 130 | + RFC-defined canonical server URIs omit the synthetic "/" path that |
| 131 | + ``AnyHttpUrl`` adds for host-only URLs. Preserve non-root paths exactly. |
| 132 | + """ |
| 133 | + |
| 134 | + serialized = str(url) |
| 135 | + parsed = urlparse(serialized) |
| 136 | + if parsed.path == "/" and not parsed.params and not parsed.query and not parsed.fragment: |
| 137 | + return serialized[:-1] |
| 138 | + return serialized |
| 139 | + |
| 140 | + |
126 | 141 | class OAuthMetadata(BaseModel): |
127 | 142 | """ |
128 | 143 | RFC 8414 OAuth 2.0 Authorization Server Metadata. |
@@ -175,3 +190,11 @@ class ProtectedResourceMetadata(BaseModel): |
175 | 190 | dpop_signing_alg_values_supported: list[str] | None = None |
176 | 191 | # dpop_bound_access_tokens_required default is False, but ommited here for clarity |
177 | 192 | dpop_bound_access_tokens_required: bool | None = None |
| 193 | + |
| 194 | + @field_serializer("resource", when_used="json") |
| 195 | + def _serialize_resource(self, resource: AnyHttpUrl) -> str: |
| 196 | + return _serialize_canonical_server_uri(resource) |
| 197 | + |
| 198 | + @field_serializer("authorization_servers", when_used="json") |
| 199 | + def _serialize_authorization_servers(self, authorization_servers: list[AnyHttpUrl]) -> list[str]: |
| 200 | + return [_serialize_canonical_server_uri(url) for url in authorization_servers] |
0 commit comments