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

Github - convert_token #56

Closed
LearningProcesss opened this issue Jun 5, 2021 · 11 comments · Fixed by #180
Closed

Github - convert_token #56

LearningProcesss opened this issue Jun 5, 2021 · 11 comments · Fixed by #180
Labels
drf-oauth2 enhancement New feature or request question Further information is requested

Comments

@LearningProcesss
Copy link

LearningProcesss commented Jun 5, 2021

Hi there,
how the github implementation is supposed to work?
Examples that i found all relate to Google or Facebook where those providers return an accessToken while Github returns a code.
At the moment i'm stuck at the point where i have the code from Github and i would convert into a token, so i do my POST request like this:

POST http://localhost:8000/auth/convert-token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

grant_type=convert_token
&client_id=aIK0dQjlOlDe9UwV0pZfR2DlEBX8HrqdqhSD1iNr
&client_secret=RXc9lTKqadPixO6ZoNiC8TWXPb7iLnQ5VeSMu0TXNkrnMVGynhHiDwzlNW6B1OftRpZ6nvWjpPiu2cA1aV0Iv7vgugwbXp1FOOCvnWHFSTeZbYrWxAbiX4dkTM7pVfEC
&backend=github
&token=35fa2fe846c3f6867e63 <- code from Github

(client_id e secret comes from django admin)

DRF response:

HTTP/1.1 400 Bad Request

{
  "error": "access_denied",
  "error_description": "Your credentials aren't allowed"
}

Below my settings

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'oauth2_provider',
'social_django',
'drf_social_oauth2',
]

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
],
},
},
]

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
'drf_social_oauth2.authentication.SocialAuthentication',
),
}

AUTHENTICATION_BACKENDS = (
'social_core.backends.github.GithubOAuth2',
'drf_social_oauth2.backends.DjangoOAuth2',
'django.contrib.auth.backends.ModelBackend',
)

SOCIAL_AUTH_GITHUB_KEY = 'my key'
SOCIAL_AUTH_GITHUB_SECRET = 'my secret'

SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
)

Sure i'm missing something.

Best regards,
Mattia

@sgallen
Copy link

sgallen commented Jun 13, 2021

See if this post provides any help: RealmTeam/django-rest-framework-social-oauth2#72

@wagnerdelima
Copy link
Owner

@LearningProcesss,
Did you manage to get this to work?

I am sorry but my time is really limited. I didn't get much help maintaining this repo.

@MilanZiaran
Copy link

MilanZiaran commented Jan 18, 2022

Hi @LearningProcesss. First you need to exchange the code for access_token. This is done by sending a POST request to https://github.com/login/oauth/access_token with body:

{
    "client_id": "string",
    "client_secret": "string",
    "code": "string"
}

Client credentials are in this case from the OAuth App on GitHub.

Now the obtained GitHub access_token can be used in your case, just replace it for the code in token=code.

@SukiCZ
Copy link

SukiCZ commented Sep 11, 2022

Hey, I'm facing the very same issue. I was able to exchange the "code" for "access_token" by sending request (as mentioned by @MilanZiaran ) but I was struggling a lot on this line of code.
The DrfSO library queries a database here to check for existing AccessToken objects for current user/application, if such token does not exist it will "create the request again, as a convert_token grant type". Calling such request obviously fail as the "code" was already used (already exchanged for "access_token") in previous step - and there is no way how to pass the obtained "access_token"

I've modified DrfSO library in my fork which basically reverts changes made by @wagnerdelima

Calling a convert-token now creates new token for every call which is still better than failing on an error "Your credentials aren't allowed".

I would like to open a PR if I would be sure reverting such changes is a way to go - maybe the token recreation should be handled by underlying library but IMO "recreating request" is something that is not a part of OAuth. Correct me if I'm wrong.

One more thing - I've modified GithubOAuth2 backend accordingly

