Error logging in with token in two separate applications

Hi guys!

We have to split our web app into mobile web app and dashboard. Dashboard is a main app located in localhost:3000. We are trying to connect mobile app located at loalhost:3002 to our main app.
There is a code:

 Meteor.remoteConnection = DDP.connect('localhost:3000');
Meteor.remoteConnection.onReconnect = function() {
    console.log('Meteor.remoteConnection.onReconnect', arguments);
};
// make sure Accounts uses this so I can login
Accounts.connection = Meteor.remoteConnection;
// redeclare so it uses remote users
Meteor.users = new Meteor.Collection('users',{connection: Meteor.remoteConnection});
Products = new Mongo.Collection("products", Meteor.remoteConnection);
Meteor.remoteConnection.subscribe('Products');

After login in to mobile app I can recieve Meteor.user() but after refreshing this page I’ve got an error: Error logging in with token: Error: You've been logged out by the server. Please log in again. [403].

Please help me with problem solution.

1 Like

Any update on this? I have the same problem and still trying to figure out.

I didn’t find the answer. Maybe in next releases it will be solved.

Just yesterday we solved it with sessionStorage or localStorage:

Tracker.autorun(function () {
    var token = sessionStorage.getItem('_storedLoginToken');

    if(token){
        Meteor.loginWithToken(token, function(err){
            // this is going to throw error if we logged out
            if(!err) {console.log('loginWithToken ',token)}
            else{console.log('loginWithTokenError ',err)};
        });
    }
});
//
// autorun.user
//if user is logged in we put token to **sessionStorage**
Tracker.autorun(function(){
    var user = Meteor.user();
    //sometimes user can be null
    if (user === null){
        user = undefined;
    }
    if(user)
    {
        console.log('set token');
        sessionStorage.setItem('_storedLoginToken', Accounts._storedLoginToken());
    }
});
1 Like

@savagesem, Where goes this code? An can it be use for three or more application?

I’ve created the file in root client directory called ‘startup.js’ and put this code to it, after meteor was updated i had to make some changes in the code:

 // Connecting to the remote server
var connection = DDP.connect('localhost:3000'); //You have to put there your remote server
//Connecting accounts system from remote server
ClientAccounts = new AccountsClient({connection: connection});

//Replace base connections
Meteor.connection = connection;
//// make sure Accounts uses this so I can login
Accounts.connection = connection;

// Patching methods
var methods = ["subscribe", "call", "apply", "methods", "status", "reconnect", "disconnect", "onReconnect"];
methods.forEach(function (method) {
    Meteor[method] = function () {
        return connection[method].apply(connection, arguments);
    };
});
// always checks if token was changed
Tracker.autorun(function () {
    var token = localStorage.getItem('_storedLoginToken');

    if (token) {

        ClientAccounts.loginWithToken(token, function (err) {
            // this is going to throw error if we logged out
            if (!err) {
                console.log('loginWithToken ', token);
                //back to previous page after login in
               // if (Iron.Location.get().path!='/')
             //   history.back();
            }
            else {
               // Router.go("/login");
                console.log('loginWithTokenError ', err)
            }


        });
        //if client login success, redirect to prev. page
        ClientAccounts.onLogin(function(){
            var path = Iron.Location.get().path;
            if (path!='/' && path=="/login")
                history.back();
        });
    }
});

//Always checks if user was changed
Tracker.autorun(function () {
    var user = ClientAccounts.user();
    if (user === null) {
        user = undefined;

    }
    if (user) {
        localStorage.setItem('_storedLoginToken', Accounts._storedLoginToken());
    }
});

Here is my code for auth on two or more meteor apps with meteor cookies.

On master app put this in client code(localhost:3000)

Accounts.onLogin(function(){
Cookie.set(’_storedLoginToken’, Accounts._storedLoginToken(), {expires: 30});
});

Tracker.autorun(function(){
var user = Accounts.user();
if (user === null) {
token = Cookie.get(’_storedLoginToken’);
Accounts.loginWithToken(token);
}
});

Accounts.ui.config({
passwordSignupFields: ‘USERNAME_AND_EMAIL’
});

on other apps put this in client code(localhost:5000, localhost:4000, etc)

REMOTE_ACCOUNTS_DDP_URL = “http://localhost:3000”;
REMOTE_ACCOUNTS_DDP_CONNECTION = DDP.connect(REMOTE_ACCOUNTS_DDP_URL);
REMOTE_ACCOUNTS_DDP_CONNECTION.subscribe(‘users’);

