forked from stytchauth/stytch-node-magic-links
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
123 lines (109 loc) · 4.17 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
const express = require("express");
const bodyParser = require("body-parser");
const url = require('url');
const stytch = require("stytch")
const { Mailchain } = require('@mailchain/sdk')
require('dotenv').config()
const app = express();
const port = process.env.PORT;
const path = `http://localhost:${port}`
const magicLinkUrl = `${path}/authenticate`
// bodyParser allows us to access the body of the post request
app.use(bodyParser.urlencoded({ extended: true }));
// defines the directory where the static assets are so images & css render correctly
app.use(express.static('public'));
// set app to use ejs so we can use html templates
app.set('view engine', 'ejs')
// define the stytch client using your stytch project id & secret
// use stytch.envs.live if you want to hit the live api
const client = new stytch.Client({
project_id: process.env.STYTCH_PROJECT_ID,
secret: process.env.STYTCH_SECRET,
env: stytch.envs.test,
}
);
const mailchain = Mailchain.fromSecretRecoveryPhrase(process.env.SECRET_RECOVERY_PHRASE)
// define the homepage route
app.get("/", (req, res) => {
res.render('loginOrSignUp');
});
// takes the email entered on the homepage and hits the stytch
// loginOrCreateUser endpoint to send the user a magic link
app.post('/login_or_create_user', async function (req, res) {
const params = {
email: req.body.email,
login_magic_link_url: magicLinkUrl,
signup_magic_link_url: magicLinkUrl,
};
const isMailchain = params.email.endsWith('mailchain.com');
if (isMailchain) {
const userSearchResult = await client.users.search({
query: {
operator: "AND",
operands: [
{ filter_name: "email_address", filter_value: [ params.email ] },
],
},
});
const existingUser = userSearchResult.results[0];
const userToAuth = existingUser ?? (await client.users.create({ create_user_as_pending: true, email: req.body.email,}));
const magicLinkParams = await client.magicLinks.create({ user_id: userToAuth.user_id })
const subject = "Stytch Magic 🪄 Link"
const magicLinkUrlWithToken = `${magicLinkUrl}?userId=${magicLinkParams.user_id}&token=${magicLinkParams.token}`
const content = {
text: `Navigate to ${magicLinkUrlWithToken} to authenticate`,
html: `
<div>
<h1>Your ${existingUser ? 'login' : 'sign up'} request. Click on the button to proceed.</h1>
<div style="text-decoration: none; margin:10px; padding:10px; display:inline-block; background-color: rgb(16, 110, 233); border: 1px solid rgb(16, 110, 233); border-radius: 4px;">
<a style="color: white" href={${magicLinkUrlWithToken}}>${existingUser ? 'LOGIN' : 'SING UP'}</a>
</div>
</div>`
}
const { data: sentMail, error } = await mailchain.sendMail({
from: (await mailchain.user()).address,
to: [params.email],
subject,
content
})
if (error) {
console.error('Failed sending message', error);
return res.status(500).render('loginOrSignUp');
}
console.log('Successfully send message', sentMail)
return res.render('emailSent')
}
client.magicLinks.email.loginOrCreate(params)
.then(
// on success, render the emailSent page
res.render('emailSent')
)
.catch(err => {
// on failure, log the error then render the homepage
console.log(err)
res.render('loginOrSignUp')
});
})
// This is the endpoint the link in the magic link hits. It takes the token from the
// link's query params and hits the stytch authenticate endpoint to verify the token is valid
app.get('/authenticate', function (req, res) {
const queryObject = url.parse(req.url,true).query;
client.magicLinks.authenticate(queryObject.token)
.then(r =>
// on success render the logged in view
res.render('loggedIn')
)
.catch(err => {
// on failure, log the error then render the homepage
console.log(err)
res.render('loginOrSignUp')
});
})
// handles the logout endpoint
app.get('/logout', function (req, res) {
res.render('loggedOut');
})
// run the server
app.listen(port, () => {
console.log(`Listening to requests on ${path}`);
});