Share login state between microservices

I am trying to create a microservice that simply publishes notifications for the current user. I have been able to deploy, connect, and subscribe to the microservice. The problem is that no data is returned because this.userId is undefined in the publication; the user is only authenticated in the app (on the default DDP connection) and not the connection for the microservice.

How would I go about doing this? Is there a way to “login” to a DDP connection, similar to Meteor.loginWithPassword? Is there a way to make the subscription aware of the current user?

I have found some packages that attempt to tackle this issue, but they haven’t been maintained in awhile and I’d like to avoid adding dependencies if I can. I was hoping to find an “official” solution.

Thanks everyone,

Mike

2 Likes

Tried this one ?

https://www.npmjs.com/package/ddp-login

2 Likes

I ran into this as well and no matter how you do it, it’s going to be a bit painful. However, depending on your use case, if you can have the client pass in their login token from local storage as one of the meteor method parameters, you can lookup the user based on their login token, and from that user, get the id (and the whole user document).

However, the token on the client won’t match the login token exactly… I think you have to run generate stamped token or some method like that to convert the client hash into the same one the server saved to the user document (I had to dig around either the simpe-rest-password package or the meteor password package to find that stamped token method.

So to sum up, pass the login token into the method and then you can pass that around. If a server is only doing a server to server call, I create a long string as a shared private token (in private meteor settings) and use that as a parameter… then you can securely send the userId if that makes more sense (but only depend on the userId if the client is not sending it to you of course)

Hope this helps!

edit

Here’s a snippet:

Meteor.methods({
  getFoo(userToken) {
    const hashedToken = Accounts._hashLoginToken(userToken);
    const user = db.users.findOne({
      "services.resume.loginTokens.hashedToken": hashedToken
    });
    const userId = user._id;
    // do work
  },
 ...
2 Likes

I assume that you have created a 2nd connection to your microservice using DDP.connect. e.g. I will call this 2nd connection mServiceConn

Then you have a connection. You can share logins with your login to your client server.

  1. Create a new Accounts client for the new connection via AccountsClient({'connection': mServiceConn})
  2. Get your client server login via Accounts._storedLoginToken(). This takes the token information out of the localStorage.
  3. Login to your new connection via the new accounts client mServiceAccount.loginWithToken(token, callback())

Snippet:

let mServiceConn= DDP.connect(MICROSERVICE_URL);
let mServiceAccount = new AccountsClient({'connection': mServiceConn});

// On login:
// - login to the client server through the Accounts package
// - login to the microservice server
Accounts.onLogin(() => {
  let loginToken = Accounts._storedLoginToken();

  // Use the accounts loginToken to login to the mService
  if(loginToken) {
    console.log('Logging in with token');
    mServiceAccount.loginWithToken(loginToken,
      (loginErr, result) => {
        if(loginErr) {
          console.log(loginErr.message);
        }
      });
  } else {
    console.log('Unable to log in');
  }
});

Good luck!

6 Likes

Wow, thank you so much! Didn’t expect to get three leads out of this.

Gonna take a look at each one, prototype it, and see which method the team prefers. Will post back with results… and likely more questions. :smiley:

Thanks again.

1 Like

PS: don’t forget to logout either.

Your logout handler could simply logout from the mServiceAccount connection and on success then logout from the main connection.

Snipped:

// On logout do the reverse:
// - log out from the microservice connection
// - log out from the main client server
function myLogout() {
  mServiceAccount .logout(function mServiceLogoutCB(error) {
    if(error) {
      console.log('MicroService logout error: ', error.message);
    } else {
      Meteor.logout(function meteorLogoutCB(CBErr) {
        if(CBErr) {
          console.log('MeteorLogout error: ', error.message);
        } else {
          // Go back to my main page
          FlowRouter.go('/');
        }
      });
    }
  });
};
2 Likes

Hi @moberegger
So which way did you end up going with? :slight_smile:
Would appreciate to get your feedback as I still have few questions too.

Thanks!

Hello, people, i am trying to do login cross microservers, for example, 3 apps, loginbackend, clientfront, databackend, all then most be login with loginbackend service, i want to validate ddp conection by user from databackend

1 Like