Multiple required auth strategies for hapi.js? - facebook

I have a hapi server that saves login credentials to a session cookie using the node module 'hapi-auth-cookie'. I'm using 'bell' to allow certain features to be authenticated with Facebook.
In the handler for the Facebook authentication, how do I access session info from the session cookie while still being able to access information bell provides me from Facebook?

there's an issue within the bell repository with a proposed solution to use server.auth.test(). Like this:
request.server.auth.test('strategy-name', request, (err, credentials) => {
if (err) {
// tested strategy didn't find a user
return reply({ error: 'Cannot find your credentials' })
}
//there is a user :)
return reply({ status: true, user: credentials.name })
})
Hope that helps and gives a direction :)

Related

Are IBM Watson IAM tokens good for all services or specific to each service, e.g., Speech-to-Text?

IBM's documentation says that the following Node back end code enables you to Use the API key to have the SDK manage the lifecycle of the token. The SDK requests an access token, ensures that the access token is valid, and refreshes it if necessary.
const SpeechToTextV1 = require('ibm-watson/speech-to-text/v1');
const { IamAuthenticator } = require('ibm-watson/auth');
const speechToText = new SpeechToTextV1({
authenticator: new IamAuthenticator({
apikey: '{apikey}',
}),
url: '{url}',
});
How do I get the token from speechToText to pass to my front end Angular app running in the browser? I tried calling the method getToken to get the token:
const SpeechToTextV1 = require('ibm-watson/speech-to-text/v1');
const { IamAuthenticator } = require('ibm-watson/auth');
const speechToText = new SpeechToTextV1({
authenticator: new IamAuthenticator({
apikey: 'my-api-key',
}),
url: 'my-url',
});
speechToText.getToken(function (err, token) {
if (!token) {
console.log('error: ', err);
} else {
console.log(token);
// do more stuff with the token
}
});
That didn't work. The error message is speechToText.getToken is not a function. Should I try speechToText.authenticator.getToken?
I tried getting the token from ibm-watson/sdk instead of from ibm-watson/speech-to-text/v1?
const watson = require('ibm-watson/sdk');
const { IamAuthenticator } = require('ibm-watson/auth');
const authorization = new watson.AuthorizationV1({
authenticator: new IamAuthenticator({ apikey: 'my-api-key' }),
url: 'my-url'
});
authorization.getToken(function (err, token) {
if (!token) {
console.log('error: ', err);
} else {
console.log(token);
// do stuff with token
}
});
That gets a smokin' new token. But the token doesn't work. When I run WatsonSpeech.SpeechToText.recognizeMicrophone I get an error message HTTP Authentication failed; no valid credentials available.
It appears that each IBM Watson service needs its own token, created with a service-specific URL. I put the Speech-to-Text URL into ibm-watson/sdk so I should get the right token. I don't see why the token isn't working.
Take a look at the supplying credentials section of the README in the Node SDK about managing the token yourself if that's what you want to do:
Use the BearerTokenAuthenticator if you want to manage the lifecycle
yourself. For details, see Authenticating to Watson services. If you want
to switch your authenticator, you must override the authenticator
property directly.
There's a link from that "Authenticating" topic that might help you understand the access process. See Invoking IBM Cloud service APIs
IBM Cloud uses what it calls Identity and Access Management (IAM) to manage access to resources. IAM has several concepts which allow for fine-grained security control. You can grant scoped access privileges to users or roles. Thus, one user may be manager for a resource, another user only reader.
Now, to access a service like the IAM-controlled Watson services, your username / password or API key is turned into a Bearer and a Refresh token, the Bearer token is only valid for a certain time and then needs a fresh Refresh token. This could be a reason why you see different tokens.
You may have seen the underlying core Node.js SDK which has background information on Authentication and some functions.
Long story short: When you have successfully created the IamAuthenticator, you should be able to request the token and use it. Even better, you can pass the IamAuthenticator to many services, including the Watson services, to initialize a session. The code "knows" how to obtain the authentication information and use it to authenticate for the other service.

How to send the Access Token in order to access AWS services - BEGINNER

I followed the following tutorial and got the facebook login working. At the end it prints out the accessToken which is great.
FB.login(function (response) {
// Check if the user logged in successfully.
if (response.authResponse) {
console.log('You are now logged in.');
// Add the Facebook access token to the Cognito credentials login map.
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'IDENTITY_POOL_ID',
Logins: {
'graph.facebook.com': response.authResponse.accessToken
}
});
// Obtain AWS credentials
AWS.config.credentials.get(function(){
// Access AWS resources here.
console.log('Access Token is '+ AWS.config.credentials.identityId);
var s3= new AWS.s3();
});
} else {
console.log('There was a problem logging you in.');
}
});
I believe that the following line of code Logins: {
'graph.facebook.com': response.authResponse.accessToken
} will register the accessToken in Cognito. Correct me if i am wrong.
My problem is, Should I save this accessToken and pass it when ever I am communicating with an AWS service (for example : DynamoDB write Item or else while adding a file to S3) ?
If so How can I do it ? (I have almost googled the entire web and found none on this)
** Note: I think the purpose of a accessToken is to add some security when the user request to access an AWS service. So in that case How can I use the accessToken to validate ?
Once you give it to Cognito in a call to get some credentials, Cognito will registered it to, and will give back credentials scoped to, that authenticated identity.
Those credentials alone will map back to that token, so all you need to give to other AWS clients when accessing them is the credentials. That being said, once those credentials have expired, you will need to have the token still handy to get more for that authenticated identity. Cognito requires at least one token linked to an authenticated identity to get credentials for it.

Read logged in User details from SSO server in Blue mix

I am working on Node.js application with Cloudant database. I was able to do IBM IDP authentication with SSO server on Blue mix via the SSO service.
My issue occurs after successful authentication, I am unable to get JSON object that can give me all the user attributes that I need, for example, is the logged in person a manager? if yes then his serial number, name etc
Does anyone know how to retrieve the information from IBM SSO service?
Kindly let me know as soon as possible.
You can check the request.user object returned after successful authentication. It returns some information about the logged in user, but each provider returns different data.
For example, for LinkedIn logged users it returns displayName, firstName, lastName and emailAddress.
The snippet code below prints the request.user JSON object in the application log, so you can see what is available and retrieve as needed.
app.get('/auth/sso/callback', function(req, res, next) {
var redirect_url = req.session.originalUrl;
passport.authenticate('openidconnect', {
successRedirect: '/hello',
failureRedirect: '/failure',
})(req,res,next);
});
app.get('/hello', ensureAuthenticated, function(request, response) {
response.send('Hello, '+ request.user['id'] + '!\n' + 'Log Out');
console.log(JSON.stringify(request.user));
});
After user logs in you can run:
cf logs <app-name> --recent
to see results from console.log code.

Meteor: Implement facebook package outside of accounts-facebook

I've got a Meteor application with a multi-phase sign-up process. The accounts are based on the accounts-password package. In the step prior to account creation, the user needs to provide some profile information.
I'd like the user to be able to launch a Facebook OAuth flow which pre-populates the profile fields with information pulled from Facebook.
This all needs to happen pre-account-creation. I want to implement this with the facebook package that backs accounts-facebook.
At the moment I've got the OAuth flow happening by calling Facebook.requestCredential, but I'm not sure how to get an OAuth access token from the credential token that comes back. I suspect I need to pass this to the server and make an API call to get back an access token.
Any pointers as to how this should work would be much appreciated.
Facebook.requestCredential(function (credentialTokenOrError) {
if (credentialTokenOrError && credentialTokenOrError instanceof Error) {
// Error...
console.log(credentialTokenOrError);
} else {
// Credential Token string
console.log(credentialTokenOrError);
// Now perhaps a Meteor.call to a server method that
// 1. Retrieves an access token
// 2. Hits the graph API to get profile information and returns it to the client
}
});
Thanks,
Chris
I was having the same trouble of converting a credentialToken to an accessToken, only with Github. I've written up a gist that has code that should work very similarly. Essentially, there are two steps:
Within your Facebook.requestCredential callback function, call OAuth._retrieveCredentialSecret(tokenOrError), the result of which is the credentialSecret. Then use Meteor.call, passing in tokenOrError and credentialSecret, to call the Meteor.method you'll set up in the next step.
code (on client):
Github.requestCredential({
loginStyle: 'popup',
requestPermissions: ['gist']
}, function(tokenOrError) {
if (tokenOrError && tokenOrError instanceof Error) {
// Throw a Meteor error
console.log('error getting the token');
return;
}
var credentialSecret = OAuth._retrieveCredentialSecret(tokenOrError);
Meteor.call('getGithubAccessToken', tokenOrError, credentialSecret, function(err, accessToken) {});
});
On the server, set up a Meteor.method that takes your credentialToken and credentialSecret and calls Facebook.retrieveCredential. This function returns a credentials object from the _pendingCredentials Mongo Collection before deleting it from the collection. The access token is credentials.serviceData.accessToken. The credentials object could potentially be persisted in the user object in the Meteor.users collection (as it is in the accounts packages) or sent back to the user.
code (on server):
Meteor.methods({
getGithubAccessToken: function(credentialToken, credentialSecret) {
var credentials = Github.retrieveCredential(credentialToken, credentialSecret);
console.log('accessToken:', credentials.serviceData.accessToken);
return credentials.serviceData.accessToken;
}
});
I'm unfamiliar with the specifics of Facebook's Graph API so after these steps, you're on your own. Good luck!

