Meteor login in Nodejs

We have a Meteor app and we’re releasing a new product that is a React Native app. The RN app uses a GraphQL API, sharing the same database as the Meteor app. We would like those RN users to be able to log into that app with the same credentials as they do in the Meteor app - email & password.

How is that possible? Is there an NPM package I can use to achieve this?

You can, just use the User collection in your graphql resolvers.
I would advise to Hash the password on the RN client before sending the request !

It’s just login, not signup. How do I compare the password input from the RN with the Meteor user one?

You need to hash the password on the client with a function such as :

function hashPassword(password) {
  return {
     digest: SHA256(password),
     algorithm: "sha-256"
  }
}

send the userId / username with this hashed string with graphql on the backend.

on the backend you can do :

function passwordResolver(info, { username, hashedPassword }) {
   const user = User.findOne({ username })
   const authed = Accounts._checkPassword(user, hashedPassword)
   if (authed.error == null)  {
     return 'sometoken' 
  }
}

Thanks a lot!
Where does Accounts come from?

And how would I validate the token, coming from the next request?

You can find the documentation here : https://docs.meteor.com/api/accounts.html
Accounts._checkPassword is used in the source code for loginWithPassword.

You should pass the token in every graphql request header in a field such as Authorization or Bearer.

On your graphql server you should get pass the user in the context object.
I don’t know which server you’re using, but with ApolloServer you can do :

import { ApolloServer, AuthenticationError } from 'apollo-server-express'
import { getUser }                           from 'meteor/apollo'

new ApolloServer({
  //...rest of the config
  context: async ({ req }) => {
    const user = await getUser(req.headers.authorization)
    if (user == null) {
      throw new AuthenticationError('must authenticate')
    }
    return { user }
  }
})

Got it, thanks!
I’m just wondering how you got the Meteor NPM package to install in your GQL backend? When I try to install it via yarn add meteor, I get an error saying Meteor cannot be installed from NPM directly.

My Meteor app is my GQL Backend…
I’m using the Apollo framework: https://www.apollographql.com/docs/
I’m using graphql on my app clients, mobile or web (which is kind of the concept of using graphql).
There’s an official support for Apollo with Meteor.

Oh, so you’re not using a pure NodeJS backend? That makes our scenarios completely different.

I want to use the Accounts._checkPassword from a fresh Node project.

  1. yarn init
  2. yarn add meteor - or however you’d get that package
  3. Inside index.js:
    const authed = Accounts._checkPassword(user, hashedPassword)

If that’s possible then it will work on my Apollo Server (Node).

That won’t work because you can’t use Meteor in a normal Node app. The auth process though isn’t too rough if you want to try and write it yourself. To confirm a password you really just need

import { compare, genSalt, hash } from 'bcryptjs'
import crypto, { randomBytes } from 'crypto'

First get the formatted pw via
const passwordHash = crypto.createHash('sha256').update(password).digest('hex')
where password is the plaintext pw sent over the API. This gives you the hashed password

then to confirm the correct password use compare:
const compared = await compare(passwordHash, user.services.password.bcrypt) where user.services.password.bcrypt is coming from the DB itself.

3 Likes

just a quick question :

  • why did you put your GQL server aside from your meteor server ?
  • are you using your GQL backend on your meteor webapp ? if so why separating the 2 ?