fix(google): get_avatar_url sometimes returns None #3574
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
The Google provider is configured to rely on data decoded from the JWT for populating the user details. This results in a situation where, for certain users,
get_avatar_url
returnsNone
because the photo URL field is not always included in the JWT. An alternative approach is to hit the userinfo API, which consistently provides the user data across all accounts. The existing default scopes are sufficient to query this endpoint.Detail
The provider is currently configured to rely on data decoded from the JWT used in the login process for populating the user photo URL and other user attributes.
User photos in Google
Google seems to maintain two types of user photos which we will call "public" and "private" even though both are technically publicly accessible given you have the right URL:
JWT return values
I was able to establish via the Google OAuth 2 playground that the information encoded in a JWT differs based on the type of photo URL that an account has, such that:
Therefore, under the current approach, the user photo url is sometimes not populated into the backend as part of the "Extra data" json. Whether it is populated or not depends on what type of profile photo the user has. This is despite the fact that the default scopes are sufficient to access the photo url regardless of whether it is public or private. The relevant endpoint is just never used as part of the current approach.
Alternative approach to accessing user details
Given that the current default scopes for the Google provider are sufficient to actually access the photo URL of each user, doing so only requires hitting the relevant "user.info" endpoint, which is "https://www.googleapis.com/oauth2/v2/userinfo." My view is that any field that is reasonably needed by django-allauth can be gained by hitting this endpoint and so I have commented out the existing code entirely and all user details are now gained via this endpoint rather than decoding the JWT.
Custom scopes
If an existing codebase has used custom scopes, this should not be an issue. From what I can tell any scope at all is sufficient to query the userinfo endpoint, but what is returned will vary depending on whether you included email and profile scopes which are included by default.
Conclusion
This pull request changes the methodology used by the google provider to grab the user details to use the relevant endpoint rather than simply decoding the JWT. This was done in order to fix inconsistently populated user photo URLs. I welcome any debate or feedback on this issue that is needed before this PR can be merged.
Acknowledgement
Thank you so much for maintaining and providing such great open source software.