HWIOAuthBundle, how to manually authenticate User with a Facebook access token?

I have a website (Symfony2) with HWIOauthBundle used to connect with Facebook and everything works fine.
Now, I'm trying to build an iOS app with Cordova and Ionic framework (AngularJS) and I want to authenticate my user with Facebook :
With $cordovaFacebook, I authenticate my user and get a valid Facebook access token, that's ok
I try to use this access token to authenticate my user on the server-side with HWIOauthBundle :
GET http://..../login/facebook?code=MY_FACEBOOK_ACCESS_TOKEN
Symfony rejects my request with this log :
INFO - Matched route "facebook_login" (parameters: "_route": "facebook_login")
INFO - Authentication request failed: OAuth error: "Invalid verification code format."
So my question is : how can I authenticate my user on both front and back end with Facebook connect?
Thanks :)
I've also been wondering how to implement a server side login with the HWIOAuthBundle.
I didn't find any solution on the web, so I coded the functionnality based on hints I've read on the net.
Basically, you have to :
authenticate the user on your app
make an http request to your server with the Facebook token.
ont the server side, check if the token is for your Facebook app, and retrieve the user's Facebook ID.
Get your user from the DB based on the fetched ID.
Here's my Symfony controller:
public function getSecurityFbAction($token)
{
// Get the token's FB app info.
#$tokenAppResp = file_get_contents('https://graph.facebook.com/app/?access_token='.$token);
if (!$tokenAppResp) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Make sure it's the correct app.
$tokenApp = json_decode($tokenAppResp, true);
if (!$tokenApp || !isset($tokenApp['id']) || $tokenApp['id'] != $this->container->getParameter('oauth.facebook.id')) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Get the token's FB user info.
#$tokenUserResp = file_get_contents('https://graph.facebook.com/me/?access_token='.$token);
if (!$tokenUserResp) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Try to fetch user by it's token ID, create it otherwise.
$tokenUser = json_decode($tokenUserResp, true);
if (!$tokenUser || !isset($tokenUser['id'])) {
throw new AccessDeniedHttpException('Bad credentials.');
}
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->findUserBy(array('facebookId' => $tokenUser['id']));
if (!$user) {
// Create user and store its facebookID.
}
// Return the user's JSON web token for future app<->server communications.
}
I throw the Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException exceptions to handle login errors on my app.
Of course, you really should use https because you will be exchanging sensible information.
I don't know if it's the best way to do it but it works well.
Hope it helps !
Well, I think that Symfony doesn't actually reject your request. Facebook is. I'm not sure if this might help, but I know that a bunch a problems can happen when dealing with the Facebook Auth :
Do you know if the tool sends, along with the code parameter, a redirect_uri parameter ? If so :
Did you check that your redirect_uri HAS a trailing slash at the end ? See this
Silly question, but did you check that your app_id is the same when you got authorized via Cordova ?
Check that your redirect_uri DOES NOT have any query parameter.
Check that the redirect_uri that you use during the whole process is the same all the time.
Overall, it seems that your issue is almost all the time related to the redirect_uri URI format.