Accounts.connection = REMOTE_ACCOUNTS_DDP_CONNECTION;
Accounts.users = new Meteor.Collection(‘users’, REMOTE_ACCOUNTS_DDP_CONNECTION);

Accounts.onLogin(function(){
Cookie.set(’_storedLoginToken’, Accounts._storedLoginToken(), {expires: 30});
});

Tracker.autorun(function(){
var user = Accounts.user();
if (user === null) {
token = Cookie.get(’_storedLoginToken’);
Accounts.loginWithToken(token);
}
});

Accounts.ui.config({
passwordSignupFields: ‘USERNAME_AND_EMAIL’
});

Please test code, and give me your feedback about security:)?

1 Like

@zarkostanisic Solution with Cookie not working for me:

Uncaught ReferenceError: Cookie is not defined(…)
(anonymous function) @ VM89344:2
InjectedScript._evaluateOn @ VM89079:875
InjectedScript._evaluateAndWrap @ VM89079:808
InjectedScript.evaluate @ VM89079:664

Does anyone found working solution?

Install “chuangbo:cookie” package.

@zarkostanisicI have installed this package both on master(web) and slave(mobile) application.
On master appliction client code i add:

// Run this when the meteor app is started
 Meteor.startup(function () {
    Accounts.onLogin(function(){
         Cookie.set('storedLoginToken', Accounts._storedLoginToken(), {expires: 30});
     });

     Tracker.autorun(function(){
         var user = Accounts.user();
         if (user === null) {
             token = Cookie.get('_storedLoginToken');
            Accounts.loginWithToken(token);
        }
    });
}); 

On slave application client code I add:

Meteor.startup(function() {
    REMOTE_ACCOUNTS_DDP_URL = "http://smartworkout.ru:3000";
    REMOTE_ACCOUNTS_DDP_CONNECTION = DDP.connect(REMOTE_ACCOUNTS_DDP_URL);
    REMOTE_ACCOUNTS_DDP_CONNECTION.subscribe('users');
    Accounts.connection = REMOTE_ACCOUNTS_DDP_CONNECTION;
    Accounts.users = new Meteor.Collection('users', REMOTE_ACCOUNTS_DDP_CONNECTION);
    Accounts.onLogin(function(){
        Cookie.set('_storedLoginToken', Accounts._storedLoginToken(), {expires: 30});
    });
    Tracker.autorun(function(){
        var user = Accounts.user();
        if (user === null) {
            token = Cookie.get('_storedLoginToken');
            Accounts.loginWithToken(token);
        }
    });
});

But after success login and refresh page I have same message:

Error logging in with token: Error: You've been logged out by the server. Please log in again. [403]

Solve.
Problem was in Accounts.storedLoginToken(). It is should be Accounts._storedLoginToken() with _ underscore prefix(corrected above).
But now I still see error message hovewer user are logged in. I think this is just workaround. We need a better solution.

@achirkof You may want to checkout the similar issue I had here:

How can I utilize `this.userId` from a Meteor method call?

However, in my app both are sharing the same database so I just added the accounts to both and logged in regularly. I don’t use allow/deny and needed to check this.userID in my Meteor method… so I just passed in the login token and then used a function to fetch the user with that login token and use that instead of this.userId.

Also in another microservice app cluster, one that’s using mostly a ReactNative app as a client, I skipped using the Meteor accounts/auth all together and rolled my own using a JWT token (standard for APIs now a days). This has been much much easier than fighting with the built in auth. but this won’t be a viable solution for every app.

Wow, do you plan on publishing your work in the form of a post or package? :smile:

Wow, do you plan on publishing your work in the form of a post or package? :smile:

Perhaps if I release a boilerplate for the REST router/controller setup I have.

Basically the JWT just works as a middleware layer for all incoming HTTP JSON requests (except user create). They’re not using any Meteor methods but if it was you could pass that JWT token as well to authenticate.

An easy to use module is: https://www.npmjs.com/package/jwt-simple

1 Like

Just mocked up a sample of the REST library i’m using… thinking about open sourcing it if there’s enough interest. Currently it’s just a local package and is a bit project specific.

Post #27
Use Functional Programming to Simplify Your Meteor Code

1 Like

The accounts package manages the stored login token and keeps it in localStorage, no need to manage the logintoken on your own.

When running a Meteor App, take a look at localStorage. You will see Meteor.loginToken in localStorage. This can be accessed via Accounts._loginToken.

See discussion here.