Meteor.user() on iron-router server side - meteor

How can check, on server side route, if user is logged?
I would add check on 'before', but Metor.user() don't work here.
thanks in advance.
p.s. I have found How to get Meteor.user() to return on the server side?, but not work on iron-router

I'm afraid that this is not possible. I guess that the problem comes from the fact that you're trying to connect to the server with two different protocols - both literally and in logically - so there is no obvious way to relate this two actions.
There is, however, a pretty simple solution that may suit your needs. You'll need to develop a simple system of privileges tokens, or secret keys, or whatever you call them. First, create a server method
var Secrets = new Meteor.Collection("secrets"); // only on server!!!
Meteor.methods({
getSecretKey: function () {
if (!this.userId)
// check if the user has privileges
throw Meteor.Error(403);
return Secrets.insert({_id: Random.id(), user: this.userId});
},
});
Then, you can now use it on the client to get the secretKey which attach to your AJAX request (or something), either within the HTTP header or in the URL itself. Fear not!
They will all be encrypted if you're using HTTPS.
On the server side you can now retrieve the secretKey from the incoming request and check if it is present in the Secrets collection. You'll know then if the user is granted certain privileges or not.
Also you may want to remove your secret keys from the collection after some time for safety reasons.

If what you're looking to do is to authenticate the Meteor.user making the request, I'm currently doing this within the context of IronRouter.route(). The request must be made with a valid user ID and auth token in the header. I call this function from within Router.route(), which then gives me access to this.user:
###
Verify the request is being made by an actively logged in user
#context: IronRouter.Router.route()
###
authenticate = ->
# Get the auth info from header
userId = this.request.headers['x-user-id']
loginToken = this.request.headers['x-auth-token']
# Get the user from the database
if userId and loginToken
user = Meteor.users.findOne {'_id': userId, 'services.resume.loginTokens.token': loginToken}
# Return an error if the login token does not match any belonging to the user
if not user
respond.call this, {success: false, message: "You must be logged in to do this."}, 401
# Attach the user to the context so they can be accessed at this.user within route
this.user = user
###
Respond to an HTTP request
#context: IronRouter.Router.route()
###
respond = (body, statusCode=200, headers={'Content-Type':'text/json'}) ->
this.response.writeHead statusCode, headers
this.response.write(JSON.stringify(body))
this.response.end()
This code was heavily inspired by RestStop and RestStop2. It's part of a meteor package for writing REST APIs in Meteor 0.9.0+ (built on top of Iron Router). You can check out the complete source code here:
https://github.com/krose72205/meteor-restivus

Related

User is created however cannot login after logging out MeteorJS

