Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AUTHORIZATION_URL and ACCESS_TOKEN_URL attributes usage #49

Merged
merged 12 commits into from
Sep 8, 2024

Conversation

Tatayoyoh
Copy link
Contributor

Motivation:

Hi there !

When I'm using FacebookOAuth2 or FacebookAppOAuth2 backends, and I'm facing to a wrong generated URL for OAuth like this : https://www.facebook.com/v{version}/dialog/oauth

Instead of https://www.facebook.com/v18.0/dialog/oauth

After some investigations, the error provides from OAuth2Strategy in core.py that defining an uncomplete get_setting() code.

class OAuth2Strategy(BaseStrategy):
    """Dummy strategy for using the `BaseOAuth2.user_data` method."""
    ...

    def get_setting(self, name) -> Any:
        """Mocked setting method."""

I fixed it by getting settings through environment (for example, it fit with my Docker/FastAPI project :p)

class OAuth2Strategy(BaseStrategy):
    """Dummy strategy for using the `BaseOAuth2.user_data` method."""
    ...

    def get_setting(self, name) -> Any:
        """ settings from environment """
        return os.getenv(name, '')

One more fix is to use authorization_url() and access_token_url() despite of to use AUTHORIZATION_URL and ACCESS_TOKEN_URL that can contain variables like facebook.py backend

class OAuth2Core:
    """OAuth2 flow handler of a certain provider."""
    ...

    def __init__(self, client: OAuth2Client) -> None:
        ...
        self.backend = client.backend(OAuth2Strategy())
        # self._authorization_endpoint = client.backend.AUTHORIZATION_URL   # <<<< could contain variable
        self._authorization_endpoint = self.backend.authorization_url()   
        # self._token_endpoint = client.backend.ACCESS_TOKEN_URL            # <<<< could contain variable
        self._token_endpoint = self.backend.access_token_url()
        self._oauth_client = WebApplicationClient(self.client_id)

Here is facebook.py from social_core package :

""" social_core/backends/facebook.py """
class FacebookOAuth2(BaseOAuth2):
    ...
    AUTHORIZATION_URL = "https://www.facebook.com/v{version}/dialog/oauth"         # <<<< format variable
    ACCESS_TOKEN_URL = "https://graph.facebook.com/v{version}/oauth/access_token"  # <<<< format variable
    REVOKE_TOKEN_URL = "https://graph.facebook.com/v{version}/{uid}/permissions"   # <<<< format variable
    USER_DATA_URL = "https://graph.facebook.com/v{version}/me"                     # <<<< format variable
    ....
    
    def authorization_url(self):
        version = self.setting("API_VERSION", API_VERSION)
        return self.AUTHORIZATION_URL.format(version=version)

Can you review this code and release a new version if it sounds good for you ?

Thanks a lot for your repo :)

@ArtyomVancyan
Copy link
Member

Hi @Tatayoyoh, the issue is clear, but this was already suggested once in #31, and it wasn't merged because this solution causes issues to another backend. The thing I suggest is just to extend the class and override the URLs with appropriate values:

from social_core.backends import facebook

class FacebookOAuth2(facebook.FacebookOAuth2):
    AUTHORIZATION_URL = "https://www.facebook.com/v18.0/dialog/oauth"
    ACCESS_TOKEN_URL = "https://graph.facebook.com/v18.0/oauth/access_token"
    USER_DATA_URL = "https://graph.facebook.com/v18.0/me"

@Tatayoyoh
Copy link
Contributor Author

Tatayoyoh commented Sep 4, 2024

Thanks for your fast answer :)

So I just added a check condition if authorization_url() and access_token_url() methods exist, and using AUTHORIZATION_URL and ACCESS_TOKEN_URL otherwise.

class OAuth2Core:
    """OAuth2 flow handler of a certain provider."""
    ...
    def __init__(self, client: OAuth2Client) -> None:
        ...
        self.backend = client.backend(OAuth2Strategy())
        self._authorization_endpoint = self.backend.authorization_url() if hasattr(self.backend, 'authorization_url') else self.backend.AUTHORIZATION_URL
        self._token_endpoint = self.backend.access_token_url() if hasattr(self.backend, 'access_token_url') else self.backend.ACCESS_TOKEN_URL

It should do the job !

@ArtyomVancyan
Copy link
Member

Hint: You can run tox or pytest locally and check if all the tests succeed before committing the changes :) It would be nice to have this feature.

@Tatayoyoh
Copy link
Contributor Author

Yes thanks to the CI I have seen that too :)
Tests fixed (only tried locally with Python3.10)

@ArtyomVancyan
Copy link
Member

ArtyomVancyan commented Sep 8, 2024

@Tatayoyoh, thanks for the effort you put into creating the PR. I have made little changes to yours so it will work with all the backends without skipping any of them :)

https://docs.pysnippet.org/fastapi-oauth2/integration/configuration#backends

@ArtyomVancyan ArtyomVancyan merged commit 350b526 into pysnippet:master Sep 8, 2024
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants