How to authenticate with a Facebook token? - feathersjs

I'm POST'ing to http://localhost:3030/authentication and trying to retrieve a JWT and create a user model using Facebook oAuth. My client side is React and seperate to the API.
My body:
{
"strategy": "facebook",
"accessToken": "EAALOM2rXQ50BAL5vERqa6YTJzyKZAeG4Yd9ZBPuqHfRmFzOpsQiTHEc1uS1sBaot7V9F7JlufpAWqqJoHIG8RCghLdBIKssKRyQqMLxiHvCPTjVDXqaR1rM4FhEXk55nFU0ZBZBP2KNVOoDNAGUBtJAOKaUdbeszLE0gXxgoF0DWgZBsRfVsZBFRBenQLMZBwZCDPIF606aHrA0CdDrcTRqSbcJWZCSlYIMwZD",
"facebookId": "10155772119707013",
"email": "joshn#hotmail.com.au"
}
But I'm getting a HTML page response saying 'You are not logged in: You are not logged in. Please log in and try again.'
Same issue # https://github.com/feathersjs/authentication-oauth2/issues/22 if anyone has figured out a solution to this.

This is possible with https://github.com/drudge/passport-facebook-token
My solution (inside authentication.js) is to extend a custom Passport strategy:
app.passport.use('facebook-token', new FacebookTokenStrategy({
clientID: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET
}, function (accessToken, refreshToken, profile, done) {
app.service('users').find({
query: {
facebookId: profile.id
}
}).then((userData) => {
if (userData.data.length > 0) {
return done(null, userData.data[0]);
} else {
app.service('users').create({}).then((data) => {
return done(null, data);
});
}
});
}
));

Related

Ionic 4 Using MySQL API Authentication Guard Not Working As Expected

