diff --git a/packages/component-admin/.gitignore b/packages/component-admin/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3614a810088d89d9ccaa28d82401545634874a18
--- /dev/null
+++ b/packages/component-admin/.gitignore
@@ -0,0 +1,8 @@
+_build/
+api/
+logs/
+node_modules/
+uploads/
+.env.*
+.env
+config/local*.*
\ No newline at end of file
diff --git a/packages/component-admin/README.md b/packages/component-admin/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6107c057207697467a41159bcc3f0eee270ae181
--- /dev/null
+++ b/packages/component-admin/README.md
@@ -0,0 +1,42 @@
+# AWS SES
+
+In order to use `component-aws-ses` you first need to have a `.env` file containing AWS data in the root folder of the starting point of your application.
+
+The `.env` file contain the following data:
+```bash
+AWS_SES_SECRET_KEY = <secretKey>
+AWS_SES_ACCESS_KEY = <accessKey>
+EMAIL_SENDER = verified_ses_sender@domain.com
+AWS_SES_REGION = region-name
+```
+
+Then, as soon as possible in your app you should add the `dotenv` package:
+```js
+require('dotenv').config()
+```
+
+# `component-aws-ses` API
+A list of endpoints that help you upload, download and delete S3 files.
+
+## Send an email [POST]
+#### Request
+`POST /api/email`
+#### Request body
+
+All parameters are `required`
+```json
+{
+	"email": "to_email@domain.com",
+	"subject": "Example subject",
+	"textBody": "this is an email",
+	"htmlBody": "<p><b>This</b> is an <i>email</i>"
+}
+```
+#### Response
+```json
+HTTP/1.1 204
+```
+
+
+
+
diff --git a/packages/component-admin/index.js b/packages/component-admin/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..f569b273abd8938c1a205c421dff09fc32e824ec
--- /dev/null
+++ b/packages/component-admin/index.js
@@ -0,0 +1,3 @@
+module.exports = {
+  backend: () => app => require('./src/User')(app),
+}
diff --git a/packages/component-admin/package.json b/packages/component-admin/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..12bc8f99650bf87df42887c5d9d350090b7d8771
--- /dev/null
+++ b/packages/component-admin/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "pubsweet-component-admin",
+  "version": "0.0.1",
+  "description": "admin component for pubsweet",
+  "license": "MIT",
+  "files": [
+    "src"
+  ],
+  "scripts": {
+    "test": "jest"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://gitlab.coko.foundation/xpub/xpub"
+  },
+  "dependencies": {
+    "body-parser": "^1.17.2"
+  },
+  "peerDependencies": {
+    "@pubsweet/logger": "^0.0.1",
+    "pubsweet": "^1.1.1",
+    "pubsweet-client": "^1.1.1",
+    "pubsweet-server": "^1.0.1"
+  },
+  "devDependencies": {
+    "jest": "^22.1.1",
+    "supertest": "^3.0.0"
+  }
+}
diff --git a/packages/component-admin/src/User.js b/packages/component-admin/src/User.js
new file mode 100644
index 0000000000000000000000000000000000000000..f72f01649615103c983a34407c02ebd314a4596e
--- /dev/null
+++ b/packages/component-admin/src/User.js
@@ -0,0 +1,150 @@
+const bodyParser = require('body-parser')
+const logger = require('@pubsweet/logger')
+const uuid = require('uuid')
+const crypto = require('crypto')
+const mailService = require('pubsweet-component-mail-service')
+
+const User = app => {
+  app.use(bodyParser.json())
+  const authBearer = app.locals.passport.authenticate('bearer', {
+    session: false,
+  })
+  app.post('/api/admin/users', authBearer, async (req, res) => {
+    const reqUser = await app.locals.models.User.find(req.user)
+    if (reqUser.admin !== true) {
+      res.status(403).json({ error: 'Unauthorized' })
+      logger.error('unauthorized request')
+      return
+    }
+    const { email, role } = req.body
+    if (email === undefined || role === undefined) {
+      res.status(400).json({ error: 'all parameters are required' })
+      logger.error('some parameters are missing')
+      return
+    }
+
+    try {
+      const user = await app.locals.models.User.findByEmail(email)
+      if (user) {
+        res.status(400).json({ error: 'User already exists' })
+        logger.error('admin tried to invite existing user')
+        return
+      }
+    } catch (e) {
+      if (e.name === 'NotFoundError') {
+        const userBody = {
+          username: uuid.v4().slice(0, 7),
+          email,
+          password: uuid.v4(),
+          roles: { role },
+          passwordResetToken: crypto.randomBytes(32).toString('hex'),
+          isConfirmed: false,
+        }
+        let newUser = new app.locals.models.User(userBody)
+        newUser = await newUser.save()
+        let emailType
+        switch (newUser.roles.role) {
+          case 'editorInChief':
+            emailType = 'invite-editor-in-chief'
+            break
+          case 'handlingEditor':
+            emailType = 'invite-handling-editor'
+            break
+          case 'reviewer':
+            emailType = 'invite-reviewer'
+            break
+          default:
+            break
+        }
+        await mailService.setupEmail(
+          newUser.email,
+          emailType,
+          newUser.passwordResetToken,
+        )
+      }
+    }
+
+    res.status(204).json()
+  })
+  app.post(
+    '/api/admin/users/password-reset',
+    bodyParser.json(),
+    async (req, res) => {
+      const {
+        token,
+        password,
+        email,
+        firstName,
+        lastName,
+        username,
+        middleName,
+        affiliation,
+        position,
+        title,
+      } = req.body
+
+      if (
+        !checkForUndefinedParams(
+          token,
+          password,
+          email,
+          firstName,
+          lastName,
+          username,
+        )
+      ) {
+        res.status(400).json({ error: 'missing required params' })
+        return
+      }
+
+      const updateFields = {
+        password,
+        firstName,
+        lastName,
+        username,
+        middleName,
+        affiliation,
+        position,
+        title,
+        isConfirmed: true,
+      }
+
+      try {
+        const user = await app.locals.models.User.findByEmail(email)
+        if (user) {
+          if (token !== user.passwordResetToken) {
+            res.status(400).json({ error: 'invalid request' })
+            logger.error('admin pw reset tokens do not match')
+            return
+          }
+
+          let newUser = Object.assign(user, updateFields, user)
+          delete newUser.passwordResetToken
+
+          newUser = await newUser.save()
+          res.status(200).json(newUser)
+        }
+      } catch (e) {
+        if (e.name === 'NotFoundError') {
+          res.status(404).json({ error: 'user not found' })
+          logger.error('admin pw reset on non-existing user')
+        } else if (e.name === 'ValidationError') {
+          res.status(400).json({ error: e.details[0].message })
+          logger.error('admin pw reset validation error')
+        }
+        res.status(400).json({ error: e })
+        logger.error(e)
+      }
+    },
+  )
+}
+
+const checkForUndefinedParams = (...params) => {
+  if (params.includes(undefined)) {
+    return false
+  }
+
+  return true
+}
+
+module.exports = User
diff --git a/packages/component-aws-ses/index.js b/packages/component-aws-ses/index.js
index 8b8d52ceca5a0d380e5e5a3a66681030ccfad18a..b54639e30fd890a999ba73bcf5ab581788aeaa82 100644
--- a/packages/component-aws-ses/index.js
+++ b/packages/component-aws-ses/index.js
@@ -1,5 +1,3 @@
 require('dotenv').config()
 
