I am using the JSForce docs in order to create a Javascript app to connect to my Salesforce org. My code is as follows:
var jsforce = require('jsforce');
var conn = new jsforce.Connection({
loginUrl : 'https://test.salesforce.com'
});
var username = 'my-username#domain.com';
var password = 'mypassword';
conn.login(username, password, function(err, userInfo) {
if (err) { return console.error(err); }
console.log(conn.accessToken);
console.log(conn.instanceUrl);
console.log("User ID: " + userInfo.id);
console.log("Org ID: " + userInfo.organizationId);
});
However, when I run it, it appears to do nothing at all. I would expact to see either the access token etc to be logged to indicate success, or an error to indicate failure. But nothing is logged at all.
When I check the login history on my Salesforce org, I can see the attempts, they are successful.
What's going on?
The answer is simple. The instructions are for jsforce v1.x, but I had jsforce 2.x (beta). Fixed by doing this:
npm install jsforce#1.11.0
Related
I'm using the node-linkedin npm package to authenticate and read information about from other users (name, job title, company name, profile pic, shared connections). I can correctly receive and store the access token (verified in my own LinkedIn profile's approved apps & console logging the token), but I am unable to return any of the requested information. My calls are copied & pasted from the package docs, but it returns the following:
2018-02-28T03:46:53.459839+00:00 app[web.1]: { errorCode: 0,
2018-02-28T03:46:53.459843+00:00 app[web.1]: message: 'Unknown authentication scheme',
2018-02-28T03:46:53.459845+00:00 app[web.1]: requestId: '3B55EVY7XQ',
2018-02-28T03:46:53.459847+00:00 app[web.1]: status: 401,
2018-02-28T03:46:53.459848+00:00 app[web.1]: timestamp: 1519789613443 }
I have included my routes below. Solely for the purpose of testing, myToken and linkedin are server-side global variables to the linkedin-controller scope. (I understand this will need to change for the final product, which is a student project.)
app.get('/companies', function (req, res) {
console.log(linkedin.connections.config.accessToken);
linkedin.companies_search.name('facebook', 1, function(err, company) {
console.log('Merpy merpy mc merpers'
,company);
// name = company.companies.values[0].name;
// desc = company.companies.values[0].description;
// industry = company.companies.values[0].industries.values[0].name;
// city = company.companies.values[0].locations.values[0].address.city;
// websiteUrl = company.companies.values[0].websiteUrl;
res.redirect("/");
});
});
app.get('/companies2', function (req, res) {
linkedin.companies.company('162479', function(err, company) {
console.log(company);
res.redirect("/");
});
});
app.get('/connections', function (req, res) {
linkedin.connections.retrieve(function(err, connections) {
console.log(connections);
res.redirect("/");
});
});
This is my authorization code, which appears to work:
app.get('/auth', function (req, res) {
// This is the redirect URI which linkedin will call to and provide state and code to verify
/**
*
* Attached to the redirect_uri will be two important URL arguments that you need to read from the request:
code — The OAuth 2.0 authorization code.
state — A value used to test for possible CSRF attacks.
*/
//TODO: validate state here to secure against CSRF
var error = req.query.error;
var error_description = req.query.error_description;
var state = req.query.state;
var code = req.query.code;
if (error) {
next(new Error(error));
}
/**
*
* The code is a value that you will exchange with LinkedIn for an actual OAuth 2.0 access
* token in the next step of the authentcation process. For security reasons, the authorization code
* has a very short lifespan and must be used within moments of receiving it - before it expires and
* you need to repeat all of the previous steps to request another.
*/
//once the code is received handshake back with linkedin to send over the secret key
handshake(req.query.code, res);
});
function handshake(code, ores) {
//set all required post parameters
var data = querystring.stringify({
grant_type: "authorization_code",
code: code,
redirect_uri: OauthParams.redirect_uri,//should match as in Linkedin application setup
client_id: OauthParams.client_id,
client_secret: OauthParams.client_secret// the secret
});
var options = {
host: 'www.linkedin.com',
path: '/oauth/v2/accessToken',
protocol: 'https:',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(data)
}
};
var req = http.request(options, function (res) {
var data = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
//once the access token is received store it
myToken = JSON.parse(data);
linkedin = Linkedin.init(myToken);
ores.redirect("/");
});
req.on('error', function (e) {
console.log("problem with request: " + e.message);
});
});
req.write(data);
req.end();
}
In my troubleshooting research, it seems I need to pass the token into the request; however, I can't find anywhere or any way to do so in the package. And with as many daily downloads as the package has, I can't possibly be the only one to experience this error. The author's Issues section of GitHub were unhelpful, as were other searches for this package's error.
My deployment: https://linkedin-api-test.herokuapp.com/
(When visiting the deployment, you must click the blue "Want to
connect to LinkedIn?" link prior to manually changing the uri
according to the routes. The results will also only display in the
Heroku logs, which is most likely largely unhelpful to you. It was
supposed to be a simple test, so I simply stole the front end from my
prior project.)
My Repo: https://github.com/SteveSonoa/LinkedIn-Test
node-linkedin Docs: https://github.com/ArkeologeN/node-linkedin/blob/master/README.md
This is my first question I haven't been able to find the answer to; I apologize if I left out anything important while asking. Thank you in advance for any help!
The solution was to pass the following token code into the linkedin variable instead of simply passing myToken:
linkedin = Linkedin.init(myToken.access_token || myToken.accessToken);
I don't understand the downvote, as no comments were left; I apologize if I left out important or generally expected information, as this was the first question I've asked. I want to make sure the solution is posted for anyone coming after me with the same issue. This issue is now solved.
I have a weird bug going on with my code.
I'm using the simple-oauth2 library (https://github.com/lelylan/simple-oauth2) and my code works fine on Windows.
When I try to run my code on a linux server (raspberry pi zero), the oauth library keeps on returning 404 Not Found for my oauth request (specifically "Access Token Error Not Found" as per the code below).
What's going on?
Code (working with Yelp API):
var fs = require('fs');
var cID = fs.readFileSync('blahblahblah', 'utf8');
var cSecret = fs.readFileSync('blahblahblah2', 'utf8');
var credentials = {
client: {
id: cID,
secret: cSecret
},
auth: {
tokenHost: 'https://api.yelp.com',
tokenPath: '/oauth2/token'
}
};
var oauth2 = require('simple-oauth2').create(credentials);
var tokenConfig = {};
module.exports.gimmeMuhToken = function(cb) {
oauth2.clientCredentials.getToken(tokenConfig, function(error, result) {
if (error) {
return console.log('Access Token Error', error.message);
}
cb(oauth2.accessToken.create(result).token.access_token); // Return the token
});
};
Thanks
Found the culprit.
It was line endings...
My setup consists of an AWS API Gateway with IAM access control and AWS cognito for log in.
I access the API already from an Android app and would now like to build a web app (angular2) to do the same.
On Android, I'm using the AWSCognitoCredentialsProvider to supply the API SDK with the required credential. (http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-generate-sdk.html)
Unfortunately I cannot figure how / if I can do that with the javascript SDK?
I have no trouble using cognito to log in and get the session ID, access token etc. However, the API SDK requires me to provide accessKey and secretKey.
Here's the relevant code snippet from the generated API SDK:
var authType = 'NONE';
if (sigV4ClientConfig.accessKey !== undefined && sigV4ClientConfig.accessKey !== '' && sigV4ClientConfig.secretKey !== undefined && sigV4ClientConfig.secretKey !== '') {
authType = 'AWS_IAM';
}
In other words, I have this part working (from some example code):
static authenticate(username:string, password:string, callback:CognitoCallback) {
AWSCognito.config.update({accessKeyId: 'anything', secretAccessKey: 'anything'})
let authenticationData = {
Username: username,
Password: password,
};
let authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
let userData = {
Username: username,
Pool: CognitoUtil.getUserPool()
};
console.log("Authenticating the user");
let cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
console.log(AWS.config);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
callback.cognitoCallback(null, result);
},
onFailure: function (err) {
callback.cognitoCallback(err.message, null);
},
});
}
and now I'd like to use this:
this.apigClient = apigClientFactory.newClient({
accessKey: "anything",
secretAccessKey: "anything",
sessionToken: "nothing",
region: 'eu-central-1'
How do I get accessKey, secretAccessKey and sessionToken out of my AWSCognito? I was unable to find any API for that so far...
Thank you Bob, for pointing me in the right direction! I've now figured it out and thus for completeness sake, here's the full solution to my problem:
From the service that creates the apigClient:
return CognitoUtil.getCredentials()
.then(() =>
this.apigClient = apigClientFactory.newClient({
accessKey: AWS.config.credentials.accessKeyId,
secretKey: AWS.config.credentials.secretAccessKey,
sessionToken: AWS.config.credentials.sessionToken,
region: 'eu-central-1'}));
The getCredentials() method, which is key to get the required temporary credentials:
public static getCredentials():Promise{
return new Promise((resolve, reject) => {
CognitoUtil.getIdToken({
callback() {
},
callbackWithParam(idTokenJwt:any) {
let url = 'cognito-idp.' + CognitoUtil._REGION.toLowerCase() + '.amazonaws.com/' + CognitoUtil._USER_POOL_ID;
let logins = {};
logins[url] = idTokenJwt;
let params = {
IdentityPoolId: CognitoUtil._IDENTITY_POOL_ID, /* required */
Logins: logins
};
AWS.config.region = CognitoUtil._REGION;
AWS.config.credentials = new AWS.CognitoIdentityCredentials(params);
AWS.config.credentials.refresh(result => {
console.log(AWS.config.credentials);
resolve();
});
}
});
});
}
So the key insight here was, that
I authenticate to the user pool (shown in my question)
I use that with an identity provider to retrieve temporary credentials (getCredentials)
I use the temporary credentials out of AWS.config.credentials to setup the apigClient
I hope this is helpful to someone else as well. Certainly the code that I just posted probably could use some refactoring, so any comments on that are very welcome!
Cognito is actually made of 3 different services:
Cognito Your User Pools - What you've integrated here
Cognito Sync - For syncing user preference data for users
Cognito Federated Identity - For federating identities (FB, Google or User Pools) into your account and generating credentials.
What the API Gateway client is expecting is credentials that come from Cognito Federated Identity.
See the Cognito documentation for integrating your user pool with Cognito Federated Identity.
I've created a Cognito User Pool. I can list the users and add the users using the AWSCognitoIdentityProviderClient from the Java AWS SDK.
However, I have a custom login page and I wish to take the entered username and password and authenticate against my User Pool. I don't see anywhere in the Java AWS SDK where I can pass credentials and get an authentication result from.
Edit: I can't get past this error:
NotAuthorizedException: Missing credentials in config
Relevant code:
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:087a3210-64f8-4dae-9e3c...' // your identity pool id here
});
AWSCognito.config.region = 'us-east-1';
AWSCognito.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:087a3210-64f8-4dae-9e3c...' // your identity pool id here
});
var poolData = {
UserPoolId: 'us-east-1_39RP...',
ClientId: 'ttsj9j5...',
ClientSecret: 'bkvkj9r8kl2ujrlu41c7krsb6r7nub2kb260gj3mgi...'
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
var authenticationData = {
Username: 'test#foo.com',
Password: 'foobarfoo',
};
var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
var userData = {
Username: 'test#foo.com',
Pool: userPool
};
var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
console.log('access token + ' + result.getAccessToken().getJwtToken());
},
onFailure: function (err) {
alert(err);
},
});
The AWS Java SDK includes APIs to authenticate users in a User Pool. You can authenticate a user using either the InitiateAuth api or AdminInitiateAuth api of the AWSCognitoIdentityProviderClient class. The difference between these two API is explained in the documentation. In short, for InitiateAuth, you need to perform SRP calculations and then pass it to the API, while in AdminInitiateAuth you can directly pass the username and password. You can read about the security implications in both cases and decide which one to use.
Documentation :
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html
API reference:
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html
My working sample(Groovy):
def login() {
AWSCognitoIdentityProviderClient client = new AWSCognitoIdentityProviderClient()
println("Provider client: " + client)
client.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1))
HashMap authParams = new HashMap<>()
authParams.put("USERNAME", "User1")
authParams.put("PASSWORD", "a*123")
AdminInitiateAuthRequest adminInitiateAuthRequest = new AdminInitiateAuthRequest()
.withClientId(<YOUR_CLIENT_ID>)
.withUserPoolId(<YOUR_USER_POOL_ID>)
.withAuthFlow(AuthFlowType.ADMIN_NO_SRP_AUTH )
.withAuthParameters(authParams)
AdminInitiateAuthResult result = client.adminInitiateAuth(adminInitiateAuthRequest);
if (result != null) {
System.out.println("AdminInitiateAuthResult:");
System.out.println(result.toString());
} else {
System.out.println("No result available");
return;
}
}
Authentication is only supported via JavaScript, iOS and Android at this time. The necessary apis to authenticate are not part of the server SDKs (java, python et. all) during the beta. Using the JavaScript SDK is the recommended way of authenticating from your login page.
check here https://github.com/aws/amazon-cognito-identity-js
there is a missing line of code
This page http://docs.aws.amazon.com/cognito/latest/developerguide/using-amazon-cognito-user-identity-pools-javascript-examples.html is not updated
// Need to provide placeholder keys unless unauthorised user access is enabled for user pool
AWSCognito.config.update({accessKeyId: 'anything', secretAccessKey: 'anything'})
After including this I stopped having this error.
I'm creating an HTML 5 client to app services, however our app services are enterprise so behind an apigee gateway proxy ( not directly through api.usergrid.com).
I'm initializing like this:
$(function() {
var client = new Apigee.Client({
orgName:'myorg',
appName:'sandbox',
monitoringEnabled:false,
URI:'https://prod.OURURL.com/appservices/v1'
});
var username = "myusername";
var password = "mypass";
client.login(username, password,
function (err) {
if (err) {
console.log('There was an error logging you in.');
} else {
//login succeeded
client.getLoggedInUser(function(err, data, user) {
if(err) {
//error - could not get logged in user
console.log("error on lvl2");
} else {
if (client.isLoggedIn()){
appUser = user;
console.log('data')
// showFullFeed();
}
}
});
}
}
);
});
I'm immediately getting:
Error: Apigee APM configuration unavailable.
and then of course:
There was an error logging you in.
using the trace tool in the proxy I can see this errorr on the request to /proxy_path/org/app/apm/apigeeMobileConfig
{"timestamp":"1398263318219","duration":"0","error":"illegal_argument","exception":"java.lang.IllegalArgumentException","error_description":"JSON source MUST not be null"}
of course this is all called by the above code.
thank you in advance.
[EDIT FOR MORE INFORMATION]
Just tested with my own private org, so not setting the options.URI param, the second log message is normal as I had not created the app user, however the initialization is NOT working on the enterprise org, so this:
var client = new Apigee.Client({
orgName:'myorg',
appName:'sandbox',
monitoringEnabled:false,
URI:'https://prod.OURURL.com/appservices/v1'
});
is returning the APM error.
It seems you need to enable some of the options in the app services app ( inthe configuration option) for this api call to return something, thus enabling the sdk.