OAuth2 server: `invalid_client` error returned for authorization code request, not documented in RFC 6749, section 4.1.2.1
Describe the "bug"
The authorization code grant error response will contain invalid_grant in the error field, if an invalid client is used.
This is indeed intuitive, but is not documented in RFC6749, section 4.1.2.1:
https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1
The list of valid error values, in the RFC, are:
- invalid_request
- unauthorized_client
- access_denied
- unsupported_response_type
- invalid_scope
- server_error
- temporarily_unavailable
This is done in validate_code_authorization_request.
☝🏻 Note that invalid_client is indeed one of the documented errors for the token route! Section 5.2 of the same RFC.
To Reproduce
A minimal example to reproduce the behavior:
Based on the documentation:
try:
grant = server.get_consent_grant(request, end_user=request.user)
except OAuth2Error as error:
result = server.handle_error_response(request, error)
return result
Call the route with a client not recognized by your server:
curl --location 'http://myserver/v1/oauth2/authorize/someuserid?response_type=code&client_id=totalybogus&code_challenge=rgw5CZck78w8i9KtMWLRt7hwPTAeXghvXo602q8y9FY&code_challenge_method=S256&redirect_uri=https://myserver/%3A%2F%2Foauth22'
The result content is:
{
"error":"invalid_client",
"error_description":"The client does not exist on this server."
}
Expected behavior
Not really sure! 😅
Environment:
- OS: Ubuntu 24.04
- Python Version: 3.10
- Authlib Version: 1.6.0
Additional context
If this is expected behavior, could you perhaps add a note in the documentation somewhere about it? Thanks! 🙏🏻
per https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
invalid_grant
The provided authorization grant (e.g., authorization
code, resource owner credentials) or refresh token is
invalid, expired, revoked, does not match the redirection
URI used in the authorization request, or was issued to
another client.
per https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
invalid_grant The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.
Hello! Could you please provide more context about the application of this citation to this issue?
Section 5.2 is about errors in the access token response.
This issue is about errors in the authorization response (section 4.1.2.1).
Thanks!
Oh, I got it. The authorization code request usually shows a "HTML" page instead of a JSON result, and this part is not documented in RFC 6749. Developers should implement the UI themselves.
try:
grant = server.get_consent_grant(request, end_user=request.user)
except OAuth2Error as error:
result = server.handle_error_response(request, error)
return result
The result usually is a HTML page. The error is designed to be easily to process the HTML error page.
Ok thanks, I think I understand better now! The RFC does document this in fact:
If the request fails due to a missing, invalid, or mismatching redirection URI, or if the client identifier is missing or invalid, the authorization server SHOULD inform the resource owner of the error and MUST NOT automatically redirect the user-agent to the invalid redirection URI.
This applies to an invalid client id. As you mentioned, this would be shown to the user in an html page.
In the example in the documentation, it shows to return result, which (with the default implementation, if I understand correctly) would return a json response with the error field. Would it be possible to adjust the example to indicate that, in the case that get_consent_grant raises an OAuth2Error, an error page should be shown in this case? Like instead of calling handle_error_response it should call render with some error template.
Alternatively, the documentation could suggest to extend AuthorizationServer, and override handle_error_response to return a rendered html response.
Thanks again!