A login validation extension for Meteor that supports OAuth services
JavaScript
Latest commit 0a81735 Oct 12, 2016 @t3db0t added enable flag

README.md

Accounts-Invite

Live demo: http://accounts-invite-demo.meteor.com/

Don't you wish you could validate account creation in Meteor more flexibly? accounts-invite is a login validation extension for Meteor that supports OAuth services, not just accounts-password, and provides basic anonymous account functionality.

Features

  • Anonymous users: On demand, the current visitor can have a user record created that can have a service added to it
  • Flexibly validate account creation: allow creation of accounts only if the client specifies a valid token, for instance

The Problem

All the beta invitation systems for Meteor that I could find (such as this one) make password-based user accounts explicitly. What I wanted was a way for the user to arrive at a special route that allows them to create an account with any service of their choice, including password. This turns out to be nontrivial because of the limitations of Meteor's built-in validation methods.

What's required is a way to allow Oauth (or accounts-password) account creation ONLY when we want, i.e. at an acceptInvitation route with a token, and deny account creation everywhere else, yet still allow registered users to login with the regular login buttons. Meteor's validateLoginAttempt and validateNewUser methods are called by the server, which has no way of knowing about your client-side token.

The Solution

accounts-validate exposes a special login method (loginWithInvite) that creates a temporary, anonymous user with a token supplied by your app (i.e. at an acceptInvitation route). That token can then be verified by login validation callbacks. accounts-invite depends on these packages:

API

  • Meteor.loginWithInvite(inviteObject) (Client)
    • inviteObject is an object containing at least a field called inviteToken
    • inviteToken can by any string of your choice, i.e. Random.id(n)
    • The object can be used for any custom fields, for instance if your app needs more than one separate validation system/area
  • validateToken(inviteObject) (Server)
    • return true to allow account registration
    • return false to deny
  • onCreatedAccount(attemptingUser, attempt) (Server)
    • Called when the account is successfully registered
    • attemptingUser, attempt: same as in brettle:accounts-multiple, useful for assigning profile name or other info

How it works

  • accounts-invite registers a custom login handler
  • loginWithInvite(token) is called by host app
  • temporary user is created
  • User signs in with service of her choice (i.e. via loginButtons)
  • accounts-multiple catches the 'switching' of accounts and calls validateToken(). If that returns true,
  • accounts-add-service merges the new service into the existing user record
  • onCreatedAccount callback is called so you can, for instance, update an invitation status to "claimed"
  • You should still be able to use Accounts.validateNewUser as normal.
  • Note: Accounts.onLoginFailure will show some 'failures' as part of the normal operation of this system, due to i.e. brettle:accounts-add-service. You can safely ignore these.

Example

// server
AccountsInvite.register({
    validateToken: validateToken,
    onCreatedAccount: onCreatedAccount
});

function validateToken(token){
    if(InvitesCollection.findOne({"token":token})) return true;
    else return false;
}

function onCreatedAccount(token, user){
    InvitesCollection.update({"token":token}, {$set:{"status":"claimed"}});
    // Here you could also do something like...
    // Roles.addUsersToRoles(user._id, ['beta-permissions']);
}

// client
Meteor.loginWithInvite(token);

Known Issues

  • I've observed a bug where the user is logged out if they attempt to sign back in too quickly

Acknowledgements

I'm indebted to brettle for his help in figuring out how to make this work.