Add client_secret_basic authentication support (#1334)
Co-authored-by: Paul Carleton <paulc@anthropic.com>
This commit is contained in:
parent
397089a78e
commit
c51936f61f
3 changed files with 695 additions and 59 deletions
|
|
@ -49,6 +49,11 @@ class RegistrationHandler:
|
|||
)
|
||||
|
||||
client_id = str(uuid4())
|
||||
|
||||
# If auth method is None, default to client_secret_post
|
||||
if client_metadata.token_endpoint_auth_method is None:
|
||||
client_metadata.token_endpoint_auth_method = "client_secret_post"
|
||||
|
||||
client_secret = None
|
||||
if client_metadata.token_endpoint_auth_method != "none": # pragma: no branch
|
||||
# cryptographically secure random 32-byte hex string
|
||||
|
|
|
|||
|
|
@ -39,6 +39,17 @@ class RevocationHandler:
|
|||
"""
|
||||
Handler for the OAuth 2.0 Token Revocation endpoint.
|
||||
"""
|
||||
try:
|
||||
client = await self.client_authenticator.authenticate_request(request)
|
||||
except AuthenticationError as e: # pragma: no cover
|
||||
return PydanticJSONResponse(
|
||||
status_code=401,
|
||||
content=RevocationErrorResponse(
|
||||
error="unauthorized_client",
|
||||
error_description=e.message,
|
||||
),
|
||||
)
|
||||
|
||||
try:
|
||||
form_data = await request.form()
|
||||
revocation_request = RevocationRequest.model_validate(dict(form_data))
|
||||
|
|
@ -51,20 +62,6 @@ class RevocationHandler:
|
|||
),
|
||||
)
|
||||
|
||||
# Authenticate client
|
||||
try:
|
||||
client = await self.client_authenticator.authenticate(
|
||||
revocation_request.client_id, revocation_request.client_secret
|
||||
)
|
||||
except AuthenticationError as e: # pragma: no cover
|
||||
return PydanticJSONResponse(
|
||||
status_code=401,
|
||||
content=RevocationErrorResponse(
|
||||
error="unauthorized_client",
|
||||
error_description=e.message,
|
||||
),
|
||||
)
|
||||
|
||||
loaders = [
|
||||
self.provider.load_access_token,
|
||||
partial(self.provider.load_refresh_token, client),
|
||||
|
|
|
|||
|
|
@ -91,10 +91,26 @@ class TokenHandler:
|
|||
)
|
||||
|
||||
async def handle(self, request: Request):
|
||||
try:
|
||||
client_info = await self.client_authenticator.authenticate_request(request)
|
||||
except AuthenticationError as e:
|
||||
# Authentication failures should return 401
|
||||
return PydanticJSONResponse(
|
||||
content=TokenErrorResponse(
|
||||
error="unauthorized_client",
|
||||
error_description=e.message,
|
||||
),
|
||||
status_code=401,
|
||||
headers={
|
||||
"Cache-Control": "no-store",
|
||||
"Pragma": "no-cache",
|
||||
},
|
||||
)
|
||||
|
||||
try:
|
||||
form_data = await request.form()
|
||||
token_request = TokenRequest.model_validate(dict(form_data)).root
|
||||
except ValidationError as validation_error:
|
||||
except ValidationError as validation_error: # pragma: no cover
|
||||
return self.response(
|
||||
TokenErrorResponse(
|
||||
error="invalid_request",
|
||||
|
|
@ -102,19 +118,6 @@ class TokenHandler:
|
|||
)
|
||||
)
|
||||
|
||||
try:
|
||||
client_info = await self.client_authenticator.authenticate(
|
||||
client_id=token_request.client_id,
|
||||
client_secret=token_request.client_secret,
|
||||
)
|
||||
except AuthenticationError as e: # pragma: no cover
|
||||
return self.response(
|
||||
TokenErrorResponse(
|
||||
error="unauthorized_client",
|
||||
error_description=e.message,
|
||||
)
|
||||
)
|
||||
|
||||
if token_request.grant_type not in client_info.grant_types: # pragma: no cover
|
||||
return self.response(
|
||||
TokenErrorResponse(
|
||||
|
|
|
|||
Loading…
Reference in a new issue