-module.exports = {
-  backend: () => app => require('./src/EmailBackend')(app),
-}
+module.exports = require('./src/EmailBackend')
diff --git a/packages/component-aws-ses/package.json b/packages/component-aws-ses/package.json
index 6267c1f10a75287b9b72fe5e0c2f369e2f6b8190..21500be0578aca6d2dfa147f4e3e5ddee0829738 100644
--- a/packages/component-aws-ses/package.json
+++ b/packages/component-aws-ses/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pubsweet-components-aws-ses",
-  "version": "0.0.1",
+  "version": "0.2.0",
   "description": "xpub aws ses configured for faraday",
   "license": "MIT",
   "files": [
diff --git a/packages/component-aws-ses/src/EmailBackend.js b/packages/component-aws-ses/src/EmailBackend.js
index 33a52e0f83f0b42874701cfdfece5ff793a5805a..3cef31414720ec8cb8caf745fd84f3df4d22fa5c 100644
--- a/packages/component-aws-ses/src/EmailBackend.js
+++ b/packages/component-aws-ses/src/EmailBackend.js
@@ -1,5 +1,4 @@
 const nodemailer = require('nodemailer')
-const bodyParser = require('body-parser')
 const AWS = require('aws-sdk')
 const config = require('config')
 const _ = require('lodash')
@@ -7,36 +6,21 @@ const logger = require('@pubsweet/logger')
 
 const sesConfig = _.get(config, 'pubsweet-component-aws-ses')
 
-const EmailBackend = app => {
-  app.use(bodyParser.json())
-  const authBearer = app.locals.passport.authenticate('bearer', {
-    session: false,
-  })
-  app.post('/api/email', authBearer, async (req, res) => {
+module.exports = {
+  sendEmail: (toEmail, subject, textBody, htmlBody) => {
     AWS.config.update({
       secretAccessKey: sesConfig.secretAccessKey,
       accessKeyId: sesConfig.accessKeyId,
       region: sesConfig.region,
     })
 
-    const { email, subject, textBody, htmlBody } = req.body
-    if (
-      email === undefined ||
-      subject === undefined ||
-      textBody === undefined ||
-      htmlBody === undefined
-    ) {
-      res.status(400).json({ error: 'all parameters are required' })
-      logger.error('some parameters are missing')
-      return
-    }
     const transporter = nodemailer.createTransport({
       SES: new AWS.SES(),
     })
     transporter.sendMail(
       {
         from: sesConfig.sender,
-        to: email,
+        to: toEmail,
         subject,
         text: textBody,
         html: htmlBody,
@@ -48,8 +32,5 @@ const EmailBackend = app => {
         logger.debug(info)
       },
     )
-    res.status(204).json()
-  })
+  },
 }
-
-module.exports = EmailBackend
diff --git a/packages/component-mail-service/.gitignore b/packages/component-mail-service/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3614a810088d89d9ccaa28d82401545634874a18
--- /dev/null
+++ b/packages/component-mail-service/.gitignore
@@ -0,0 +1,8 @@
+_build/
+api/
+logs/
+node_modules/
+uploads/
+.env.*
+.env
+config/local*.*
\ No newline at end of file
diff --git a/packages/component-mail-service/README.md b/packages/component-mail-service/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/packages/component-mail-service/index.js b/packages/component-mail-service/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..3d0b3c14535e01c151f895accdfd5e0ccfc1294b
--- /dev/null
+++ b/packages/component-mail-service/index.js
@@ -0,0 +1 @@
+module.exports = require('./src/Mail')
diff --git a/packages/component-mail-service/package.json b/packages/component-mail-service/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..09ca4ea72eafe7a7507fef3b6cd682216dad9850
--- /dev/null
+++ b/packages/component-mail-service/package.json
@@ -0,0 +1,30 @@
+{
+  "name": "pubsweet-component-mail-service",
+  "version": "0.0.1",
+  "description": "mail service component for pubsweet",
+  "license": "MIT",
+  "files": [
+    "src"
+  ],
+  "scripts": {
+    "test": "jest"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://gitlab.coko.foundation/xpub/xpub"
+  },
+  "dependencies": {
+    "body-parser": "^1.17.2",
+    "handlebars": "^4.0.11"
+  },
+  "peerDependencies": {
+    "@pubsweet/logger": "^0.0.1",
+    "pubsweet": "^1.1.1",
+    "pubsweet-client": "^1.1.1",
+    "pubsweet-server": "^1.0.1"
+  },
+  "devDependencies": {
+    "jest": "^22.1.1",
+    "supertest": "^3.0.0"
+  }
+}
diff --git a/packages/component-mail-service/src/Mail.js b/packages/component-mail-service/src/Mail.js
new file mode 100644
index 0000000000000000000000000000000000000000..23644ec833d62036e394e8f933810fad077ae486
--- /dev/null
+++ b/packages/component-mail-service/src/Mail.js
@@ -0,0 +1,50 @@
+const fs = require('fs')
+const handlebars = require('handlebars')
+const querystring = require('querystring')
+const SES = require('pubsweet-components-aws-ses')
+const config = require('config')
+
+const resetUrl = config.get('admin-reset-password.url')
+
+module.exports = {
+  setupEmail: async (email, emailType, token, comment = '') => {
+    let subject
+    const htmlFile = readFile(`${__dirname}/templates/${emailType}.html`)
+    const textFile = readFile(`${__dirname}/templates/${emailType}.txt`)
+    let replacements = {}
+    const htmlTemplate = handlebars.compile(htmlFile)
+    const textTemplate = handlebars.compile(textFile)
+
+    switch (emailType) {
+      case 'invite-editor-in-chief':
+        subject = 'Hindawi Invitation'
+        replacements = {
+          url: `${resetUrl}?${querystring.encode({
+            email,
+            token,
+          })}`,
+        }
+        break
+      default:
+        subject = 'Welcome to Hindawi!'
+        break
+    }
+
+    const htmlBody = htmlTemplate(replacements)
+    const textBody = textTemplate(replacements)
+
+    SES.sendEmail(email, subject, textBody, htmlBody)
+  },
+}
+
+const readFile = path => {
+  const file = fs.readFileSync(path, { encoding: 'utf-8' }, (err, file) => {
+    if (err) {
+      throw err
+    } else {
+      return file
+    }
+  })
+
+  return file
+}
diff --git a/packages/component-mail-service/src/templates/invite-editor-in-chief.html b/packages/component-mail-service/src/templates/invite-editor-in-chief.html
new file mode 100644
index 0000000000000000000000000000000000000000..58abc88115fe94ea3601b861c1703316e49f0446
--- /dev/null
+++ b/packages/component-mail-service/src/templates/invite-editor-in-chief.html
@@ -0,0 +1,2 @@
+<p>You have been invited</p>
+<p>Here is your url <a href="{{ url }}">PW RESET</a></p>
\ No newline at end of file
diff --git a/packages/component-mail-service/src/templates/invite-editor-in-chief.txt b/packages/component-mail-service/src/templates/invite-editor-in-chief.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d249e30cc14554c2a87ba079439bbba7d2b2d976
--- /dev/null
+++ b/packages/component-mail-service/src/templates/invite-editor-in-chief.txt
@@ -0,0 +1,2 @@
+You have been invited
+Here is your url PW REST {{ url }}
\ No newline at end of file
diff --git a/packages/components-faraday/src/components/Admin/Admin.js b/packages/components-faraday/src/components/Admin/Admin.js
index 10a21ca47871a8863218d5d62faa879851571543..929cda6e26fdd300baf94bc5b0001ebcbe527efc 100644
--- a/packages/components-faraday/src/components/Admin/Admin.js
+++ b/packages/components-faraday/src/components/Admin/Admin.js
@@ -1,17 +1,196 @@
 import React from 'react'
 import styled from 'styled-components'
+import { Icon, Menu } from '@pubsweet/ui'
 
-const Admin = ({ users = [] }) => (
-  <Root>
-    <h2>Admin</h2>
-    <ul>
-      {users.map((u, i) => (
-        <li key={u.id}>
-          {u.username} - {u.email}
-        </li>
-      ))}
-    </ul>
-  </Root>
+import { Pagination } from './'
+
+const AddButton = styled.button`
+  align-items: center;
+  border: none;
+  cursor: pointer;
+  display: flex;
+  font-family: Helvetica;
+  font-size: 12px;
+  text-align: left;
+  color: #667080;
+
+  &:active,
+  &:focus {
+    outline: none;
+  }
+`
+
+const Header = styled.div`
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+
+  & span {
+    font-family: Helvetica;
+    font-size: 24px;
+    font-weight: bold;
+    text-align: left;
+    color: #667080;
+  }
+`
+
+const SubHeader = styled.div`
+  align-items: center;
+  border-bottom: 1px solid #667080;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  margin-top: 20px;
+  padding-bottom: 10px;
+
+  > div:first-child {
+    display: flex;
+    align-items: center;
+  }
+
+  span {
+    font-family: Helvetica;
+    font-size: 14px;
+    text-align: left;
+    color: #667080;
+  }
+`
+
+const Table = styled.table`
+  border-spacing: 0;
+  border-collapse: collapse;
+  margin-top: 10px;
+  width: 100vw;
+
+  & thead tr {
+    height: 40px;
+    border-bottom: 1px solid #667080;
+    font-family: Helvetica;
+    font-size: 14px;
+    font-weight: bold;
+    text-align: left;
+    color: #667080;
+  }
+`
+
+const Row = styled.tr`
+  border-bottom: 1px solid #667080;
+  color: #667080;
+  font-family: Helvetica;
+  font-size: 14px;
+  height: 40px;
+  text-align: left;
+`
+
+const Status = styled.td`
+  & span {
+    border: solid 1px #667080;
+    text-transform: uppercase;
+    font-family: Helvetica;
+    font-size: 12px;
+    font-weight: bold;
+    text-align: left;
+    color: #667080;
+    padding: 2px 10px;
+  }
+`
+
+const Input = styled.input`
+  height: 20px;
+  width: 20px;
+`
+
+const TableRow = ({ toggleUser, selected, email, username, type }) => (
+  <Row>
+    <td>
+      <Input checked={selected} onClick={toggleUser} type="checkbox" />
+    </td>
+    <td>{email}</td>
+    <td>{username}</td>
+    <td>affiliation here</td>
+    <td>country here</td>
+    <td>{type}</td>
+    <Status>
+      <span>status</span>
+    </Status>
+  </Row>
+)
+
+const Admin = ({
+  users,
+  toggleUser,
+  toggleAllUsers,
+  incrementPage,
+  decrementPage,
+  page,
+  itemsPerPage,
+}) => (
+  <div>
+    <Header>
+      <span>Users</span>
+      <AddButton>
+        <Icon color="#667080">plus-circle</Icon>
+        Add User
+      </AddButton>
+    </Header>
+    <SubHeader>
+      <div>
+        <span>Bulk actions: </span>
+        <Menu
+          onChange={value => value}
+          options={[
+            { value: 'deactivate', label: 'Deactivate' },
+            { value: 'activate', label: 'Activate' },
+          ]}
+          value="activate"
+        />
+
+        <Menu
+          onChange={value => value}
+          options={[
+            { value: 'sort', label: 'SORT' },
+            { value: 'unsort', label: 'UNSORT' },
+          ]}
+          value="sort"
+        />
+
+        <Icon color="#667080" size={24}>
+          search
+        </Icon>
+      </div>
+      <Pagination
+        decrementPage={decrementPage}
+        incrementPage={incrementPage}
+        itemsPerPage={itemsPerPage}
+        page={page}
+      />
+    </SubHeader>
+
+    <Table>
+      <thead>
+        <tr>
+          <td>
+            <Input
+              checked={users.every(u => u.selected)}
+              onClick={toggleAllUsers}
+              type="checkbox"
+            />
+          </td>
+          <td>Email</td>
+          <td>Full name</td>
+          <td>Affiliation</td>
+          <td>Country</td>
+          <td>Roles</td>
+          <td>Status</td>
+        </tr>
+      </thead>
+      <tbody>
+        {users.map(u => (
+          <TableRow key={u.id} {...u} toggleUser={toggleUser(u)} />
+        ))}
+      </tbody>
+    </Table>
+  </div>
 )
 
 export default Admin
diff --git a/packages/components-faraday/src/components/Admin/AdminPage.js b/packages/components-faraday/src/components/Admin/AdminPage.js
index 684f7df5ddd552914641e4961163e89fbc134b9e..075f484484a7e72b8659a3ef1b9138a30b381390 100644
--- a/packages/components-faraday/src/components/Admin/AdminPage.js
+++ b/packages/components-faraday/src/components/Admin/AdminPage.js
@@ -4,11 +4,33 @@ import { connect } from 'react-redux'
 import { actions } from 'pubsweet-client'
 import { ConnectPage } from 'xpub-connect'
 import { withRouter } from 'react-router-dom'
+import { compose, withState, withHandlers } from 'recompose'
 
 import Admin from './Admin'
 
 export default compose(
   ConnectPage(() => [actions.getUsers()]),
   withRouter,
-  connect(state => ({ users: get(state, 'users.users') })),
+  connect(state => ({ currentUsers: get(state, 'users.users') })),
+  withState('users', 'setUsers', props =>
+    props.currentUsers.map(u => ({ ...u, selected: false })),
+  ),
+  withState('itemsPerPage', 'setItemsPerPage', 50),
+  withState('page', 'setPage', 0),
+  withHandlers({
+    incrementPage: ({ setPage }) => () => {
+      setPage(p => p + 1)
+    },
+    decrementPage: ({ setPage }) => () => {
+      setPage(p => (p > 0 ? p - 1 : p))
+    },
+    toggleUser: ({ setUsers }) => user => () => {
+      setUsers(prev =>
+        prev.map(u => (u.id === user.id ? { ...u, selected: !u.selected } : u)),
+      )
+    },
+    toggleAllUsers: ({ setUsers }) => () => {
+      setUsers(users => users.map(u => ({ ...u, selected: !u.selected })))
+    },
+  }),
 )(Admin)
diff --git a/packages/components-faraday/src/components/Admin/Pagination.js b/packages/components-faraday/src/components/Admin/Pagination.js
new file mode 100644
index 0000000000000000000000000000000000000000..df4373a0d4f4fe2e93df637c90e8664c4060bde9
--- /dev/null
+++ b/packages/components-faraday/src/components/Admin/Pagination.js
@@ -0,0 +1,70 @@
+import React from 'react'
+import styled from 'styled-components'
+import { Icon } from '@pubsweet/ui'
+
+const Root = styled.div`
+  display: flex;
+  align-items: center;
+`
+
+const Chevrons = styled.div`
+  display: flex;
+  align-items: center;
+`
+
+const IconButton = styled.button`
+  align-items: center;
+  border: none;
+  cursor: pointer;
+  display: flex;
+  font-family: Helvetica;
+  font-size: 12px;
+  text-align: left;
+  color: #667080;
+
+  &:active,
+  &:focus {
+    outline: none;
+  }
+`
+
+const Showing = styled.div`
+  display: flex;
+  align-items: center;
+
+  span:first-child {
+    font-family: Helvetica;
+    font-size: 14px;
+    text-align: left;
+    color: #667080;
+    margin-right: 10px;
+  }
+  span:last-child {
+    border: solid 1px #667080;
+    padding: 2px 10px;
+  }
+`
+
+const Pagination = ({ page, itemsPerPage, incrementPage, decrementPage }) => (
+  <Root>
+    <Showing>
+      <span>Showing:</span>
+      <span>50</span>
+    </Showing>
+    <Chevrons>
+      <IconButton onClick={decrementPage}>
+        <Icon color="#667080" size={18}>
+          chevron-left
+        </Icon>
+      </IconButton>
+      <span>{`${page * itemsPerPage + 1} to ${page * itemsPerPage + 50}`}</span>
+      <IconButton onClick={incrementPage}>
+        <Icon color="#667080" size={18}>
+          chevron-right
+        </Icon>
+      </IconButton>
+    </Chevrons>
+  </Root>
+)
+
+export default Pagination
diff --git a/packages/components-faraday/src/components/Admin/index.js b/packages/components-faraday/src/components/Admin/index.js
index f623059ef006ec5d6c516c651bdaa474feb4f073..4f1e2831e6e6710d184684b30b4257f9493ea47a 100644
--- a/packages/components-faraday/src/components/Admin/index.js
+++ b/packages/components-faraday/src/components/Admin/index.js
@@ -1,3 +1,4 @@
 import AdminPage from './AdminPage'
 
 export default AdminPage
+export { default as Pagination } from './Pagination'
diff --git a/packages/components-faraday/src/components/Dashboard/Dashboard.js b/packages/components-faraday/src/components/Dashboard/Dashboard.js
index 29ba564fd069e3d25afe4247899b5f5917afd15f..110f39981fe79f44e7671d3c02fec67ebd76e666 100644
--- a/packages/components-faraday/src/components/Dashboard/Dashboard.js
+++ b/packages/components-faraday/src/components/Dashboard/Dashboard.js
@@ -23,14 +23,24 @@ const Dashboard = ({
   filterItems,
   abstractModal,
   setModal,
+  history,
   ...rest
 }) => (
   <div className={classes.root}>
     <div className={classes.header}>
       <div className={classes.heading}>Manuscripts</div>
-      <Button onClick={createDraftSubmission} primary>
-        New
-      </Button>
+      <div className={classes.headerButtons}>
+        <Button
+          className={classes['admin-button']}
+          onClick={() => history.push('admin')}
+          primary
+        >
+          Admin dashboard
+        </Button>
+        <Button onClick={createDraftSubmission} primary>
+          New
+        </Button>
+      </div>
     </div>
     <DashboardFilters
       changeFilterValue={changeFilterValue}
diff --git a/packages/components-faraday/src/components/Dashboard/Dashboard.local.scss b/packages/components-faraday/src/components/Dashboard/Dashboard.local.scss
index 5a2dc6819b679b6e45fd78737c23c00a77787a86..b4fb082487cd95ba901f0c2dcfb120d20b300312 100644
--- a/packages/components-faraday/src/components/Dashboard/Dashboard.local.scss
+++ b/packages/components-faraday/src/components/Dashboard/Dashboard.local.scss
@@ -67,6 +67,14 @@
   justify-content: space-between;
 }
 
+.headerButtons {
+  display: flex;
+
+  .admin-button {
+    margin-right: 15px;
+  }
+}
+
 .heading {
   color: var(--color-primary);
   font-size: 1.6em;
diff --git a/packages/xpub-faraday/config/components.json b/packages/xpub-faraday/config/components.json
index 8c34645a85924f65fc2e2d8475db8b2d05cba90c..d64253bf25516eebd779a3f72a6f728e37ef63c6 100644
--- a/packages/xpub-faraday/config/components.json
+++ b/packages/xpub-faraday/config/components.json
@@ -7,5 +7,5 @@
   "pubsweet-component-wizard",
   "pubsweet-components-faraday",
   "pubsweet-components-aws-s3",
-  "pubsweet-components-aws-ses"
+  "pubsweet-component-admin"
 ]
diff --git a/packages/xpub-faraday/config/default.js b/packages/xpub-faraday/config/default.js
index d41444fcc32124eeb24639c80380e9f2536f3204..245f1dbe7b3d34ab7c80d7399c2d000240341f51 100644
--- a/packages/xpub-faraday/config/default.js
+++ b/packages/xpub-faraday/config/default.js
@@ -25,7 +25,7 @@ module.exports = {
   'pubsweet-client': {
     API_ENDPOINT: '/api',
     'login-redirect': '/',
-    'redux-log': false,
+    'redux-log': true,
     theme: process.env.PUBSWEET_THEME,
   },
   'mail-transport': {
@@ -60,6 +60,11 @@ module.exports = {
     region: process.env.AWS_SES_REGION,
     sender: process.env.EMAIL_SENDER,
   },
+  'admin-reset-password': {
+    url:
+      process.env.PUBSWEET_ADMIN_PASSWORD_RESET_URL ||
+      'http://localhost:3000/admin/password-reset',
+  },
   publicKeys: [
     'pubsweet-client',
     'authsome',
diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js
index f7d617d3d72c0ead1b9bc4390c10a45445006929..8b98883df175275ecb57a268cf4f549d065a92c3 100644
--- a/packages/xpub-faraday/config/validations.js
+++ b/packages/xpub-faraday/config/validations.js
@@ -88,6 +88,13 @@ module.exports = {
   user: {
     name: Joi.string(), // TODO: add "name" to the login form
     roles: Joi.object(),
+    isConfirmed: Joi.boolean(),
+    firstName: Joi.string().allow(''),
+    lastName: Joi.string().allow(''),
+    middleName: Joi.string().allow(''),
+    affiliation: Joi.string().allow(''),
+    position: Joi.string().allow(''),
+    title: Joi.string().allow(''),
   },
   team: {
     group: Joi.string(),
diff --git a/packages/xpub-faraday/package.json b/packages/xpub-faraday/package.json
index fabc887cc97882eb924de656b768f103fbf52326..e3b80d41b71900568e6bb0eb5d821f06df2765f7 100644
--- a/packages/xpub-faraday/package.json
+++ b/packages/xpub-faraday/package.json
@@ -31,7 +31,7 @@
     "pubsweet-component-xpub-submit": "^0.0.2",
     "pubsweet-server": "1.0.5",
     "pubsweet-components-aws-s3": "^0.0.1",
-    "pubsweet-components-aws-ses": "^0.0.1",
+    "pubsweet-component-admin": "^0.0.1",
     "react": "^15.6.1",
     "react-dnd": "^2.5.4",
     "react-dnd-html5-backend": "^2.5.4",
diff --git a/yarn.lock b/yarn.lock
index eaeb4eea2fab94726a5a42f59a381f52f3ad1025..76654745dcb4355df780499d9a0f89f31cf8640e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4324,7 +4324,7 @@ handle-thing@^1.2.5:
   version "1.2.5"
   resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
 
-handlebars@^4.0.2, handlebars@^4.0.3:
+handlebars@^4.0.11, handlebars@^4.0.2, handlebars@^4.0.3:
   version "4.0.11"
   resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc"
   dependencies: