authlib icon indicating copy to clipboard operation
authlib copied to clipboard

OAuth2 server: `invalid_client` error returned for authorization code request, not documented in RFC 6749, section 4.1.2.1

Open caarmen opened this issue 5 months ago • 4 comments

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! 🙏🏻

caarmen avatar Aug 07 '25 10:08 caarmen

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.

lepture avatar Aug 07 '25 11:08 lepture

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!

caarmen avatar Aug 07 '25 11:08 caarmen

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.

lepture avatar Aug 08 '25 02:08 lepture

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!

caarmen avatar Aug 08 '25 06:08 caarmen