i am required to make Register And Login process by connecting Ionic 4 to MySQL, the Login and Registration works, but i am having problem on configuring the guard to enable access based on user currently logged in, below is my code at tabs.router.module.ts which is the route for first loaded page after user logged in
{
path: 'profile-qr',
children: [
{
path: '',
loadChildren: () =>
import('../profile-qr/profile-qr.module').then(m => m.ProfileQRPageModule),
canActivate: [AuthGuard],
data: {
role: 'C'
}
}
]
},
below is my code to store login data in local storage during login process login.page.ts
async prosesLogin(){
if(this.loginForm.value.email != "" && this.loginForm.value.password != ""){
let body = {
email: this.loginForm.value.email,
password: this.loginForm.value.password,
action: 'login'
};
this.postPvdr.postData(body, 'user-api.php').subscribe(async data =>{
if(data.success){
this.storage.set('session_storage', data.result);
below is my code at AuthGuard auth.guard.ts
canActivate(route: ActivatedRouteSnapshot){
const expectedRole = route.data.role;
this.storage.get('session_storage').then((res)=>{
if (res == null){
this.router.navigate([`/home`]);
return false;
}else{
if (expectedRole == res.role) {
return true;
} else {
this.router.navigateByUrl('/login');
return false;
}
}
})
return false;
}
during login as customer#email.com which have a role of 'C' which is customer, i am unable to access any page which have set canActivate : [AuthGuard]
i have tried to copy other code style, which use Observable and Firebase, but i am unable to do so with MySQL because i do not really understand how to write Observable object.
i have checked on the mysql database and the user role are inserted correctly, there are no problem appear on my VSCode,
the problem are only at RBAC
kindly guide and explain on how to write code at auth.guard.ts

Update subscription Braintree and prorateCharges Error ID already taken

Hey everyone so I am trying to update a monthly subscription to another monthly subscription in Braintree and prorate the charges. After reading their documentation I am stumped on how to do this effectively. When I go to update the subscription I get the following error message: 'ID has already been taken.'
router.put("/update-subscription", async (req, res, next) => {
try {
console.log("hit route");
if (!res.locals.user) {
throw { status: 403, message: "Not logged in." };
} else {
const { subscriptionId, selectedPlanName } = req.body;
const oldSubscriptionId = subscriptionId;
const selectedPlanId = selectedPlanName.replace(/\s/g, "_");
const userId = res.locals.user.id;
const [[userData]] = await database.query("call getUserByUserId(?)", [
userId
]);
const { braintreeId } = userData;
const { paymentMethods } = await gateway.customer.find("" + braintreeId);
const { token } = paymentMethods.find(p => p.default);
console.log("oldSubscriptionId", oldSubscriptionId);
console.log("selectedPlanId", selectedPlanId);
const subUpdateResponse = await gateway.subscription.update(
oldSubscriptionId,
{
id: selectedPlanId,
paymentMethodToken: token,
options: {
prorateCharges: true
}
}
);
console.log("subUpdateResponse", subUpdateResponse);
if (subUpdateResponse.success) {
res.send("Successfully updated plan");
} else {
throw { message: "An error occurred." };
}
}
} catch (error) {
next(error);
}
});
Heres the Log
subUpdateResponse ErrorResponse {
errors:
ValidationErrorsCollection {
validationErrors: {},
errorCollections: { subscription: [Object] } },
params:
{ id: 'SILVER_MONTHLY',
paymentMethodToken: 'krs2p5',
options: { prorateCharges: 'true' } },
message: 'ID has already been taken.',
success: false }
{ message: 'An error occurred.' }
I understand that the 'SILVER_MONTHLY' ID is already used I mean I am trying to update from one subscription to the other obviously the one I am trying to update to has already been used. Again all I am trying to do is update from the subscription the user is already on to the subscription the user picked to update to. Any help here would be great. Thanks
Full disclosure, I work at Braintree. If you have any further questions, I recommend contacting Support
You are passing the plan ID in the incorrect parameter. The id parameter can be used for a new subscription ID that you'd like to have. To update to a different plan, you'll need to pass a planId parameter, which represents the plan you'd like to update them to.
I also noticed you are passing a paymentMethodToken parameter. This is to be used only if you're updating the payment method token. If that's what you intended, carry on! Otherwise, you do not need to pass this parameter in your update request.
As an example, if you wanted to update the plan and keep the same payment method token, your request may look something like this:
const subUpdateResponse = await gateway.subscription.update(
oldSubscriptionId,
{
planId: selectedPlanId,
options: {
prorateCharges: true
}
}
);

Error: No handler for requested intent at WebhookClient.handleRequest

Default intent calling a cloud function gives error
Error: No handler for requested intent
at WebhookClient.handleRequest (/user_code/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:287:29)
at exports.dialogflowFirebaseFulfillment.functions.https.onRequest (/user_code/index.js:73:11)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /var/tmp/worker/worker.js:783:7
at /var/tmp/worker/worker.js:766:11
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
as my webresponse in diagnostic info log shows this.
{
"responseId": "86043a10-8bc2-4ee7-8e8b-1e997289ad7c",
"queryResult": {
"queryText": "hi",
"action": "input.welcome",
"parameters": {},
"allRequiredParamsPresent": true,
"fulfillmentText": "Hi. Am Uma. Kindly let me know your experience facing an issue.",
"fulfillmentMessages": [
{
"text": {
"text": [
"Hi. Am Uma and welcome to support. Kindly let me know your experience facing an issue."
]
}
}
],
"outputContexts": [
{
"name": "projects/handymanticketagent/agent/sessions/e416a522-da87-ebd1-348e-9fdea1efbf65/contexts/defaultwelcomeintent-followup",
"lifespanCount": 2
}
],
"intent": {
"name": "projects/handymanticketagent/agent/intents/c58f706f-6cb6-499d-9ce2-459e8054ddc1",
"displayName": "Default Welcome Intent"
},
"intentDetectionConfidence": 1,
"diagnosticInfo": {
"webhook_latency_ms": 10001
},
"languageCode": "en"
},
"webhookStatus": {
"code": 4,
"message": "Webhook call failed. Error: Request timeout."
}
}
Based on the stack overflow answers here, Have added an intent mapped to function but am still getting error and could progress further. Where and how the cloud function console says am missing a handler for my request?
Update : As #prisoner said, including my cloud function code.
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const { WebhookClient } = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:*'; // enables lib debugging statements
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
console.log(request.body.queryResult.fulfillmentText);
console.log(request);
console.log(response);
const agent = new WebhookClient({ request, response });
console.log(agent);
function writeToDb(agent) {
// Get parameter from Dialogflow with the string to add to the database
const databaseEntry = agent.parameters.databaseEntry;
console.log(databaseEntry);
// Get the database collection 'dialogflow' and document 'agent' and store
// the document {entry: "<value of database entry>"} in the 'agent' document
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
console.log(dialogflowAgentRef);
return db.runTransaction(t => {
t.set(dialogflowAgentRef, { entry: databaseEntry });
console.log(Promise.resolve('Write complete'));
return Promise.resolve('Write complete');
}).then(doc => {
agent.add('Wrote "${databaseEntry}" to the Firestore database.');
return null;
}).catch(err => {
if (err) {
console.log(err.stack);
}
console.log('Error writing to Firestore: ${err}');
agent.add('Failed to write "${databaseEntry}" to the Firestore database.');
});
}
function readFromDb(agent) {
console.log(agent);
// Get the database collection 'dialogflow' and document 'agent'
const dialogflowAgentDoc = db.collection('dialogflow').doc('agent');
console.log(dialogflowAgentDoc);
// Get the value of 'entry' in the document and send it to the user
return dialogflowAgentDoc.get()
.then(doc => {
if (!doc.exists) {
agent.add('No data found in the database!');
} else {
agent.add(doc.data().entry);
}
return Promise.resolve('Read complete');
}).catch(() => {
agent.add('Error reading entry from the Firestore database.');
agent.add('Please add a entry to the database first by saying, "Write <your phrase> to the database"');
});
}
function defaultwelcomeintent_function(agent) {
console.log(agent);
}
// Map from Dialogflow intent names to functions to be run when the intent is matched
let intentMap = new Map();
intentMap.set('defaultwelcomeintent-followup', defaultwelcomeintent_function);
intentMap.set('ReadFromFirestore', readFromDb);
intentMap.set('WriteToFirestore', writeToDb);
console.log(intentMap);
agent.handleRequest(intentMap);
});
The diagnostic info says that the intent's display name for that fulfillment is "Default Welcome Intent":
"intent": {
"name": "projects/handymanticketagent/agent/intents/c58f706f-6cb6-499d-9ce2-459e8054ddc1",
"displayName": "Default Welcome Intent"
},
So you'd need to create a mapping for it like this:
intentMap.set('Default Welcome Intent', defaultwelcomeintent_function);
Where defaultwelcomeintent_function is the handler you have defined within your cloud function.
I had the same issue with the exact error from Dialogflow : Error: No handler for requested intent, in my case I'm using async/await in order to make synchronous calls through a cloud function in dialogflow fulfillement.
I noticed that in one of my main function mapped to an agent, I wasn't returning anything. Since the function was using async I added a return statment with the promise that I was waiting for at the beggining.
async function getInfo(agent) {
var hh = await getUserInfos(request.body.originalDetectIntentRequest.payload.uuid);
// Do what you want here
var yy = hh.aa[0].zz.yy;
agent.setFollowupEvent({ "name": "xxx", "parameters": { "xxx": yy } });
// Return your promise
return hh;
}

check the json data for comparing in extjs

I created a simple login page using extjs MVC to understand MVC architecture of extjs. As you can see below, I am trying to get the json data into the store and then I will check each username and password in that data with the entered login credentials. The thing in which I am confused right now is that, how to check the username and password from the retrieved json data present in store folder into the view folder? (Below code is only the related code with the problem)
I aware that this could invoke security threats, as I am checking on client side.
'view' folder --> Code.js
function checkJson(username, password){
//if matched, return true.
//else, return false.
}
'model' folder --> Code.js
Ext.define('AM.model.User', {
extend: 'Ext.data.Model',
fields: ['name', 'email']
});
'store' folder --> Code.js
Ext.define('LoginPage.store.Code', {
extend: 'Ext.data.Store',
model: 'LoginPage.model.Code',
autoLoad: true,
proxy: {
type: 'ajax',
api: {
read: 'data/loginResponse.json',
update: 'data/checkCredentials.json' //Contains: {"success": true}
},
reader: {
type: 'json',
root: 'loginResponse',
successProperty: 'success'
}
}
});
loginResponse.json
{
"form": {
"login": [
{
"username": "venkat",
"password": "123"
},
{
"username": "admin",
"password": "345"
}
]
}
You should put your checking part of the code to the Controller (views are for presentation). In view define some form with login and password fields. In Controller catch click event on form OK (Login) button, get form values (login + password), then use Ext.data.Store.query() method to find wether credentials fits or not like:
Look here for examples how to use controllers in MVC to catch events;
In your Controller put:
init: function() {
this.control({
'#form_ok_button': { // this is the `id` property of your form's Login button
click: function(button) {
var fValues = button.up('form').getValues(); // Assume your button is bound to the form
// Or you can use `Controller.refs` property (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.app.Controller-cfg-refs) to get form
var matched = store.query('username', fValues.username);
if(matched.length && matched[0].get('password') === fValues.password) {
// login OK!
}
}
}
});
},
How to use refs (in Controller):
refs: [
{ ref: 'usernameField', selector: '#username_field' }, // username field id is "username_field"
{ ref: 'passwordField', selector: '#password_field' }, // password field id is "password_field"
],
init: function() {
this.control({
'#form_ok_button': {
click: function() {
// with `refs` autogetters are created for every `ref`:
var username_field = this.getUsernameField();
var password_field = this.getPasswordField();
}
}
})
}
You can read about referencing here.
For every Store in Ext.app.Controller.stores array autogetters are created too (in your case for Code store use this.getCodeStore() inside controller).
Here is the flow:
You get username and password field values with this.getUsernameField() and this.getPasswordField();
You query() store for username
If username exist in store, you check if password fits.

Get userID with the new JS SDK

how would you do something like:
strUserID = FB.getSession().uid;
with the new JS SDK?
simple call to get the users id after logged in?
REF: http://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/
FB.getLoginStatus(function(response) {
if (response.authResponse) {
// logged in and connected user, someone you know
} else {
// no user session available, someone you dont know
}
});
Response:
{
status: 'connected',
authResponse: {
accessToken: '...',
expiresIn:'...',
signedRequest:'...',
userID:'...'
}
}