Skip to content

Commit b0275dd

Browse files
committed
feat(keycardai-oauth): client metadata updates
1 parent 46a6de9 commit b0275dd

2 files changed

Lines changed: 56 additions & 36 deletions

File tree

packages/oauth/src/keycardai/oauth/types/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
Endpoints,
1010
JsonWebKey,
1111
JsonWebKeySet,
12+
OAuthClientMetadata,
13+
OAuthClientMetadataFull,
1214
PushedAuthorizationRequest,
1315
RevocationRequest,
1416
ServerMetadataRequest,
@@ -34,6 +36,8 @@
3436
"Endpoints",
3537
"JsonWebKey",
3638
"JsonWebKeySet",
39+
"OAuthClientMetadata",
40+
"OAuthClientMetadataFull",
3741
"PKCE",
3842
"PushedAuthorizationRequest",
3943
"RevocationRequest",

packages/oauth/src/keycardai/oauth/types/models.py

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -98,70 +98,86 @@ class RevocationRequest(BaseModel):
9898
# Dynamic Client Registration (RFC 7591)
9999
# =============================================================================
100100

101-
class ClientRegistrationRequest(BaseModel):
102-
"""Dynamic Client Registration Request as defined in RFC 7591 Section 2.
101+
class OAuthClientMetadata(BaseModel):
102+
"""Base OAuth 2.0 Client Metadata fields (RFC 7591 Section 2).
103+
104+
Common metadata fields shared across client registration requests,
105+
responses, and client information representations.
103106
104107
Reference: https://datatracker.ietf.org/doc/html/rfc7591#section-2
105108
"""
106-
client_id: str | None = None
107-
client_name: str = Field(..., min_length=1, description="Human-readable name of the client application.")
109+
# Core client identification
110+
client_name: str | None = None
111+
client_uri: str | None = None
112+
logo_uri: str | None = None
113+
114+
# Policy and legal URIs
115+
tos_uri: str | None = None
116+
policy_uri: str | None = None
117+
118+
# Software identification
119+
software_id: str | None = None
120+
software_version: str | None = None
121+
122+
# Authentication configuration
108123
jwks_uri: str | None = None
109124
jwks: dict | None = None
125+
token_endpoint_auth_method: TokenEndpointAuthMethod | None = None
126+
127+
# OAuth flow configuration
128+
redirect_uris: list[str] | None = None
129+
grant_types: list[GrantType] | None = None
130+
response_types: list[ResponseType] | None = None
131+
scope: str | None = None
132+
133+
class OAuthClientMetadataFull(OAuthClientMetadata):
134+
"""OAuth 2.0 Client Metadata fields (RFC 7591 Section 2).
135+
136+
Reference: https://datatracker.ietf.org/doc/html/rfc7591#section-2
137+
"""
138+
client_id: str
139+
client_secret: str | None = None
140+
client_id_issued_at: int | None = None
141+
client_secret_expires_at: int | None = None
142+
143+
144+
class ClientRegistrationRequest(OAuthClientMetadata):
145+
"""Dynamic Client Registration Request as defined in RFC 7591 Section 2.
146+
147+
Reference: https://datatracker.ietf.org/doc/html/rfc7591#section-2
148+
"""
149+
# Override with required field
150+
client_name: str = Field(..., min_length=1, description="Human-readable name of the client application.")
151+
152+
# Override with defaults for registration
110153
token_endpoint_auth_method: TokenEndpointAuthMethod = (
111154
TokenEndpointAuthMethod.CLIENT_SECRET_BASIC
112155
)
113156
redirect_uris: list[str] | None = Field(default_factory=lambda: ["http://localhost:8080/callback"])
114157
grant_types: list[GrantType] | None = Field(default_factory=lambda: [GrantType.TOKEN_EXCHANGE, GrantType.CLIENT_CREDENTIALS])
115158
response_types: list[ResponseType] | None = Field(default_factory=lambda: [ResponseType.CODE])
116159
scope: str | None = "read write"
160+
161+
# Request-specific fields
162+
client_id: str | None = None
117163
timeout: float | None = None
118164
additional_metadata: dict[str, Any] | None = None
119165

120-
# Direct client metadata fields (alternatives to additional_metadata)
121-
client_uri: str | None = None
122-
logo_uri: str | None = None
123-
tos_uri: str | None = None
124-
policy_uri: str | None = None
125-
software_id: str | None = None
126-
software_version: str | None = None
127-
128166

129-
@dataclass
130-
class ClientRegistrationResponse:
167+
class ClientRegistrationResponse(OAuthClientMetadataFull):
131168
"""RFC 7591 Dynamic Client Registration Response.
132169
133170
Preserves all RFC 7591 fields plus vendor extensions and response metadata.
134171
Reference: https://datatracker.ietf.org/doc/html/rfc7591#section-3.2.1
135172
"""
136173

137-
# Server-generated required fields
138-
client_id: str
139-
client_secret: str | None = None
140-
client_id_issued_at: int | None = None
141-
client_secret_expires_at: int | None = None
142-
143-
# Echoed request fields
144-
client_name: str | None = None
145-
jwks_uri: str | None = None
146-
jwks: dict | None = None
147-
token_endpoint_auth_method: TokenEndpointAuthMethod | None = None
148-
redirect_uris: list[str] | None = None
149-
grant_types: list[GrantType] | None = None
150-
response_types: list[ResponseType] | None = None
174+
# Override scope type from str to list[str] for responses
151175
scope: list[str] | None = None
152176

153177
# Additional server-provided metadata
154178
registration_access_token: str | None = None
155179
registration_client_uri: str | None = None
156180

157-
# Additional client metadata (vendor extensions)
158-
client_uri: str | None = None
159-
logo_uri: str | None = None
160-
tos_uri: str | None = None
161-
policy_uri: str | None = None
162-
software_id: str | None = None
163-
software_version: str | None = None
164-
165181
# Vendor extensions and debugging
166182
raw: dict[str, Any] | None = None
167183
headers: dict[str, str] | None = None

0 commit comments

Comments
 (0)