I'm using
accounts-password
accounts-facebook
service-configuration
On the server:
ServiceConfiguration.configurations.remove({
service: 'facebook'
});
ServiceConfiguration.configurations.upsert(
{ service: 'facebook' },
{ $set: {
appId: 'xxxxxxxxxxxxxxxx',
secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}
}
);
On the client:
Meteor.loginWithFacebook({requestPermissions: ['email']}, function(error){
if (error) {
throwError('Could not log in');
} else {
// success
}
});
This configuration prompts the user for Facebook verification with access to email and returns no errors. A new user is stores with the correct name and ID. But this e-mail is not stored in the user object.
This is what I get when i fetch a user from the shell.
{ _id: 'xxxxxxxxxxxxxxxxx',
createdAt: Mon Jul 13 2015 13:36:21 GMT+0200 (CEST),
services:
{ facebook:
{ accessToken: 'xxxxxxxxxxxxxxxxxxxxx...',
expiresAt: 1441971380621,
id: 'xxxxxxxxxxxxxxxxx',
name: 'xxxx xxxxxx' },
resume: { loginTokens: [Object] } },
profile: { name: 'xxxx xxxxxx' } }
Why is the email address from Facebook not being stored?
While I have reported the issue to Meteor I've found a quick fix for the time being.
On the server run this:
Accounts.onCreateUser(function(options, user) {
if (user.hasOwnProperty('services') && user.services.hasOwnProperty('facebook') ) {
var fb = user.services.facebook;
var result = Meteor.http.get('https://graph.facebook.com/v2.4/' + fb.id + '?access_token=' + fb.accessToken + '&fields=name,email');
if (!result.error) {
_.extend(user, {
"emails": [{"address": result.data.email, "verified": false}],
"profile": {"name": result.data.name}
});
}
}
return user;
});
[EDIT]
The previous code works, but since it causes problems with other login methods I went with another approach:
In the client I call a function on the server when the user authenticates with Facebook:
Meteor.loginWithFacebook({requestPermissions: ['email']}, function(error){
if (error) {
//error
} else {
Meteor.call('fbAddEmail');
}
});
And then on the server:
Meteor.startup(function () {
Meteor.methods({
fbAddEmail: function() {
var user = Meteor.user();
if (user.hasOwnProperty('services') && user.services.hasOwnProperty('facebook') ) {
var fb = user.services.facebook;
var result = Meteor.http.get('https://graph.facebook.com/v2.4/' + fb.id + '?access_token=' + fb.accessToken + '&fields=name,email');
if (!result.error) {
Meteor.users.update({_id: user._id}, {
$addToSet: { "emails": {
'address': result.data.email,
'verified': false
}}
});
}
}
}
});
});
Facebook API may not return the email address for some users even if you asked for the "email" permission. The official API docs state that:
[email] field will not be returned if no valid email address is available.
One of the reason may be an unconfirmed email address and another one a user who registered with a mobile phone number only.
Related
I want Auth0 to send some additional info in the user profile. So I created the following rule:
function (user, context, callback) {
user.app_metadata = user.app_metadata || {};
user.app_metadata.test = "some info here";
auth0.users.updateAppMetadata(user.user_id, user.app_metadata)
.then(function() {
context.idToken['https://example.com/test'] = user.app_metadata.test;
callback(null, user, context);
})
.catch(function(err) {
callback(err);
});
}
However, instead of receiving this (which I expected):
{
user_metadata: {
test: "some customer id"
}
nickname: "afaafa11fdf"
name: "afaafa11fdf#bob.com"
}
I receive this:
{
https://example.com/test: "some customer id"
nickname: "afaafa11fdf"
name: "afaafa11fdf#bob.com"
}
I have been following these guidelines here.
I contacted Auth0 and apparently that's the desired behaviour. I expected the wrong result, but what I describe above and did in fact receive is correct. So for anyone with this question, you will in the end receive something along these lines:
{
https://example.com/test: "some customer id"
nickname: "afaafa11fdf"
name: "afaafa11fdf#bob.com"
}
My problem today is that I have a web application with an express checkout to execute.
I used the Client - Server architecture to avoid security issues.
So my client code is the following:
paypal.Button.render({
env : 'sandbox',
commit: true,
style: {
size: 'medium',
color: 'gold',
shape: 'pill',
label: 'checkout'
},
locale: 'en_US',
payment: function() {
nickname = $("#nickname").val();
amount = $("#amount").val();
description = $("#description").val();
data = {
"nickname" : nickname,
"amount" : amount,
"description" : description
};
return new paypal.Promise(function(resolve, reject) {
// Call your server side to get the Payment ID from step 3, then pass it to the resolve callback
jQuery.post("/newPayment", data).done(function(data){
console.log("HEI I GOT THE PAYMENT JSON = " + data);
parsed_data = JSON.parse(data);
resolve(parsed_data['id']);
});
});
},
onAuthorize: function(data, actions) {
console.log("JSON = " + JSON.stringify(actions.payment.getTransactions()[0]));
console.log("TRANSACTION = " + actions.payment.getTransactions()[0])
console.log("PAYMENT SUCCESSFUL");
return actions.payment.execute();
},
onError: function(data, actions){
console.log("ERRORRRRRR");
$("#warning").show();
}
}, '#paypal-button');
My server side code:
app.post("/newPayment",function(req,res){
console.log("RECEIVING POST WITH AMOUNT = " + req.body.amount);
//CONFIGURE PAYMENY - PAYPAL PHASE 1
var first_config = {
'mode': 'sandbox',
'client_id': '<MY CLIENT ID>',
'client_secret': '<MY SECRET>'
};
paypal.configure(first_config);
console.log("AMOUNT AUTHORIZED = " + req.body.amount);
//CREATING PAYMENT
PAYMENT = {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
"return_url": "http://return.url",
"cancel_url": "http://cancel.url"
},
"transactions": [{
"amount": {
"currency": "EUR",
"total": req.body.amount
},
"description": "This is the payment description."
}]
};
//CREATING PAYMENT AND SENDING IT TO THE CLIENT
paypal.payment.create(PAYMENT, function (error, payment) {
if (error) {
throw error;
} else {
console.log("Create Payment Response");
res.send(JSON.stringify(payment));
}
});
Now, the paypal window opens and I can insert all my data to execute a test payment.
But when I confirm payment and Paypal service should call my "onAuthorize" method, instead methon "onError" fires...
What could be the problem?
Redirect URLS?
The fact that I should execute the paypal.configure() with a .then() after it to ensure the flow of actions?
I'm really exploding trying to use Paypal services
EDIT:
Pushing my code on cloudno.de the payment is executed correctly, but running it locally it doesn't work... I don't know what to say ahah
actions.payment.getTransactions is not a function. You need to call actions.payment.get().then(function(result) { ... })
I’m using mean.js to let registered users access content. It’s sort of working. I can change isAllowed to !isAllowed to let people see the content. The problem is that content is not authorized when the user logs in. The articles example works fine. But when I create my own section, logged in users can’t access pages!
So basically if I log in, I get message: 'User is not authorized' if I try going to localhost:3000/requestoffwork
If I log in and change isAllowed to !isAllowed, I can access it
'use strict';
/**
* Module dependencies.
*/
var acl = require('acl');
// Using the memory backend
acl = new acl(new acl.memoryBackend());
/**
* Invoke Articles Permissions
*/
exports.invokeRolesPolicies = function () {
acl.allow([{
roles: ['admin'],
allows: [{
resources: '/api/articles',
permissions: '*'
}, {
resources: '/api/articles/:articleId',
permissions: '*'
}]
}, {
roles: ['user'],
allows: [{
resources: '/requestoffwork',
permissions: '*'
}, {
resources: '/api/articles/:articleId',
permissions: ['get']
}]
}, {
roles: ['guest'],
allows: [{
resources: '/api/articles',
permissions: ['get']
}, {
resources: '/api/articles/:articleId',
permissions: ['get']
}]
}]);
};
/**
* Check If Articles Policy Allows
*/
exports.isAllowed = function (req, res, next) {
var roles = (req.user) ? req.user.roles : ['guest'];
// If an article is being processed and the current user created it then allow any manipulation
if (req.article && req.user && req.article.user.id === req.user.id) {
return next();
}
// Check for user roles
acl.areAnyRolesAllowed(roles, req.route.path, req.method.toLowerCase(), function (err, isAllowed) {
if (err) {
// An authorization error occurred.
return res.status(500).send('Unexpected authorization error');
} else {
if (isAllowed) {
// Access granted! Invoke next middleware
return next();
} else {
return res.status(403).json({
message: 'User is not authorized'
});
}
}
});
};
This is the route
app.route('/requestoffwork').all(managementPolicy.isAllowed)
.get(management.list)
.post(management.submit);
And here's the data for the user
{"_id":"5788fe46587a1c0b07a04078","displayName":"","provider":"local","__v":0,"created":"2016-07-15T15:16:22.625Z","roles":["user"],"profileImageURL":"modules/users/client/img/profile/default.png","email":"email#gmail.com","lastName":"","firstName":”"}
Did you add the permissions to the client side routes ass well ?
In modules/youModule/client/config/youModule.client.routes.js add this:
function routeConfig($stateProvider) {
$stateProvider
.state('yourState', {
abstract: true,
url: '/requestoffwork',
template: '<ui-view/>',
data: {
roles: ['user'], //here you must specify the roles as well
pageTitle: 'requestoffwork'
}
})
}
Hope this helps.
I am trying to authenticate a user with github, then pass their avatar_url to the client. Simplified structure looks as follows.
server/
publications.js
client/
users/
login.js
main.js
In my client/users/login.js file, I try to get the permission to the user Object which contains the avatar url
Accounts.ui.config({
requestPermissions: {
github: ['user']
}
});
Then in my server/publications.js, I try to publish the data related to the avatar url.
Meteor.publish('userData', function() {
if(this.userId) {
return Meteor.users.find(
{ _id: this.userId }, {
fields: {
'services.github.id': 1,
'services.github.user.avatar_url': 1
}
})
} else {
this.ready();
}
});
However I never get the data related to the github user when I get my user object. How can I get access to the user with OAuth?
Please have a look at this sample code, do you capture the Github profile data onCreateUser?
EDIT: this is server side code, e.g. server/accounts.js
Accounts.onCreateUser(function (options, user) {
var accessToken = user.services.github.accessToken,
result,
profile;
result = Meteor.http.get("https://api.github.com/user", {
params: {
access_token: accessToken
}
});
if (result.error)
throw result.error;
profile = _.pick(result.data,
"login",
"name",
"avatar_url",
"url",
"company",
"blog",
"location",
"email",
"bio",
"html_url");
user.profile = profile;
return user;
});
Code found here
Can someone please provide the correct method to send an email verification upon user creation? This is the important part...
a) I would like the user to have immediate access upon signing up. But if the user has not yet clicked clicked on the verification link within 48 hours, I would like to deny them logging in until they have clicked on the link.
My code so far sends an email verification but the user has continuos access to the application with or without clicking on the verification link (so my code is of course incomplete).
client.js
Template.join.events({
'submit #join-form': function(e,t){
e.preventDefault();
var firstName= t.find('#join-firstName').value,
lastName= t.find('#join-lastName').value,
email = t.find('#join-email').value,
password = t.find('#join-password').value,
username = firstName.substring(0) + '.' + lastName.substring(0),
profile = {
fullname: firstName + ' ' + lastName
};
Accounts.createUser({
email: email,
username: username,
password: password,
userType: // 'reader' or 'publisher'
createdAt: new Date(),
profile: profile
}, function(error) {
if (error) {
alert(error);
} else {
Router.go('home');
}
});
}
});
server.js
Meteor.startup(function () {
process.env.MAIL_URL = 'smtp://postmaster.....';
Accounts.emailTemplates.from = "no-reply#mydomain.com";
Accounts.emailTemplates.sitename = "My SIte Name";
Accounts.emailTemplates.verifyEmail.subject = function(user) {
return 'Please confirm tour Email address' ;
},
Accounts.emailTemplates.verifyEmail.text = function(user, url) {
return 'Click on the link below to verify your address: ' + url;
}
Accounts.config({
sendVerificationEmail: true
});
My attempt have been made through own readings on meteor docs and looking at other code on SO. I am stuck guys. Thanks for the support.
I think the basic idea is to have some validation code eg in Accounts.validateLoginAttempt which you want to check every time before user logs in. What you can do is to store the date&time when user signs up in user.profile.joinDate. If a user tries to login
Check if the email address has been verified or
check if the user is logging within the grace period of 48 hrs
isWithinGracePeriod = function(user) {
** TBD returning true or false.
This can be tricky when you
have multiple instances in
different time-zones.
** }
and
Accounts.validateLoginAttempt(function(attempt){
if (attempt.user && attempt.user.emails && !attempt.user.emails[0].verified ) {
console.log('No verification action received yet.');
return isWithinGracePeriod(attempt.user);
}
return true;
});
Further, here is the HTML/spacebars stuff:
<body>
{{ > start }}
</body>
<template name="start">
{{#if currentUser}}{{>showUserProfile}}{{else}}{{> login}}{{/if}}
</template>
<template name="login">
## Grab username/password here
</template>
If the login template is created, we can try to capture the verification code after the user clicked the verification link. Note that, if no user is logged in, then login will be rendered, so we attach to login via
Template.login.created = function() {
if (Accounts._verifyEmailToken) {
Accounts.verifyEmail(Accounts._verifyEmailToken, function(err) {
if (err != null) {
if (err.message = 'Verify email link expired [403]') {
var message ='Sorry this verification link has expired.';
console.log(message);
alertBox = Blaze.renderWithData(Template.Alert, {message: message}, $("body").get(0));
}
} else {
var message = "Thank you! Your email address has been confirmed.";
console.log(message);
alertBox = Blaze.renderWithData(Template.Alert, {message: message}, $("body").get(0));
}
});
}
};
The verification link is send in "hook" to Accounts.createUser:
Accounts.onCreateUser(function(options, user) {
user.profile = {};
Meteor.setTimeout(function() {
Accounts.sendVerificationEmail(user._id);
}, 2 * 3000);
return user;
});