Authentication is failing
I'm trying without success to get my users signed into LinkedIn via Oauth authentication in Python. I'm using Django in python and not using any third party social authentication. I'm using the Guide to gain access to the API using Python and Django. However I am having trouble getting the Access Token. I can get the user logged in and get the Authentication Code. I have placed a new request as the earlier question was far too convoluted. You can see that here: Performing POST on a URL string in Django
Nothing was resolved and still unsure if this is an issue with LinkedIn or the code. LinkedIn have not been particularly helpful here, sadly.
but after getting the Author code, I simply cannot get the access token. I'm getting a 400 error for everything and despite getting the author code, on posting as the documentation suggests, I get the following:
u'oauth_problem=parameter_absent&oauth_parameters_absent=oauth_consumer_key%26oauth_signature%26oauth_signature_method%26oauth_token%26oauth_timestamp%26oauth_verifier'
I'm enclosing my Python code here in its entirety in the hope that someone can spot what is going wrong.
import oauth2 as oauth
import httplib2
import time, os, simplejson
import urllib
import urllib2
import pycurl
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.core.urlresolvers import resolve
#from django.core.shortcuts import render, redirect
from django import forms
from django.utils import timezone
import urlparse
import requests
consumer_key = 'Yours'
consumer_secret = 'Yours'
user_token = 'Yours'
user_secret = 'Yours'
consumer = oauth.Consumer(consumer_key, consumer_secret)
access_token = oauth.Token(key=user_token,secret=user_secret)
client = oauth.Client(consumer, access_token)
request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken'
access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken'
authorize_url = 'https://www.linkedin.com/uas/oauth/authenticate'
def login(request):
redirect_uri = urllib2.quote('http://127.0.0.1:9000/loginsuccess')
codeURL = "https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=c3skrqz5wqmm&scope=r_fullprofile&state=DCEEFWF45453sdffef425&redirect_uri=" + redirect_uri
# Fill the keys and secrets you retrieved after registering your app
# Use your API key and secret to instantiate consumer object
#resp,content = client.request("http://api.linkedin.com/v1/people/~?format=json", "GET", "")
#resp, content = client.request(request_token_url, "POST")
#request_token = dict(urlparse.parse_qsl(content))
#return HttpResponse(access_token)
return HttpResponseRedirect(codeURL)
def loginsuccess(request):
authcode = request.GET.get('code')
redirect_uri = 'http://www.jelt.com'
#redirect_succ = 'http://www.127.0.0.1:8080/manage'
postdata = {
'grant_type': 'authorization_code',
'code': authcode,
'redirect_uri': redirect_uri,
'client_id': consumer_key,
'client_secret': consumer_secret,
}
r = requests.post(access_token_url, data=postdata)
#return HttpResponse(r.text)
#return HttpResponse(r.status_code)
return HttpResponseRedirect(redirect_uri)
def Manage(request):
return HttpResponseRedirect('http://www.xyz.com')
def success(request):
redirect_uri = urllib2.quote('http://www.xyz.com')
redirect_uri = "http://www.xyz.com"
return HttpResponseRedirect(redirect_uri)
Your login code is redirecting to the OAuth 2.0 endpoint https://www.linkedin.com/uas/oauth2/authorization but your callback loginsuccess is trying to fetch the OAuth 1.0a token from https://api.linkedin.com/uas/oauth/accessToken. You need to update your access_token_url to the OAuth 2.0 endpoint https://www.linkedin.com/uas/oauth2/accessToken per the LinkedIn docs.
Related
I would like to return the token as a string to another python script. However I'm stuck at the callback page. I made the redirect_uri to "/callback" and it returns the authorization code in the URL as
www.my.website.com/callback?code={code}.
The Facebook OAuth 2 example at http://requests-oauthlib.readthedocs.org/en/latest/examples/facebook.html. I keep getting a 404 error by just pasting the redirect URI.
I would also like to request the following parameters: {id, message, created_time} but I'm not sure how.
import os
from requests_oauthlib import OAuth2Session
from flask import Flask, request, redirect, session, render_template, url_for
from requests_oauthlib.compliance_fixes import facebook_compliance_fix
app = Flask(__name__)
app.secret_key = os.urandom(24)
#app.route("/login")
def demo():
client_id = '1624399237811291'
client_secret = 'SECRET'
# OAuth endpoints given in the Facebook API documentation
authorization_base_url = 'https://www.facebook.com/dialog/oauth'
token_url = 'https://graph.facebook.com/oauth/access_token'
redirect_uri = 'http://www.bbg.mybluemix.net/callback' # Should match Site URL
facebook = OAuth2Session(client_id, redirect_uri=redirect_uri)
facebook = facebook_compliance_fix(facebook)
# Redirect user to Facebook for authorization
authorization_url, state = facebook.authorization_url(authorization_base_url)
authurl = '%s' % authorization_url
return render_template('welcome.html', authurl=authurl)
# Get the authorization verifier code from the callback url
#app.route("/callback", methods=["GET"])
def callback():
# Fetch the access token
redirect_response = ' '
token = facebook.fetch_token(token_url, client_secret=client_secret,
authorization_response=redirect_response)
return '%s' % token
# Fetch a protected resource, i.e. user profile
#r = facebook.get('https://graph.facebook.com/me?')
#return '%s' % r.content
I'm using django rest framework for exposing an api and django oauth toolkit for authentication. So after writing a custom ModelBackend and relevant unit tests, I was trying to write some integration tests too, to verify the endpoint using this backend is returning an access token for some scenarios..
I'm using drf APIClient for making test requests and works great for everything else, but in this I case I'm getting {"error": "unsupported_grant_type"} when I do:
from requests.auth import _basic_auth_str
from rest_framework.test import APIClient
client = APIClient()
client.credentials(HTTP_AUTHORIZATION=_basic_auth_str(CLIENT_ID, CLIENT_SECRET))
client.post(
'/oauth2/token/',
{'grant_type': 'password', 'username': 'user1', 'password': 'pass1'},
content_type='application/x-www-form-urlencoded'
)
Any ideas?
I got it to work. I was not encoding the payload. Here is the full working code with example asserts:
import urllib
from requests.auth import _basic_auth_str
from rest_framework.test import APIClient
client = APIClient()
url = reverse('access_token')
data = urllib.urlencode({
'client_id': client_id,
'client_secret': client_secret,
'grant_type': grant_type
})
response = self.client.post(url, data,
content_type='application/x-www-form-urlencoded',
HTTP_AUTHORIZATION=_basic_auth_str(self.client_id, self.client_secret)
)
self.assertEqual(response.status_code, 200)
self.assertIn('access_token', json.loads(response.content))
...
My website uses Django's default auth module to do user authentications. Usually, user just needs to fill out a html form in the login page with his/her username and password and click submit, then the CSRF-protected data will be posted to /auth/login/, the Django auth endpoint.
But now for some reason I also need to do this on my server. This is the same server as the backend authentication server. After researching and trials and errors, I finally got:
from django.views.generic import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
import requests
class fb_login(View):
"login view for Facebook OAuth"
#method_decorator(csrf_protect)
def get(self, request):
''' code that gets username and password info. from user's FB profile
is not shown here '''
# login code
url = 'http://localhost:8000/auth/login/'
client = requests.session()
# Retrieve the CSRF token first
client.get(url) # sets cookie
csrftoken = client.cookies['csrftoken']
form = {'username': uname, 'password': pw}
header = {'X-CSRFToken': csrftoken}
resp = requests.post(url, data=form, headers=header)
I also tried to add csrf token as part of the form field:
form = {'username': uname, 'password': pw , 'csrfmiddlewaretoken': csrftoken}
resp = requests.post(url, data=form)
I pretty much just followed the Django doc. But I still get the 403 error saying CSRF verification failed, CSRF cookie not set. I wonder if I missed something here? I've double-checked the process against the Django doc but I cannot find anything that might be wrong or missing.
As suggested by #rodrigo, cookies are also needed to pass the CSRF security check. Here's a simple code snippet:
csrftoken = requests.get(url).cookies['csrftoken']
form = {'username': uname, 'password': pw}
header = {'X-CSRFToken': csrftoken}
cookies = {'csrftoken': csrftoken}
resp = requests.post(url, data=form, headers=header, cookies=cookies)
I am trying to enable authentication in my single page angular app using Satellizer as client on frontend and python social auth on backend using django rest framework. The main problem is that I want to use JWT instead of session authentication.
I have tried passing the response I get after the user confirms the popup window to social/complete/backend (python social auth view) but with no luck.
In satellizer for google configuration I put:
$authProvider.google({
clientId:'609163425136-1i7b7jlr4j4hlqtnb1gk3al2kagavcjm.apps.googleusercontent.com',
url: 'social/complete/google-oauth2/',
optionalUrlParams: ['display', 'state'],
state: function() {
return Math.random();
}
});
The problems I encounter are in python social auth:
Missing needed parameter state
for google-oauth2
and
Missing needed parameter code
for facebook.
That is very strange to me because those parameters are present in the request payload and I can get then in my own custom view.
The closest I have come to a solution is writing my own view in which I can accept the parameter state normally.
This is my view which handles the response and creates a new jwt token using the django-rest-framework-jwt:
class SocialAuthView(APIView):
throttle_classes = ()
permission_classes = ()
authentication_classes = ()
social_serializer = SocialAuthSerializer
user_serializer = None
def post(self, request):
access_token_url = 'https://accounts.google.com/o/oauth2/token'
people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect'
from django.conf import settings
payload = dict(client_id=request.data['clientId'],
redirect_uri=request.data['redirectUri'],
client_secret=settings.SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET,
code=request.data['code'],
grant_type='authorization_code')
# Step 1. Exchange authorization code for access token.
import requests
import json
r = requests.post(access_token_url, data=payload)
token = json.loads(r.text)
headers = {'Authorization': 'Bearer {0}'.format(token['access_token'])}
# Step 2. Retrieve information about the current user.
r = requests.get(people_api_url, headers=headers)
profile = json.loads(r.text)
try:
user = User.objects.filter(email=profile['email'])[0]
except IndexError:
pass
import jwt
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler
if user:
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({'token': token.decode('unicode_escape')},
status=status.HTTP_200_OK)
u = User.objects.create(username=profile['name'], first_name=profile['given_name'],
last_name=profile['family_name'], email=profile['email'])
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({'Bearer': token.decode('unicode_escape')},
status=status.HTTP_200_OK)
I mean, it works, but I don't get all the benefits that I would get if I could implement it with python social auth. Maybe there is a way to authenticate with python social auth calling some functions like do_auth from this view?
It amazes me how much I struggle with this problem.
All help is welcome.
tl,dr: How to implement angular single page application using Satellizer, django-rest-framework, python social auth and JWT?
Not quite an answer, but I don't have sufficient reputation to comment.
I've been trying to do something similar. Satellizer works well with DRF's djoser module for email/pass token auth.
As for the social aspect, I'm finding OAuth2 quite complicated. You might want to look at the following project (no relation to me), it seems to be trying to implement just that (angularjs-satellizer/psa/jwt):
https://github.com/hsr-ba-fs15-dat/opendatahub
specifically:
https://github.com/hsr-ba-fs15-dat/opendatahub/blob/master/src/main/python/authentication/views.py
I'm trying to connect my django app with the Google Calendar API v3.
To do this I'm using the Google API Python client
In the docs I see a reference about how to create a service object.
I see an example of how to use it here Django example from Google.
This is a portion of my views.
import logging
import httplib2
from oauth2client.django_orm import Storage
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.util import logger
from apiclient.discovery import build
from core.models import FlowModel, CredentialsModel
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
FLOW = OAuth2WebServerFlow(
client_id= _cliente_id,
client_secret= _cliente_secret,
scope= _scope,
user_agent=_user_agent)
current_site = Site.objects.get_current()
URI = "http://"+str(current_site)+"/auth_return"
def authentice(request):
user = request.user
storage = Storage(CredentialsModel, 'id', user, 'credential')
credential = storage.get()
if credential is None or credential.invalid == True:
authorize_url = FLOW.step1_get_authorize_url(URI)
f = FlowModel(id=user, flow=flow)
f.save()
return authorize_url
else:
http = httplib2.Http()
http = credential.authorize(http)
# The Service Object
service = build(serviceName='calendar', version='v3', http=http)
return service
def auth_return(request):
f = FlowModel.objects.get(id=request.user)
credential = f.FLOW.step2_exchange(request.REQUEST) #Zica aqui...
storage = Storage(CredentialsModel, 'id', request.user, 'credential')
storage.put(credential)
f.delete()
return HttpResponseRedirect("/")
def new_calendar(request):
service = authentice(request)
if request.POST:
service = authentice(request)
calendar = {
'summary': request.POST.get("summary"),
'timeZone': 'America/Santo_Domingo'
}
created_calendar = service.calendars().insert(body=calendar).execute()
return HttpResponseRedirect("/")
else:
return render_to_response('calendar_form.html',
context_instance=RequestContext(request))
This is returning the next error:
'str' object has no attribute 'calendars'
It's actually returning an string (A URL) an not a Service Object, and I don't know why.
If one of you have any idea, please help me with this.
PS: Sorry for my English! :P