4

I know there's already a lot of discussion around the "unsupported_grant_type" error that occurs when using the Username/Password Authentication Flow, but I've exhausted through all other proposed solutions and am still having problems. I've found that from the Angular.JS app, I will get the error, but when I use cURL, it works fine.

The current route of the request originates on localhost:3001, goes through a proxy running on that same localhost at localhost:3001/proxy, where the request is then routed to the Salesforce instance. The proxy is made using Express.JS and the client side app is made using Angular.JS. Note: I did remember to tag my security token at the end of my password, although when using cURL, this doesn't seem to be necessary. Here are a series of HTTP traces that will hopefully provide some clues:

HTTP Request Log from Angular.JS App:

POST /proxy HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Content-Length: 234
Pragma: no-cache
Cache-Control: no-cache
X-User-Agent: salesforce-toolkit-rest-javascript/v29.0
Origin: http://localhost:3001
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: application/json, text/plain, */*
SalesforceProxy-Endpoint: https://uniquename.salesforce.com/services/oauth2/token
Referer: http://localhost:3001/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: liveagent_oref=; liveagent_ptid=3c69c2f9-139d-4439-ba6c-fd8d9dcae101; liveagent_vc=5
grant_type=password&client_id=3MVGxyzxyzxyzxyz&client_secret=99889988&username=first.last%40email.com&password=pswdwACYodaYfHs

400 Bad Request
Object {error_description: "grant type not supported", error: "unsupported_grant_type"}

Relevant Express.JS code used for proxy routing:

app.all('/proxy', function(req, res) {
    var url = req.header('SalesforceProxy-Endpoint');
    console.log(req.body); //prints all form data variables in JSON format
    console.log(res.body); //undefined

    request({url: url}).pipe(res).on('error', function(error){
        console.log(error);
    });
});

Request details using cURL:

curl -v https://uniquename.salesforce.com/services/oauth2/token
 -d "grant_type=password" -d "client_id=3MVGxyzxyzxyzxyz"
-d "client_secret=99889988" -d "username=jfirst.last@email.com" -d "password=pswd"

> POST /services/oauth2/token HTTP/1.1
> User-Agent: curl/7.41.0
> Host: uniquename.salesforce.com
> Accept: */*
> Content-Length: 207
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 207 out of 207 bytes
< HTTP/1.1 200 OK
< Date: Wed, 29 Jul 2015 06:04:55 GMT
< Set-Cookie: BrowserId=auu1mgvHSMS1EedDEduz8Q;Path=/;Domain=.salesforce.com;Exp
ires=Sun, 27-Sep-2015 06:04:55 GMT
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Cache-Control: no-cache, no-store
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
<
{
  "id":"https://test.salesforce.com/id/05390530530",
  "issued_at":"1438132525896197",
  "token_type":"Bearer",
  "instance_url":"https://uniquename.salesforce.com",
  "signature":"blahblah",
  "access_token":"XXXXXXXXXXXXXXXXX"
}
* Connection #0 to
host uniquename.salesforce.com left intact

As you can see, I get back a valid response from the cURL request. I suspect something is wrong with the proxy, as it may not be forwarding all the form data to Salesforce, but I'm not sure how to debug that in Express.JS. The reason I suspect this is because if I try curl https://uniquename.salesforce.com/services/oauth2/token it returns the same unsupported_grant_type error.

UPDATE: I got past the original error by including an Accept: '*/*' header in my request. Now I'm getting a response back from Salesforce saying:

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS
Date: Tue, 04 Aug 2015 21:58:53 GMT
Connection: keep-alive
Transfer-Encoding: chunked

Does anyone know how to enable POST on my instance? Remember, I'm using the Username/Password auth flow.

  • To any moderators who see this, maybe it makes sense to migrate this to StackOverflow as a Request/NodeJS/ExpressJS question? – JLewkovich Jul 29 '15 at 15:24
  • that seems to be the general opinion, i don't have the full suite of moderator tools, but i seem to recall in the past migrating things was a bit of a pain and they recommended just cross posting to save time – Ralph Callaway Jul 30 '15 at 23:18
  • Question reposted here: stackoverflow.com/questions/31736514/… – JLewkovich Jul 31 '15 at 1:09
  • 3
    Actually, I don't see why this is offtopic, it is clearly about authenticating with salesforce. – Samuel De Rycke Jul 31 '15 at 7:00
  • For the record, mods can't migrate themselves anyway! – Matt Lacey Aug 5 '15 at 2:55
0

I finally got this working by switching to use the cors-anywhere proxy. I deploy my AngularJS app on port 8080, and the proxy on port 3001. My packages are managed using npm and grunt. Here is the code for the proxy:

var host = 'localhost';
var port = 3001;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer().listen(port, host, function() {
    console.log('CORS proxy running on ' + host + ':' + port);
});

And here is how I'm making the HTTP request in AngularJS (you have to fill in your own credentials in the data object):

var login = {
    method: 'POST',
    url: 'http://localhost:3001/https://login.salesforce.com/services/oauth2/token',
    data: 'grant_type=password&client_id='+encodeURIComponent(CLIENT_ID)+'&client_secret='+encodeURIComponent(CLIENT_SECRET)+'&username='+encodeURIComponent(EMAIL)+'&password='+encodeURIComponent(PASSWORD+USER_SECURITY_TOKEN),
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': '*/*'
    }
};

$http(login).success(function(response){
    console.log(response);
})
.error( function(response, status){
    console.log(response);
    console.log("Status: " + status);
});

You can run the proxy with the node server.js command, and run the AngularJS app with grunt. I hope this helps someone out, this was a tough problem to solve.

  • But what was the problem? Sounds like you found a way to get the desired results but never uncovered what the problem was? – Eric Aug 6 '15 at 3:15
  • 1
    Honestly there were so many problems I cycled through after this initial one, but I believe the "unsupported_grant_type" error was caused by a proxy that wasn't fowarding along all the necessary information from the original request, and the problem listed in my UPDATE section was a CORS issue, which was solved by switching to a proxy that specifically handles CORS requests. You can look at the code in the cors-anywhere package to see how it does this. – JLewkovich Aug 6 '15 at 3:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.