So I'm creating a new user as my template is created. The user is being created successfully, and automatically is logged in however if I sign out and then try to sign in , I get the 'user not found'. Here is my code
Template.hello.onCreated(function helloOnCreated() {
// counter starts at 0
this.counter = new ReactiveVar(0);
var userObject = {
username: "anotherTest",
mail: "anotherTest#me.com",
password: "testingME"
};
Accounts.createUser(userObject, function(error){
console.log('User created');
console.log(error);
});
});
And here is the full project in case it is needed.
https://github.com/hayk94/UbMvp/tree/accountsTEST
Do you know what is the problem?
You're trying to use client side accounts management to perform a task it hasn't been designed for.
Client side accounts package purpose is to specifically allow new users to create their account and expect to be logged in immediately.
You have to remember that certain functions can be run on the client and/or on the server with different behaviors, Accounts.createUser docs specify that : "On the client, this function logs in as the newly created user on successful completion."
On the contrary, "On the server, it returns the newly created user id." (it doesn't mess with the currently logged in user on the client).
In order to solve your problem, you should write a server side method creating a new user and be able to call it from your client side admin panel, after filling correctly a user creation form of your own design.

Handling authentification to Firebase Database with Fetch in a Service Worker

I'm trying to query a Firebase database from a Service Worker using the Fetch API. However it doesn't work as expected as I can't get authenticated correctly.
Basically what I'm trying to do is from origin https://myproject.firebaseapp.com inside a Service Worker I do a call like this :
var fetchOptions = {};
fetchOptions.credentials = 'include';
var url = options.messageUrl;
var request = new Request('https://myproject.firebaseio.com/user/foobar.json', fetchOptions);
messagePromise = fetch(request).then(function(response) {
return response.json();
});
I'm getting this error :
Fetch API cannot load https://myproject.firebaseio.com/user/foobar.json. Response to preflight request doesn't pass access control check: Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials. Origin 'https://myproject.firebaseapp.com' is therefore not allowed access.
Any idea of a way to fix it? How one should do to query/update the Firebase database from a SW?
I've read https://jakearchibald.com/2014/using-serviceworker-today/ and one of the gotcha was exactly that problem, the fact that Fetch request do not send authentification.
Ideally it would be great to be able to use the Firebase JS API inside a SW but this doesn't seem to work as well.
Firebase doesn't store authentication info as a cookie or in anything that would be sent along in the credentials, so there's no need to send them in your fetch request. Instead, you'll need to pull the token from Firebase Auth:
firebase.auth().currentUser.getToken(true).then(function(token) {
// token is the value you'll need to remember for later
});
Once you've got the token, you should be able to add it as a query parameter to the REST request e.g. ?auth={THE_TOKEN}. This will allow you to make your authenticated request in the Service Worker.

meteor-shopify authenticator getPermanentAccessToken with code

I'm using the froatsnook:shopify atmosphere package to create an embedded public app on Shopify. I currently have a couple issues:
1) Getting the access token from the "code" query parameter after a user authenticates. As it mentions in the docs here, I'm supposed to use authenticator.getPermanentAccessToken(code) but what I don't understand is how to get call authenticator if the "code" parameter appears on the callback route (at that point, the authenticator I instantiated on the client pre-auth route is out of scope).
2) The "oAuth" function callback is never called for some reason, even when assigning it to Shopify.onAuth on the server.
3) The difference between post_auth_uri and redirect_uri ?
// I call this during 'onBeforeAction' for iron-router
function beforeAuth (query) {
// is this necessary..?
console.assert(Meteor.isClient);
// get shop name like 'myshop' from 'myshop.shopify.com';
const shop = query.shop.substring(0, query.shop.indexOf('.'));
// use api_key stored in settings
var api_key = Meteor.settings.public.shopify.api_key;
// Prepare to authenticate
var authenticator = new Shopify.PublicAppOAuthAuthenticator({
shop: shop,
api_key: api_key,
keyset: 'default',
embedded_app_sdk: true,
redirect_uri: 'https://45a04f23.ngrok.com/testContent',
//post_auth_uri: ???
// This is doesn't seem to be getting
// called after clicking through the OAuth dialog
onAuth: function(access_token) {
ShopifyCredentials.insert({
shop: shop,
api_key: api_key,
access_token: access_token
});
}
});
// Should i use something different with iron-router?
location.href = authenticator.auth_uri;
// how do i get code in this scope???
// authenticator.getPermanentAccessToken(code);
}
There are a few issues with the way you are trying to set up the authenticator, although it's not really your fault because the way Scenario 3 works in the docs is not an 'out of the box' solution and requires a bunch of custom code, including your own handler (I can provide a gist if you REALLY want to build your own handler, but I suggest using the new server-side onAuth callback instead)
1. Specifying a redirect_uri overrides the package's default redirect_uri handler which is Meteor.absoluteUrl("/__shopify-auth").
So instead, completely remove redirect_uri and put your testContent url in post_auth_uri instead.
2. ShopifyCredentials does not exist in this package. If you want to use it that way, make sure you actually have defined a collection called 'ShopifyCredentials' and insert the record from the server, not the client. Note that you will still need to add a keyset on the server for the API methods to work. If you are using user accounts and would like to permanently store credentials, I suggest saving the credentials to the database and adding the keyset via a server-side onAuth callback.
3. authenticator.getPermanentAccessToken(code) isn't useful unless you are using your own handler. Instead, you can just get access_token from the onAuth callback.
Also keep in mind that if you ever need to reauthenticate from inside the embedded app, you need to use window.top.location.href to break out of the iframe.
If you want a complete, working boilerplate example with user accounts see my gist here:
Authentication with Accounts and Persistent Keysets
If you aren't using accounts, you can use this gist instead, but please note that you really need to come up with some way to check that the current client has permission to request the keyset for a given shop before going to production:
Authentication with Persistent Keysets

How can I create a method for retrieving user email address that is available on the client and server?

I've got facebook, google and regular registration/login turned on on my website. The problem I have is that the email address is stored in different fields depending on how the user first joined.
For regular users, it is in field emails[0].address. For facebook and google authenticated users it is in field services[0].email.
At various places in the client (templates, events) and on the server (method), I just want to call one method that works out which field to use and returns the email address. I also want to do something similar for the verification field.
I'm fairly new to meteor and the only ways I've found to do the above so far is to repeat the same logic in the client and on the server which doesn't sit well with me.
The best thing to do would be to transfer the email address to 'emails' if they log in with facebook, google or another services for the first time. This would also make it more future proof incase you add other services, since meteor will always use emails.address (including in other packages)
Server side code:
Accounts.onCreateUser(function(user) {
user.emails = user.emails || []; //If its null set it to an empty array
if(user.services.facebook) {
user.emails.push({address: user.services.facebook.email, verified: false});
}else if(user.services.google) {
user.emails.push({address: user.services.google.email, verified: false});
}
return user;
});
Then you can just check Meteor.user().emails[0].address every time.
Note: If not published due to the autopublish package you may have to publish the emails field for it to work on the client.
You may also have to run this the first time for users who have already logged in before:
Meteor.startup(function() {
Meteor.users({'emails':{$exists: false}}).fetch().forEach(function(user) {
var email = (user.services.facebook || user.services.google).email;
if(email) Meteor.users.update({_id: user._id},{$push:{emails:{address: email, verified: false}}});
});
});
I'm not sure if facebook and google both use email in the services key, if they do the above should work fine. If they don't you can edit out the key that is used for google or facebook, in case one is emailAddress instead of email for example.

Inner auth() seems to adhere to outer auth() rules

In our application we use Firebase's custom login functionality to store some metadata in user's auth token.
Later we send this token to one of our web applications to perform a task on behalf of the user using a new admin token to disable security rules. The idea is that a particular location is not writable by authenticated users directly, but data could be written in that location after some server side calculations and validations are done.
Here's a sample code of what I'm trying to do:
var testRef = new Firebase(firebaseApp + 'test');
testRef.auth(userFirebaseAuthToken, function(error, result) {
if (!error) {
var userId = result.auth.userId;
// perform validations and calculations
var tokenGenerator = new FirebaseTokenGenerator(firebaseSecret);
var token = tokenGenerator.createToken({admin: true});
var protectedRef = new Firebase(firebaseApp + '/protected/');
protectedRef.auth(token, function(error) {
if (!error) {
protectedRef.child('foo').push({id: userId});
}
});
}
});
But I get this error:
FIREBASE WARNING: set at /protected/foo/-Ityb1F6_G9ZrGCvMtX- failed: permission_denied
When desired behavior is to be able to write in that location using an admin token.
I understand that this might not be a Firebase issue, but some JavaScript good/bad parts, but what I need to do is to write in some protected location on behalf of a user which even though is not authorized to write in that location, but needs to be authenticated.
Based on what I've seen from my test units and from experience, I don't think that new Firebase actually gives you an independent connection to the data. That is to say, these are both connected to the same Firebase instance internally (I think):
var refA = new Firebase('...');
var refB = new Firebase('...');
So if you want to re-auth, I'm pretty sure you need to call unauth first, which will probably affect your testRef instance as well.
If you truly need to have multiple instances opened to the database with different auth at the same time, then you'll have to look at node-fibers or some other worker pool model, which will allow separate connections.
However, give some thought to this; you are probably overthinking your approach. If you are writing on behalf of a user who doesn't have permissions, then you probably don't actually need to be authenticated as that user.
I've written an entire app with secure Firebase components that are consumed by a third-party app, and then written back to privileged paths and then read by users, and haven't yet run into a condition where the server would need to demote its permissions to do this.
That's not meant to presume I know your use case, just to give you some encouragement to keep things simple, because trying to juggle authentication will not be simple.
My approach is to treat the Firebase security rules as a last defense--like my firewall--rather than part of the programming algorithm used by privileged processes.

Resources