class GitHubOAuth2(GithubOAuth2):
    @handle_http_errors
    def do_auth(self, access_token, *args, **kwargs):
        access_token = self.exchange_code_for_access_token(access_token)
        return super(GitHubOAuth2, self).do_auth(access_token, *args, **kwargs)

    @handle_http_errors
    def exchange_code_for_access_token(self, access_token):
        response = self.request_access_token(
            self.ACCESS_TOKEN_URL,
            data={
                "client_id": self.setting("SOCIAL_AUTH_GITHUB_KEY"),
                "client_secret": self.setting("SOCIAL_AUTH_GITHUB_SECRET"),
                "code": access_token,
                "scope": "user,user:email",
            },
            headers=self.auth_headers(),
            method=self.ACCESS_TOKEN_METHOD,
        )
        self.process_error(response)
        return response["access_token"]

EDIT: I¨m investigating what happened at jazzband/django-oauth-toolkit#1058

@wagnerdelima
Copy link
Owner

@LearningProcesss @SukiCZ @MilanZiaran

Adding GitHub Sign In is easy. Please refer to the GitHub section in the README file.

@SukiCZ
Copy link

SukiCZ commented Apr 8, 2023

@wagnerdelima Yes, it works as described in documentation where developer generates an Access Token that can be used multiple times. It doesn't work in production run, when GitHub issues a code (that can only be used once) which needs to be converted to an Access Token.

@wagnerdelima wagnerdelima added enhancement New feature or request question Further information is requested drf-oauth2 labels Apr 21, 2023
@wagnerdelima wagnerdelima reopened this Apr 21, 2023
@wagnerdelima
Copy link
Owner

wagnerdelima commented Apr 21, 2023

https://github.com/login/oauth/access_token

@SukiCZ thanks for your reply. Unfortunately I could not authenticate and get the token from the first step: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#1-request-a-users-github-identity.

I keep getting an 422Unprocessable Entity execption. I have been trying for hours.

Let me know if you can help.

@SukiCZ
Copy link

SukiCZ commented Apr 26, 2023

@wagnerdelima I would like to help but I wasn't able to reproduce 422 error.
I've made a small Django app that demonstrates working GitHub OAuth. Feel free to have a look https://github.com/SukiCZ/tmp_django

@wagnerdelima
Copy link
Owner

I will take a look at it, @SukiCZ

@wagnerdelima wagnerdelima linked a pull request Apr 28, 2023 that will close this issue
5 tasks
@wagnerdelima
Copy link
Owner

@SukiCZ thanks for your demo project. It helped me understand the flow from /authorize to /convert-token.

I updated the documentation of GitHub. You can find it here https://drf-social-oauth2.readthedocs.io/en/latest/integration.html#github-integration.

I did not understand why you needed to create a custom github baseauth. drf-social-oauth2 handled it without any other setup other than those listed in the GitHub settings.
Let me know if I am missing something.

@LearningProcesss hope this helps.

@SukiCZ
Copy link

SukiCZ commented Apr 28, 2023

sorry @wagnerdelima if I wasn't clear but the demo project is using modified version of drf-social-oauth2 + modfied BaseAuth.

Without any modification the OAuth flow starts with GET request to https://api.github.com/user with headers:
{"Authorization": "token 35fa2fe846c3f6867e63", "User-Agent": "social-auth-4.4.2"} which fails and the flow ends with

{
  "error": "access_denied",
  "error_description": "Your credentials aren't allowed"
}

The modified version of drf-social-oauth2 basically reverts changes from one of your commits where the flow was triggered twice. The modified BaseAuth sends a POST request to https://github.com/login/oauth/access_token with data

{
    "client_id": "<github client ID>",
    "client_secret": "<github client secret>",
    "code": "35fa2fe846c3f6867e63",
    "scope": "user,user:email"
}

which returns access_token (Bearer) that can be used to finish the flow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
drf-oauth2 enhancement New feature or request question Further information is requested
Projects
Development

Successfully merging a pull request may close this issue.

5 participants