I am an advanced beginner and I have been stuck on this issue for a couple of days now. The app I am creating requires access to each user's Salesforce account. In order to make an API connection, we need to store their Salesforce username, password and access token.
The user will provide their Salesforce username and password then click a button to Authorize. This button directs the user to:
The response from Salesforce Oauth servers should be:
https://www.mysite.com/oauth/salesforce/?display=popup&code=aPrx6RMKPrMpm.SHNCxBmHz3ZiHMc.xZRY9RHLekkzW_G8Uu.KyqmmY0.JGCr5roqPT49vTCbg%3D%3D
Here is the views.py file
from django.views.generic.base import RedirectView, TemplateView, View
from django.http import Http404, HttpResponse
from django.conf import settings
from django.contrib import messages
from django.core.urlresolvers import reverse_lazy, reverse
from guardian.mixins import LoginRequiredMixin
from simple_salesforce import Salesforce
import logging
from campaigns.views import CampaignOwnerPermission
from . import api, utils, settings
from .models import OauthToken
class SalesforceOauthRedirectView(
LoginRequiredMixin,
RedirectView
):
def get_redirect_url(self):
logger = logging.getLogger(__name__)
# Extract 'code' parameter from return URL and set to variable
if (
not self.request.GET.get(
'code', None
) is None
):
try:
existing_credentials = OauthToken.objects.get(
user=request.user
)
# get stored Salesforce username and password
username = str(existing_credentials.salesforce_user_id)
password = str(existing_credentials.password)
payload = {
'grant_type': 'password',
'client_id': str(settings.CONSUMER_KEY),
'client_secret': str(settings.CONSUMER_SECRET),
'username': username,
# must concatenate password & code before passing to server
'password': password + str(code)
}
try:
# Post payload to Salesforce Oauth server and get user
# token in response.
r = requests.post(
"https://login.salesforce.com/services/oauth2/token",
headers={
"Content-Type":"application/x-www-form-urlencoded"
},
data=payload
)
# Decode the JSON response from Salesforce Oauth server
decoded = json.loads(r.content)
# Store access_token to database
existing_credentials.token = decoded['access_token']
existing_credentials.active = True
existing_credentials.save()
messages.add_message(
self.request,
messages.SUCCESS,
_(
'Successfully updated Salesforce \
authentication with user credentials: "%s"'
%
salesforce_user_id
)
)
# Success point
return reverse_lazy('providers:provider_list')
# except (ValueError, KeyError, TypeError):
# logger.error('Could not decode response from Salesforce API')
# Not sure how this should be arranged
except:
logger.error(
'Could not get Oauth_token from Salesforce API.'
)
messages.add_message(
self.request,
messages.WARNING,
('Could not get Oauth_token from Salesforce API.\n\n \
Salesforce may be experiencing an outage. Try again \
in a few minutes and contact explorro support if the \
problem persists.'
)
)
return reverse_lazy('providers:provider_list')
except:
logger.error('Could not get users Salesforce credentials')
messages.add_message(
self.request,
messages.WARNING,
('There was a problem authenticating with \
Salesforce. Be sure to enter your Salesforce \
username and password before attempting to authorize your\
account. Contact our support team if you need some help.'
)
)
return reverse_lazy('providers:provider_list')
else:
pass
return reverse_lazy('providers:provider_list')
messages.add_message(
self.request,
messages.WARNING,
('Could not retrieve Salesforce Authorization Code\n\n \
Contact your Salesforce administrator for assistance.'
)
)
The 'code' parameter (example value = randomTextCode) is parsed from the response URL, and passed as part of the 'payload' variable (line 38) to https://login.salesforce.com/services/oauth2/token
The last step should be receiving a JSON response from https://login.salesforce.com/services/oauth2/token which contains the access_token
The error seems to be originating from the first try/except statement, as I am getting the exception error message on lines #103-106.
While running locally, here is the server response (301)
"GET /oauth/salesforce/?display=popup&code=aPrx6RMKPrMpm.SHNCxBmHz3ZgWIqBWQKmln4Q6TfdI8TbmeWuMw5H..Di.342no15VYNvmgzA%3D%3D HTTP/1.1" 301 0
Here is models.py
from django.db import models
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
class OauthToken(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='Salesforce User',
verbose_name=_('Salesforce User'),
db_index=True,
)
salesforce_user_id = models.EmailField(
verbose_name=_('Salesforce user id'),
db_index=True, unique=True
)
password = models.CharField( # TODO: This needs to be encrypted!!
verbose_name=_('Salesforce password'),
max_length=256,
)
token = models.CharField(
verbose_name=_('Token'),
max_length=256,
null=True,
blank=True,
)
security_token = models.CharField(
verbose_name=_('Security Token'),
max_length=256
)
active = models.BooleanField(
verbose_name=_('Active'),
default=False,
db_index=True
)
def __unicode__(self):
return str(self.salesforce_user_id)
class Meta:
verbose_name = _('Oauth token')
verbose_name_plural = _('Oauth tokens')
Any help troubleshooting this issue is greatly appreciated.