updatedFields_contains: "resetToken"
node: { resetToken_not: "null" }
const fetch = require('isomorphic-fetch');
const Base64 = require('Base64');
const FormData = require('form-data');
const apiKey = 'api:key-YOUR_MAIL_GUN_API_KEY';
const url = 'https://api.mailgun.net/v3/your.mailgun.url/messages';
module.exports = async event => {
email, resetToken, firstname, company: { host },
} = event.data.User.node;
const resetUrl = `${host}/reset/${resetToken}`;
<p>We've received a password reset request for the account with this email. <a href="${resetUrl}">Click here</a> to reset your password.</p>
const form = new FormData();
form.append('from', 'Your Email Name <no-reply@yourwebsite.com>');
form.append('to', email);
form.append('subject', 'Password Reset Confirmation');
form.append('html', message);
Authorization: `Basic ${Base64.btoa(apiKey)}`,
return { data: { status: 'success' } };
type triggerPasswordResetPayload {
triggerPasswordReset(email: String!): triggerPasswordResetPayload
const crypto = require('crypto');
const { fromEvent } = require('graphcool-lib');
module.exports = event => {
const { email } = event.data;
const graphcool = fromEvent(event);
const api = graphcool.api('simple/v1');
const generateResetToken = () => crypto.randomBytes(20).toString('hex');
const generateExpiryDate = () => {
return new Date(now.getTime() + 3600000).toISOString();
const getGraphcoolUser = email => api
.then(userQueryResult => {
if (userQueryResult.error) {
return Promise.reject(userQueryResult.error);
return userQueryResult.User;
const toggleReset = graphcoolUserId => api.request(`
id: "${graphcoolUserId}",
resetToken: "${generateResetToken()}",
resetExpires: "${generateExpiryDate()}"
return getGraphcoolUser(email)
if (graphcoolUser === null) {
return Promise.reject(Error('An unexpected error occurred.'));
return toggleReset(graphcoolUser.id);
const { id } = response.updateUser;
return { error: 'An unexpected error occured.' };
type ResetPasswordPayload {
resetPassword(resetToken: String!, password: String!): ResetPasswordPayload
const { fromEvent } = require('graphcool-lib');
const bcrypt = require('bcryptjs');
module.exports = event => {
const { resetToken } = event.data;
const newPassword = event.data.password;
const graphcool = fromEvent(event);
const api = graphcool.api('simple/v1');
const getUserWithToken = resetToken =>
User(resetToken: "${resetToken}") {
.then(userQueryResult => {
if (userQueryResult.error) {
return Promise.reject(userQueryResult.error);
!userQueryResult.User.id ||
!userQueryResult.User.resetExpires
return Promise.reject(new Error('Not a valid token'));
return userQueryResult.User;
const updatePassword = (id, newPasswordHash) =>
password: "${newPasswordHash}",
.then(userMutationResult => userMutationResult.updateUser.id);
return getUserWithToken(resetToken)
console.log(graphcoolUser);
const userId = graphcoolUser.id;
const { resetExpires } = graphcoolUser;
if (new Date() > new Date(resetExpires)) {
return Promise.reject(Error('Token expired.'));
.hash(newPassword, saltRounds)
.then(hash => updatePassword(userId, hash))
.then(id => ({ data: { id } }))
.catch(error => ({ error: error.toString() }));
return { error: 'An unexpected error occured.' };