diff --git a/packages/component-invite/src/Invite.js b/packages/component-invite/src/Invite.js
index ad15c5e4d9852905b352704e277986cfd026b567..b4309fc68d017f930ec15afc13f5e9941b5bc637 100644
--- a/packages/component-invite/src/Invite.js
+++ b/packages/component-invite/src/Invite.js
@@ -5,7 +5,9 @@ const crypto = require('crypto')
 const mailService = require('pubsweet-component-mail-service')
 const get = require('lodash/get')
 const pick = require('lodash/pick')
+const config = require('config')
 
+const configRoles = config.get('roles')
 const Invite = app => {
   app.use(bodyParser.json())
   const authBearer = app.locals.passport.authenticate('bearer', {
@@ -19,42 +21,33 @@ const Invite = app => {
       return
     }
 
+    const hasInviteRight = existingRole =>
+      configRoles.inviteRights[existingRole].includes(role)
     const collectionId = get(req, 'params.collectionId')
     const reqUser = await app.locals.models.User.find(req.user)
     let collection
-    if (collectionId) {
+    if (collectionId && reqUser.roles !== undefined) {
+      if (!configRoles.collection.includes(role)) {
+        res
+          .status(400)
+          .json({ error: `Role ${role} cannot be set on collections` })
+        logger.error(`invitation has been attempted with invalid role: ${role}`)
+        return
+      }
+
+      if (!reqUser.roles.some(hasInviteRight)) {
+        res.status(403).json({
+          error: `${reqUser.roles} cannot invite a ${role}`,
+        })
+        logger.error(`incorrect role when inviting a user`)
+        return
+      }
       try {
-        if (role !== 'reviewer' && role !== 'handlingEditor') {
-          res.status(400).json({ error: 'Role does not exist for collections' })
-          logger.error(
-            `invitation has been attempted with invalid role: ${role}`,
-          )
-          return
-        }
-        if (reqUser.roles === undefined) {
-          res
-            .status(403)
-            .json({ error: 'Only HE or EiC can invite users to collection' })
-          logger.error(`request user does not have any defined roles`)
-          return
-        }
-        if (role === 'reviewer' && !reqUser.roles.includes('handlingEditor')) {
-          res.status(403).json({ error: 'Only HE can invite reviewers' })
-          logger.error(`incorrect role when inviting a reviewer`)
-          return
-        } else if (
-          role === 'handlingEditor' &&
-          !reqUser.roles.includes('editorInChief')
-        ) {
-          res.status(403).json({ error: 'Only EiC can invite HE' })
-          logger.error(`incorrect role when inviting a handling editor`)
-          return
-        }
         collection = await app.locals.models.Collection.find(collectionId)
       } catch (e) {
         if (e.name === 'NotFoundError') {
           res.status(404).json({ error: 'Collection not found' })
-          logger.error(`invalid collection id when inviting ${role}`)
+          logger.error(`invalid collection id when inviting a ${role}`)
           return
         }
 
@@ -62,13 +55,23 @@ const Invite = app => {
         logger.error(e)
         return
       }
-    } else if (role !== 'editorInChief') {
-      res.status(400).json({ error: 'Collection id is required' })
-      logger.error('missing collection id when trying to invite reviewer/HE')
+    } else if (reqUser.admin === true) {
+      reqUser.roles = []
+      reqUser.roles.push('admin') // this should be moved in pubsweet server
+    } else {
+      res.status(403).json({
+        error: `${reqUser.roles ||
+          'undefined roles'} cannot invite a ${role} without a collection`,
+      })
+      logger.error(`request user does not have any defined roles`)
       return
-    } else if (reqUser.admin !== true) {
-      res.status(403).json({ error: 'Only an admin can invite EiC' })
-      logger.error('non-admin user tried to invite an EiC')
+    }
+
+    if (!reqUser.roles.some(hasInviteRight)) {
+      res.status(403).json({
+        error: `${reqUser.roles} cannot invite a ${role}`,
+      })
+      logger.error(`incorrect role when inviting a ${role}`)
       return
     }
 
@@ -98,6 +101,7 @@ const Invite = app => {
         lastName,
         affiliation,
         title,
+        admin: role === 'admin',
       }
       let newUser = new app.locals.models.User(userBody)
       newUser = await newUser.save()
@@ -180,30 +184,12 @@ const Invite = app => {
     '/api/users/invite/password/reset',
     bodyParser.json(),
     async (req, res) => {
-      const {
-        token,
-        password,
-        email,
-        firstName,
-        lastName,
-        affiliation,
-        title,
-      } = req.body
-
-      if (
-        !checkForUndefinedParams(
-          token,
-          password,
-          email,
-          firstName,
-          lastName,
-          affiliation,
-        )
-      ) {
+      if (!checkForUndefinedParams(req.body)) {
         res.status(400).json({ error: 'missing required params' })
         return
       }
 
+      const { password } = req.body
       if (password.length < 7) {
         res
           .status(400)
@@ -216,16 +202,16 @@ const Invite = app => {
 
       const updateFields = {
         password,
-        firstName,
-        lastName,
-        affiliation,
-        title,
+        firstName: req.body.firstName,
+        lastName: req.body.lastName,
+        affiliation: req.body.affiliation,
+        title: req.body.title,
         isConfirmed: true,
       }
 
       const validateResponse = await validateEmailAndToken(
-        email,
-        token,
+        req.body.email,
+        req.body.token,
         app.locals.models.User,
       )
       if (validateResponse.success === false) {
@@ -235,6 +221,11 @@ const Invite = app => {
         return
       }
 
+      if (validateResponse.user.isConfirmed) {
+        res.status(400).json({ error: 'User is already confirmed' })
+        return
+      }
+
       let newUser = Object.assign(
         validateResponse.user,
         updateFields,
diff --git a/packages/xpub-faraday/config/default.js b/packages/xpub-faraday/config/default.js
index b5acdae84239af709cacddfc81852a9fb7d37b62..3fb21750085971bb004180f6b5ef357272253ab8 100644
--- a/packages/xpub-faraday/config/default.js
+++ b/packages/xpub-faraday/config/default.js
@@ -65,6 +65,15 @@ module.exports = {
       process.env.PUBSWEET_INVITE_PASSWORD_RESET_URL ||
       'http://localhost:3000/invite',
   },
+  roles: {
+    global: ['admin', 'editorInChief', 'author'],
+    collection: ['handlingEditor', 'reviewer'],
+    inviteRights: {
+      admin: ['admin', 'editorInChief', 'author'],
+      editorInChief: ['handlingEditor'],
+      handlingEditor: ['reviewer'],
+    },
+  },
   publicKeys: [
     'pubsweet-client',
     'authsome',