drf-social-oauth2
drf-social-oauth2 copied to clipboard
Github - convert_token
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
See if this post provides any help: https://github.com/RealmTeam/django-rest-framework-social-oauth2/issues/72
@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.
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.
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
@LearningProcesss @SukiCZ @MilanZiaran
Adding GitHub Sign In is easy. Please refer to the GitHub section in the README file.
@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.
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.
@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
I will take a look at it, @SukiCZ
@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.
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.