From 35dd4e8a131f265bb21366909819aae0ca2d29df Mon Sep 17 00:00:00 2001 From: Tim Boeckmann <2022378+tboeckmann@users.noreply.github.com> Date: Sun, 12 Feb 2023 18:38:45 +0000 Subject: [PATCH 1/9] Add Mailchain tutorial --- books/tutorials/mailchain/README.md | 56 ++++++++++++++++ books/tutorials/mailchain/SUMMARY.md | 10 +++ books/tutorials/mailchain/book.json | 4 ++ books/tutorials/mailchain/configure.md | 90 ++++++++++++++++++++++++++ books/tutorials/mailchain/logout.md | 19 ++++++ books/tutorials/mailchain/prompt.md | 74 +++++++++++++++++++++ books/tutorials/mailchain/send.md | 33 ++++++++++ books/tutorials/mailchain/session.md | 65 +++++++++++++++++++ books/tutorials/mailchain/setup.md | 35 ++++++++++ books/tutorials/mailchain/verify.md | 74 +++++++++++++++++++++ 10 files changed, 460 insertions(+) create mode 100644 books/tutorials/mailchain/README.md create mode 100644 books/tutorials/mailchain/SUMMARY.md create mode 100644 books/tutorials/mailchain/book.json create mode 100644 books/tutorials/mailchain/configure.md create mode 100644 books/tutorials/mailchain/logout.md create mode 100644 books/tutorials/mailchain/prompt.md create mode 100644 books/tutorials/mailchain/send.md create mode 100644 books/tutorials/mailchain/session.md create mode 100644 books/tutorials/mailchain/setup.md create mode 100644 books/tutorials/mailchain/verify.md diff --git a/books/tutorials/mailchain/README.md b/books/tutorials/mailchain/README.md new file mode 100644 index 00000000..ef01d9e2 --- /dev/null +++ b/books/tutorials/mailchain/README.md @@ -0,0 +1,56 @@ +# Introduction + +We will build a todo list app in this tutorial, complete with functionality that +allows users to sign in with Mailchain, the communication layer for Web3 offering +completely private Web3 email. By following along with this tutorial, you will +learn how to use Passport for authentication. + +If you want to see where we are headed, here's an example of the final result: +[https://github.com/passport/todos-express-mailchain](https://github.com/passport/todos-express-mailchain) + +Before we dive in, you'll need a working development environment with [Node.js](https://nodejs.org/) +and [Git](https://git-scm.com/), as well as an editor and terminal of your +choosing. Take a moment to set up these tools if you have not already done so. + +You'll also need a [Mailchain](https://mailchain.com/) account. If you don't +already have one, it's free to sign up. + +Let's get started! + +We are going to start with a starter app, which has all the scaffolding needed +to build a todo list. Let's clone the app: + +```sh +$ git clone https://github.com/passport/todos-express-starter.git mailchain-tutorial +``` + +You now have a directory named `'mailchain-tutorial'`. Let's `cd` into it: + +```sh +$ cd mailchain-tutorial +``` + +Take a moment browse through the files in the starter app. As we work through +this tutorial, we'll be using [Express](https://expressjs.com/) as our web +framework, along with [EJS](https://ejs.co/) as our template engine and [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) +for styling. We will use [SQLite](https://github.com/mapbox/node-sqlite3) as +our database for storing data. Don't worry if you are not familiar with these +technologies -- the necessary code will be provided at each step. + +Now, let's install the dependencies: + +```sh +$ npm install +``` + +And start the server: + +``` +$ npm start +``` + +Let's check to see if its working. Open [http://localhost:3000](http://localhost:3000) +in your browser. You should be greeted with a page explaining how todos help +you get things done. + +Next, we will [add a login page](prompt/) to the app. diff --git a/books/tutorials/mailchain/SUMMARY.md b/books/tutorials/mailchain/SUMMARY.md new file mode 100644 index 00000000..83a51ce4 --- /dev/null +++ b/books/tutorials/mailchain/SUMMARY.md @@ -0,0 +1,10 @@ +# Summary + +* [Introduction](README.md) +* [Login Prompt](prompt.md) +* [Set Up Mailchain](setup.md) +* [Configure Strategy](configure.md) +* [Send Mailchain Message](send.md) +* [Verify Mailchain Address](verify.md) +* [Establish Session](session.md) +* [Log Out](logout.md) diff --git a/books/tutorials/mailchain/book.json b/books/tutorials/mailchain/book.json new file mode 100644 index 00000000..1d348e0e --- /dev/null +++ b/books/tutorials/mailchain/book.json @@ -0,0 +1,4 @@ +{ + "title": "Mailchain Magic Link Tutorial", + "description": "In this tutorial you will build an Express app that lets users log in using their Mailchain or web3 email address by clicking a magic link." +} diff --git a/books/tutorials/mailchain/configure.md b/books/tutorials/mailchain/configure.md new file mode 100644 index 00000000..597a09b8 --- /dev/null +++ b/books/tutorials/mailchain/configure.md @@ -0,0 +1,90 @@ +# Configure Strategy + +Now that we've set up Mailchain, we are ready to configure Passport and the +`passport-magic-link` strategy. + +Install the necessary dependencies: + +```sh +$ npm install passport +$ npm install passport-magic-link +$ npm install @mailchain/sdk +``` + +Open `'routes/auth.js'` and `require` the newly installed packages at line 2, +below where `express` is `require`'d: + +```js +var express = require('express'); +var passport = require('passport'); +var MagicLinkStrategy = require('passport-magic-link').Strategy; +var Mailchain = require('@mailchain/sdk').Mailchain; +var db = require('../db'); +``` + +The app's database is also `require`'d. + +Add the following code at line 8 to configure the `MagicLinkStrategy`. + +``` +var mailchain = Mailchain.fromSecretRecoveryPhrase(process.env.SECRET_RECOVERY_PHRASE); +let fromAddress = process.env['FROM_ADDRESS'] || await mailchain.user().address; +passport.use(new MagicLinkStrategy({ + secret: 'keyboard cat', // change this to something secret + userFields: [ 'mailchain_address' ], + tokenField: 'token', + verifyUserAfterToken: true +}, async function send(user, token) { + var link = 'http://localhost:3000/login/mailchain/verify?token=' + token; + + var msg = { + to: [ user.mailchain_address ], + from: fromAddress, + subject: 'Sign in to Todos', + content: { + text: 'Hello! Click the link below to finish signing in to Todos.\r\n\r\n' + link, + html: '

Hello!

Click the link below to finish signing in to Todos.

Sign in

', + } + }; + return await mailchain.sendMail(msg); +}, function verify(user) { + return new Promise(function(resolve, reject) { + db.get('SELECT * FROM users WHERE mailchain_address = ?', [ + user.mailchain_address + ], function(err, row) { + if (err) { return reject(err); } + if (!row) { + db.run('INSERT INTO users (mailchain_address, mailchain_address_verified) VALUES (?, ?)', [ + user.mailchain_address, + 1 + ], function(err) { + if (err) { return reject(err); } + var id = this.lastID; + var obj = { + id: id, + mailchain_address: user.mailchain_address + }; + return resolve(obj); + }); + } else { + return resolve(row); + } + }); + }); +})); +``` + +This configures the `MagicLinkStrategy` to send mails containing a magic link +using Mailchain. When the user clicks on the magic link, the user record +associated with the Mailchain address will be found. If a user record does not +exist, one is created the first time someone signs in. + +We also need to update our database scheme. Open `'db.js'` and insert the following at line 16: +``` +mailchain_address TEXT UNIQUE, \ +mailchain_address_verified INTEGER, \ +``` + + +The strategy is now configured. Next we need to [send the user a magic link](../send/) +when they click "Sign in with Mailchain." \ No newline at end of file diff --git a/books/tutorials/mailchain/logout.md b/books/tutorials/mailchain/logout.md new file mode 100644 index 00000000..56d76576 --- /dev/null +++ b/books/tutorials/mailchain/logout.md @@ -0,0 +1,19 @@ +# Log Out + +Now that users can sign in, they'll need a way to sign out. + +Open `'routes/auth.js'` and add this route at line 84, below the +`'/login/mailchain/verify'` route: + +```js +router.post('/logout', function(req, res, next) { + req.logout(function(err) { + if (err) { return next(err); } + res.redirect('/'); + }); +}); +``` + +Return to the app, where you should already be signed in, and click "Sign out." + +We've now got a working app where users can sign in and sign out! diff --git a/books/tutorials/mailchain/prompt.md b/books/tutorials/mailchain/prompt.md new file mode 100644 index 00000000..bbbd30a0 --- /dev/null +++ b/books/tutorials/mailchain/prompt.md @@ -0,0 +1,74 @@ +# Login Prompt + +We want to let users sign in with their Mailchain account or any valid Mailchain +address. For that, we need a login page that prompts the user to enter their +Mailchain address. Let's add that now. + +Let's create a file that will contain authentication-related routes: + +```sh +$ touch routes/auth.js +``` + +Add the following code to that file, which creates a login route that will +render the login page. + +```js +var express = require('express'); + +var router = express.Router(); + +router.get('/login', function(req, res, next) { + res.render('login'); +}); + +module.exports = router; +``` + +Next, we need to add this route to the app. Open `'app.js'` and `require` the +newly created auth routes at line 10, below where `'routes/index'` is +`require`'d: + +```js +var indexRouter = require('./routes/index'); +var authRouter = require('./routes/auth'); +``` + +Continuing within `'app.js'`, use the newly `require`'d `authRouter` at line 27, +below where `indexRouter` is `use`'d. + +```js +app.use('/', indexRouter); +app.use('/', authRouter); +``` + +The login page has been added to our app! Let's see how it looks. + +Start the server: + +```sh +$ npm start +``` + +And open [http://localhost:3000](http://localhost:3000) and click "Sign in." We +are prompted to sign in, but there's no place to enter a Mailchain address. + +For that we need an HTML form. Let's add that now. + +Open `'views/login.ejs'` and add the form at line 15, below the "Sign in" +heading: + +```html +

Sign in

+
+
+ + +
+ +
+``` + +Refresh the page. We've now got a login page that prompts the user to sign in +with Mailchain. Next, we will [set up Mailchain](../setup/), in preparation for +sending the user a magic link. diff --git a/books/tutorials/mailchain/send.md b/books/tutorials/mailchain/send.md new file mode 100644 index 00000000..1d361734 --- /dev/null +++ b/books/tutorials/mailchain/send.md @@ -0,0 +1,33 @@ +# Send Web3 Email + +Now that we are prompting the user for their Mailchain address, and have the +strategy configured, the next step is to send the user a Mailchain message when +they click "Sign in with Mailchain." + +Open `'routes/auth.js'`, add this route at line 57, below the `'/login'` route: + +```js +router.post('/login/mailchain', passport.authenticate('magiclink', { + action: 'requestToken', + failureRedirect: '/login' +}), function(req, res, next) { + res.redirect('/login/mailchain/check'); +}); +``` + +This route will process the form on the login page and send a Mailchain message to +the user. + +Continuing within `'routes/auth.js'`, add this route at line 63, below the newly +added `'/login/mailchain'` route: + +```js +router.get('/login/mailchain/check', function(req, res, next) { + res.render('login/mailchain/check'); +}); +``` + +This route will render a page instructing the user to check their Mailchain account +and click the link. + +Next, we will [verify the Mailchain address](../verify/) when the user clicks that link. diff --git a/books/tutorials/mailchain/session.md b/books/tutorials/mailchain/session.md new file mode 100644 index 00000000..ca6f93ec --- /dev/null +++ b/books/tutorials/mailchain/session.md @@ -0,0 +1,65 @@ +# Establish Session + +Once we've verified the user's Mailchain address, we need a login session to +remember the fact that the user has authenticated as they navigate the app. + +To do that, we'll add session support. Begin by installing the necessary +dependencies: + +```sh +$ npm install express-session +$ npm install connect-sqlite3 +``` + +Open `'app.js'` and `require` the additional dependencies at line 8, below +where `'morgan'` is `require`'d: + +```js +var logger = require('morgan'); +var passport = require('passport'); +var session = require('express-session'); + +var SQLiteStore = require('connect-sqlite3')(session); +``` + +Add the following code at line 29, after `express.static` middleware, to +maintain and authenticate the session. + +```js +app.use(express.static(path.join(__dirname, 'public'))); +app.use(session({ + secret: 'keyboard cat', + resave: false, + saveUninitialized: false, + store: new SQLiteStore({ db: 'sessions.db', dir: './var/db' }) +})); +app.use(passport.authenticate('session')); +``` + +Finally, we need to configure Passport to manage the login session. Open +`'routes/auth.js'` and add the following code at line 53: + +```js +passport.serializeUser(function(user, cb) { + process.nextTick(function() { + cb(null, { id: user.id, mailchain_address: user.mailchain_address }); + }); +}); + +passport.deserializeUser(function(user, cb) { + process.nextTick(function() { + return cb(null, user); + }); +}); +``` + +Now, let's retry signing in. Open [http://localhost:3000](http://localhost:3000), +click "Sign in", enter your Mailchain address and click "Sign in with Mailchain". + +Now, check your Mailchain Inbox and click the link. + +We are logged in! Go ahead and enter some tasks you've been needing to get +done. + +At this point, users can sign in with Mailchain! Next, we will add the ability to +[sign out](../logout/). diff --git a/books/tutorials/mailchain/setup.md b/books/tutorials/mailchain/setup.md new file mode 100644 index 00000000..5c4d472a --- /dev/null +++ b/books/tutorials/mailchain/setup.md @@ -0,0 +1,35 @@ +# Set Up Mailchain + +Before we can let users sign in to our app with web3 email, we need a way to send +Mailchain messages. + +For that, we are going to use [Mailchain](https://mailchain.com/). + +For the purposes of this tutorial, we suggest you create a Mailchain account for testing. + +Navigate to [Mailchain](https://app.mailchain.com/register) and follow the steps to register. + +You will be prompted to save your Secret Recovery Phrase, which we will use later. + +You can also retrieve your Secret Recovery Phrase at any time by navigating to +**Settings > [Secret Recovery Phrase](https://app.mailchain.com/settings/security/)**. +Then click **View** and enter your password to retrieve your Secret Recovery Phrase. + +Save your Secret Recovery Phrase somewhere safe and private. We will use it later. + +Now that we have the Secret Recovery Phrase and a Mailchain address, let's create a +`'.env'` file to store them. + +```sh +$ touch .env +``` + +Add your FROM_ADDRESS and API key. The contents of the file should look something like +this: + +```sh +FROM_ADDRESS=user@mailchain.com +SECRET_RECOVERY_PHRASE=__INSERT_SECRET_RECOVERY_PHRASE__ +``` + +Next we will [configure the strategy](../configure/). diff --git a/books/tutorials/mailchain/verify.md b/books/tutorials/mailchain/verify.md new file mode 100644 index 00000000..f6f14140 --- /dev/null +++ b/books/tutorials/mailchain/verify.md @@ -0,0 +1,74 @@ +# Verify Mailchain Address + +Now that we've sent the user a Mailchain message with a magic link, the next step is +to verify the Mailchain address when they click the link. + +Open `'routes/auth.js'`, add this route at line 66, below the `'/login/mailchain/check'` +route: + +```js +router.get('/login/mailchain/verify', passport.authenticate('magiclink', { + successReturnToOrRedirect: '/', + failureRedirect: '/login' +})); +``` + +This route will verify the Mailchain address when the link is clicked. + +Now create a folder and corresponding view for our route. Run the following commands: + +``` +$ mkdir views/login/mailchain +$ touch views/login/mailchain/check.ejs +``` + +Open `'views/login/mailchain/check.ejs'`, add the following code: + +``` + + + + + + Express • TodoMVC + + + + + +
+

todos

+

Check your Mailchain Inbox

+

We sent a magic link to your Mailchain address. Click the link in that message to sign in.

+
+

Didn't receive the message? Get another link

+
+ + + +``` + +Finally, update `'views/index.ejs'` at line 15 to include the `user.mailchain_address`: +``` +
  • <%= user.name || user.username || user.email || user.mailchain_address %>
  • +``` + +Let's test it out to see what happens. + +Start the server: + +```sh +$ npm start +``` + +Open [http://localhost:3000](http://localhost:3000), click "Sign in", enter your +Mailchain address and click "Sign in with Mailchain". + +Now, check your Mailchain inbox and click the link. + +Uh oh... we are informed that there's an error related to sessions. Next, we +will fix that by [establishing a session](../session/). From 8aeda75cb3a2f20e7df0722acd5a0aab92fc610c Mon Sep 17 00:00:00 2001 From: Tim Boeckmann <2022378+tboeckmann@users.noreply.github.com> Date: Sun, 12 Feb 2023 20:15:22 +0000 Subject: [PATCH 2/9] update intro --- books/tutorials/mailchain/README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/books/tutorials/mailchain/README.md b/books/tutorials/mailchain/README.md index ef01d9e2..baae9869 100644 --- a/books/tutorials/mailchain/README.md +++ b/books/tutorials/mailchain/README.md @@ -1,8 +1,16 @@ # Introduction -We will build a todo list app in this tutorial, complete with functionality that -allows users to sign in with Mailchain, the communication layer for Web3 offering -completely private Web3 email. By following along with this tutorial, you will +Mailchain is the communication layer for Web3 offering private, end-to-end encrypted email using +blockchain wallet addresses and web3 identities (e.g. an Ethereum address, ENS name, Unstoppable +Domains name, etc.). Instead of users needing to sign data with a blockchain wallet, passwordless +authentication with magic links for Passport.js improves the safety of users: + +* User signup and login without passwords or needing to sign data +* Supports magic links sent to ENS names, Ethereum addresses, Mailchain accounts and more +* Handles secure token generation, expiration and confirmation + +In this tutorial, we will build a todo list app in this tutorial, complete with functionality +that allows users to sign in with Mailchain. By following along with this tutorial, you will learn how to use Passport for authentication. If you want to see where we are headed, here's an example of the final result: From f33a5ad657b5c863c4176230b82d06afc8f88f96 Mon Sep 17 00:00:00 2001 From: Tim Boeckmann <2022378+tboeckmann@users.noreply.github.com> Date: Sun, 12 Feb 2023 20:18:02 +0000 Subject: [PATCH 3/9] update formatting --- books/tutorials/mailchain/prompt.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/books/tutorials/mailchain/prompt.md b/books/tutorials/mailchain/prompt.md index bbbd30a0..53331bca 100644 --- a/books/tutorials/mailchain/prompt.md +++ b/books/tutorials/mailchain/prompt.md @@ -63,7 +63,8 @@ heading:
    - +
    From 2189f5ca339de6c469c3ab84df925b2fff1ee518 Mon Sep 17 00:00:00 2001 From: Tim Boeckmann Date: Tue, 14 Feb 2023 14:02:10 +0000 Subject: [PATCH 4/9] update line numbers, formatting and flow --- books/tutorials/mailchain/prompt.md | 20 +++----------------- books/tutorials/mailchain/send.md | 2 +- books/tutorials/mailchain/setup.md | 5 +---- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/books/tutorials/mailchain/prompt.md b/books/tutorials/mailchain/prompt.md index 53331bca..f4e9eeec 100644 --- a/books/tutorials/mailchain/prompt.md +++ b/books/tutorials/mailchain/prompt.md @@ -26,11 +26,10 @@ module.exports = router; ``` Next, we need to add this route to the app. Open `'app.js'` and `require` the -newly created auth routes at line 10, below where `'routes/index'` is +newly created auth route at line 10, below where `'routes/index'` is `require`'d: ```js -var indexRouter = require('./routes/index'); var authRouter = require('./routes/auth'); ``` @@ -38,28 +37,15 @@ Continuing within `'app.js'`, use the newly `require`'d `authRouter` at line 27, below where `indexRouter` is `use`'d. ```js -app.use('/', indexRouter); app.use('/', authRouter); ``` -The login page has been added to our app! Let's see how it looks. +Now we will update the login page so the use can enter a Mailchain address. -Start the server: - -```sh -$ npm start -``` - -And open [http://localhost:3000](http://localhost:3000) and click "Sign in." We -are prompted to sign in, but there's no place to enter a Mailchain address. - -For that we need an HTML form. Let's add that now. - -Open `'views/login.ejs'` and add the form at line 15, below the "Sign in" +Open `'views/login.ejs'` and add the form at line 15, below `

    Sign in

    `. heading: ```html -

    Sign in

    diff --git a/books/tutorials/mailchain/send.md b/books/tutorials/mailchain/send.md index 1d361734..97eecc27 100644 --- a/books/tutorials/mailchain/send.md +++ b/books/tutorials/mailchain/send.md @@ -4,7 +4,7 @@ Now that we are prompting the user for their Mailchain address, and have the strategy configured, the next step is to send the user a Mailchain message when they click "Sign in with Mailchain." -Open `'routes/auth.js'`, add this route at line 57, below the `'/login'` route: +Open `'routes/auth.js'`, add this route at line 74, below the `'/login'` route: ```js router.post('/login/mailchain', passport.authenticate('magiclink', { diff --git a/books/tutorials/mailchain/setup.md b/books/tutorials/mailchain/setup.md index 5c4d472a..03ff3b5b 100644 --- a/books/tutorials/mailchain/setup.md +++ b/books/tutorials/mailchain/setup.md @@ -1,9 +1,6 @@ # Set Up Mailchain -Before we can let users sign in to our app with web3 email, we need a way to send -Mailchain messages. - -For that, we are going to use [Mailchain](https://mailchain.com/). +Now we need a way to send [Mailchain](https://mailchain.com/) messages from our app. For the purposes of this tutorial, we suggest you create a Mailchain account for testing. From 44d1c59996d539dee17c54d07378fd0f95f95d87 Mon Sep 17 00:00:00 2001 From: Tim Boeckmann Date: Tue, 14 Feb 2023 14:03:10 +0000 Subject: [PATCH 5/9] add method to sanitize mailchain addresses --- books/tutorials/mailchain/configure.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/books/tutorials/mailchain/configure.md b/books/tutorials/mailchain/configure.md index 597a09b8..0556c34e 100644 --- a/books/tutorials/mailchain/configure.md +++ b/books/tutorials/mailchain/configure.md @@ -28,7 +28,23 @@ Add the following code at line 8 to configure the `MagicLinkStrategy`. ``` var mailchain = Mailchain.fromSecretRecoveryPhrase(process.env.SECRET_RECOVERY_PHRASE); -let fromAddress = process.env['FROM_ADDRESS'] || await mailchain.user().address; +let fromAddress = async function fromAddress() { + return process.env['FROM_ADDRESS'] || mailchain.user().address; +} +let createMailchainAddress = function(address) { + switch (address) { + case address.match(/^[\d\w\-\_]*@mailchain\.com$/)?.input: // Mailchain address: + return address + case address.match(/^0x[a-fA-F0-9]{40}$/)?.input: // Ethereum address: + return address + '@ethereum.mailchain.com' + case address.match(/^.*\.eth$/)?.input: // ENS address: + return address + '@ens.mailchain.com' + case address.match(/^.*\.*@mailchain$/)?.input: // Mailchain address without .com: + return address + '.com' + default: + console.error("Invalid address"); + } +} passport.use(new MagicLinkStrategy({ secret: 'keyboard cat', // change this to something secret userFields: [ 'mailchain_address' ], @@ -38,7 +54,7 @@ passport.use(new MagicLinkStrategy({ var link = 'http://localhost:3000/login/mailchain/verify?token=' + token; var msg = { - to: [ user.mailchain_address ], + to: [ createMailchainAddress(user.mailchain_address) ], from: fromAddress, subject: 'Sign in to Todos', content: { @@ -50,19 +66,19 @@ passport.use(new MagicLinkStrategy({ }, function verify(user) { return new Promise(function(resolve, reject) { db.get('SELECT * FROM users WHERE mailchain_address = ?', [ - user.mailchain_address + createMailchainAddress(user.mailchain_address) ], function(err, row) { if (err) { return reject(err); } if (!row) { db.run('INSERT INTO users (mailchain_address, mailchain_address_verified) VALUES (?, ?)', [ - user.mailchain_address, + createMailchainAddress(user.mailchain_address,) 1 ], function(err) { if (err) { return reject(err); } var id = this.lastID; var obj = { id: id, - mailchain_address: user.mailchain_address + mailchain_address: createMailchainAddress(user.mailchain_address) }; return resolve(obj); }); From 59535ab1387cc289c22756dc3512c94ebe183e70 Mon Sep 17 00:00:00 2001 From: Tim Boeckmann Date: Tue, 14 Feb 2023 14:04:28 +0000 Subject: [PATCH 6/9] formatting --- books/tutorials/mailchain/README.md | 47 ++++++++++++++------------ books/tutorials/mailchain/configure.md | 37 ++++++++++++-------- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/books/tutorials/mailchain/README.md b/books/tutorials/mailchain/README.md index baae9869..a61aedd0 100644 --- a/books/tutorials/mailchain/README.md +++ b/books/tutorials/mailchain/README.md @@ -2,47 +2,52 @@ Mailchain is the communication layer for Web3 offering private, end-to-end encrypted email using blockchain wallet addresses and web3 identities (e.g. an Ethereum address, ENS name, Unstoppable -Domains name, etc.). Instead of users needing to sign data with a blockchain wallet, passwordless -authentication with magic links for Passport.js improves the safety of users: +Domains name, etc.). Instead of users needing to sign data with a blockchain wallet, _passwordless +authentication with magic links for Passport.js_ improves the safety of users. -* User signup and login without passwords or needing to sign data -* Supports magic links sent to ENS names, Ethereum addresses, Mailchain accounts and more -* Handles secure token generation, expiration and confirmation +Key feature include: -In this tutorial, we will build a todo list app in this tutorial, complete with functionality -that allows users to sign in with Mailchain. By following along with this tutorial, you will -learn how to use Passport for authentication. +- Users can signup and login to your application without passwords or needing to sign data with their wallets. +- Mailchain supports magic links sent to ENS names, Ethereum addresses, Mailchain accounts and more. +- Passport handles secure token generation, expiration and confirmation. + +In this tutorial, we will build a todo list app, complete with functionality +that allows users to sign in with Mailchain. By following along with this tutorial, you will +learn how to use Passport for passwordless authentication using Mailchain to send magic links. If you want to see where we are headed, here's an example of the final result: [https://github.com/passport/todos-express-mailchain](https://github.com/passport/todos-express-mailchain) -Before we dive in, you'll need a working development environment with [Node.js](https://nodejs.org/) -and [Git](https://git-scm.com/), as well as an editor and terminal of your -choosing. Take a moment to set up these tools if you have not already done so. +Before we dive in, you'll need: + +1. A working development environment with [Node.js](https://nodejs.org/) +and [Git](https://git-scm.com/) +1. An editor and terminal of your +choosing. +1. A [Mailchain](https://mailchain.com/) account. If you don't already have one, it's free to sign up. -You'll also need a [Mailchain](https://mailchain.com/) account. If you don't -already have one, it's free to sign up. +Take a moment to set these up if you have not already done so. Let's get started! We are going to start with a starter app, which has all the scaffolding needed -to build a todo list. Let's clone the app: +to build a todo list. Let's clone the app: ```sh $ git clone https://github.com/passport/todos-express-starter.git mailchain-tutorial ``` -You now have a directory named `'mailchain-tutorial'`. Let's `cd` into it: +You now have a directory named `'mailchain-tutorial'`. Let's `cd` into it: ```sh $ cd mailchain-tutorial ``` -Take a moment browse through the files in the starter app. As we work through +Take a moment browse through the files in the starter app. As we work through this tutorial, we'll be using [Express](https://expressjs.com/) as our web framework, along with [EJS](https://ejs.co/) as our template engine and [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) -for styling. We will use [SQLite](https://github.com/mapbox/node-sqlite3) as -our database for storing data. Don't worry if you are not familiar with these +for styling. We will use [SQLite](https://github.com/mapbox/node-sqlite3) as +our database for storing data. Don't worry if you are not familiar with these technologies -- the necessary code will be provided at each step. Now, let's install the dependencies: @@ -53,12 +58,12 @@ $ npm install And start the server: -``` +```sh $ npm start ``` -Let's check to see if its working. Open [http://localhost:3000](http://localhost:3000) -in your browser. You should be greeted with a page explaining how todos help +Let's check to see if its working. Open [http://localhost:3000](http://localhost:3000) +in your browser. You should be greeted with a page explaining how todos help you get things done. Next, we will [add a login page](prompt/) to the app. diff --git a/books/tutorials/mailchain/configure.md b/books/tutorials/mailchain/configure.md index 0556c34e..f098da3d 100644 --- a/books/tutorials/mailchain/configure.md +++ b/books/tutorials/mailchain/configure.md @@ -15,18 +15,17 @@ Open `'routes/auth.js'` and `require` the newly installed packages at line 2, below where `express` is `require`'d: ```js -var express = require('express'); -var passport = require('passport'); -var MagicLinkStrategy = require('passport-magic-link').Strategy; -var Mailchain = require('@mailchain/sdk').Mailchain; -var db = require('../db'); +var passport = require("passport"); +var MagicLinkStrategy = require("passport-magic-link").Strategy; +var Mailchain = require("@mailchain/sdk").Mailchain; +var db = require("../db"); ``` The app's database is also `require`'d. Add the following code at line 8 to configure the `MagicLinkStrategy`. -``` +```js var mailchain = Mailchain.fromSecretRecoveryPhrase(process.env.SECRET_RECOVERY_PHRASE); let fromAddress = async function fromAddress() { return process.env['FROM_ADDRESS'] || mailchain.user().address; @@ -90,17 +89,27 @@ passport.use(new MagicLinkStrategy({ })); ``` -This configures the `MagicLinkStrategy` to send mails containing a magic link -using Mailchain. When the user clicks on the magic link, the user record -associated with the Mailchain address will be found. If a user record does not -exist, one is created the first time someone signs in. +This configures the `MagicLinkStrategy` to sanitize the input address, then send +mails containing a magic link using Mailchain. When the user clicks on the magic +link, the user record associated with the Mailchain address will be found. If a +user record does not exist, one is created the first time someone signs in. -We also need to update our database scheme. Open `'db.js'` and insert the following at line 16: -``` +We also need to update our database scheme. Open `'db.js'` and insert the +following at line 16: + +```js mailchain_address TEXT UNIQUE, \ mailchain_address_verified INTEGER, \ ``` +We will now delete the database and re-create it. NOTE: This will delete any +data you may have added in this tutorial so far. If you are considering adding +this solution to an existing app, you would simply run a DB migration to alter +your `users` table. + +```sh +$ rm ./var/db/todos.db +``` -The strategy is now configured. Next we need to [send the user a magic link](../send/) -when they click "Sign in with Mailchain." \ No newline at end of file +The strategy is now configured. Next we need to +[send the user a magic link](../send/) when they click "Sign in with Mailchain" From f0d9a7655f9b29307aa3dc741df862e1344a5b5f Mon Sep 17 00:00:00 2001 From: Tim Boeckmann Date: Tue, 14 Feb 2023 14:06:24 +0000 Subject: [PATCH 7/9] Update configure.md --- books/tutorials/mailchain/configure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/books/tutorials/mailchain/configure.md b/books/tutorials/mailchain/configure.md index f098da3d..82d58fd9 100644 --- a/books/tutorials/mailchain/configure.md +++ b/books/tutorials/mailchain/configure.md @@ -70,7 +70,7 @@ passport.use(new MagicLinkStrategy({ if (err) { return reject(err); } if (!row) { db.run('INSERT INTO users (mailchain_address, mailchain_address_verified) VALUES (?, ?)', [ - createMailchainAddress(user.mailchain_address,) + createMailchainAddress(user.mailchain_address), 1 ], function(err) { if (err) { return reject(err); } From d717cf42bd96992a1484fe4132601ec3108fe413 Mon Sep 17 00:00:00 2001 From: Tim Boeckmann Date: Tue, 14 Feb 2023 14:11:27 +0000 Subject: [PATCH 8/9] Update verify.md --- books/tutorials/mailchain/verify.md | 101 ++++++++++++++-------------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/books/tutorials/mailchain/verify.md b/books/tutorials/mailchain/verify.md index f6f14140..f633a029 100644 --- a/books/tutorials/mailchain/verify.md +++ b/books/tutorials/mailchain/verify.md @@ -1,21 +1,25 @@ # Verify Mailchain Address -Now that we've sent the user a Mailchain message with a magic link, the next step is -to verify the Mailchain address when they click the link. +Now that we've sent the user a Mailchain message with a magic link, the next +step is to verify the Mailchain address when they click the link. -Open `'routes/auth.js'`, add this route at line 66, below the `'/login/mailchain/check'` -route: +Open `'routes/auth.js'`, add this route at line 66, below the +`'/login/mailchain/check'` route: ```js -router.get('/login/mailchain/verify', passport.authenticate('magiclink', { - successReturnToOrRedirect: '/', - failureRedirect: '/login' -})); +router.get( + "/login/mailchain/verify", + passport.authenticate("magiclink", { + successReturnToOrRedirect: "/", + failureRedirect: "/login", + }) +); ``` This route will verify the Mailchain address when the link is clicked. -Now create a folder and corresponding view for our route. Run the following commands: +Now create a folder and corresponding view for our route. Run the following +commands: ``` $ mkdir views/login/mailchain @@ -24,51 +28,50 @@ $ touch views/login/mailchain/check.ejs Open `'views/login/mailchain/check.ejs'`, add the following code: -``` - +```html + - - - - Express • TodoMVC - - - - - -
    -

    todos

    -

    Check your Mailchain Inbox

    -

    We sent a magic link to your Mailchain address. Click the link in that message to sign in.

    -
    -

    Didn't receive the message? Get another link

    -
    - - + + + + Express • TodoMVC + + + + + +
    +

    todos

    +

    Check your Mailchain Inbox

    +

    + We sent a magic link to your Mailchain address. Click the link in that + message to sign in. +

    +
    +

    + Didn't receive the message? Get another link +

    +
    + + ``` -Finally, update `'views/index.ejs'` at line 15 to include the `user.mailchain_address`: -``` -
  • <%= user.name || user.username || user.email || user.mailchain_address %>
  • -``` - -Let's test it out to see what happens. - -Start the server: +Finally, update `'views/index.ejs'` at line 15 to include the +`user.mailchain_address`: -```sh -$ npm start +```html +
  • <%= user.name || user.username || user.email || user.mailchain_address %>
  • ``` -Open [http://localhost:3000](http://localhost:3000), click "Sign in", enter your -Mailchain address and click "Sign in with Mailchain". - -Now, check your Mailchain inbox and click the link. +We have configured the flow for users to click "Sign in", enter a +Mailchain address or ENS name and click "Sign in with Mailchain", which will send a magic link. -Uh oh... we are informed that there's an error related to sessions. Next, we -will fix that by [establishing a session](../session/). +Now we need to [establish a session](../session/) for a user logging in. From 77dabddad3777703dbe33295db92b84b420cb8c5 Mon Sep 17 00:00:00 2001 From: Tim Boeckmann Date: Tue, 14 Feb 2023 19:33:28 +0000 Subject: [PATCH 9/9] Update line numbers --- books/tutorials/mailchain/configure.md | 29 +++-------------- books/tutorials/mailchain/session.md | 12 ++++--- books/tutorials/mailchain/setup.md | 45 +++++++++++++++++++------- books/tutorials/mailchain/verify.md | 4 ++- 4 files changed, 50 insertions(+), 40 deletions(-) diff --git a/books/tutorials/mailchain/configure.md b/books/tutorials/mailchain/configure.md index 82d58fd9..07890cb5 100644 --- a/books/tutorials/mailchain/configure.md +++ b/books/tutorials/mailchain/configure.md @@ -27,9 +27,7 @@ Add the following code at line 8 to configure the `MagicLinkStrategy`. ```js var mailchain = Mailchain.fromSecretRecoveryPhrase(process.env.SECRET_RECOVERY_PHRASE); -let fromAddress = async function fromAddress() { - return process.env['FROM_ADDRESS'] || mailchain.user().address; -} +var fromAddress = process.env['FROM_ADDRESS'] || mailchain.user().address; let createMailchainAddress = function(address) { switch (address) { case address.match(/^[\d\w\-\_]*@mailchain\.com$/)?.input: // Mailchain address: @@ -51,7 +49,7 @@ passport.use(new MagicLinkStrategy({ verifyUserAfterToken: true }, async function send(user, token) { var link = 'http://localhost:3000/login/mailchain/verify?token=' + token; - + var msg = { to: [ createMailchainAddress(user.mailchain_address) ], from: fromAddress, @@ -65,19 +63,19 @@ passport.use(new MagicLinkStrategy({ }, function verify(user) { return new Promise(function(resolve, reject) { db.get('SELECT * FROM users WHERE mailchain_address = ?', [ - createMailchainAddress(user.mailchain_address) + user.mailchain_address ], function(err, row) { if (err) { return reject(err); } if (!row) { db.run('INSERT INTO users (mailchain_address, mailchain_address_verified) VALUES (?, ?)', [ - createMailchainAddress(user.mailchain_address), + user.mailchain_address, 1 ], function(err) { if (err) { return reject(err); } var id = this.lastID; var obj = { id: id, - mailchain_address: createMailchainAddress(user.mailchain_address) + mailchain_address: user.mailchain_address }; return resolve(obj); }); @@ -94,22 +92,5 @@ mails containing a magic link using Mailchain. When the user clicks on the magic link, the user record associated with the Mailchain address will be found. If a user record does not exist, one is created the first time someone signs in. -We also need to update our database scheme. Open `'db.js'` and insert the -following at line 16: - -```js -mailchain_address TEXT UNIQUE, \ -mailchain_address_verified INTEGER, \ -``` - -We will now delete the database and re-create it. NOTE: This will delete any -data you may have added in this tutorial so far. If you are considering adding -this solution to an existing app, you would simply run a DB migration to alter -your `users` table. - -```sh -$ rm ./var/db/todos.db -``` - The strategy is now configured. Next we need to [send the user a magic link](../send/) when they click "Sign in with Mailchain" diff --git a/books/tutorials/mailchain/session.md b/books/tutorials/mailchain/session.md index ca6f93ec..e37217ca 100644 --- a/books/tutorials/mailchain/session.md +++ b/books/tutorials/mailchain/session.md @@ -15,7 +15,6 @@ Open `'app.js'` and `require` the additional dependencies at line 8, below where `'morgan'` is `require`'d: ```js -var logger = require('morgan'); var passport = require('passport'); var session = require('express-session'); @@ -26,7 +25,6 @@ Add the following code at line 29, after `express.static` middleware, to maintain and authenticate the session. ```js -app.use(express.static(path.join(__dirname, 'public'))); app.use(session({ secret: 'keyboard cat', resave: false, @@ -37,7 +35,7 @@ app.use(passport.authenticate('session')); ``` Finally, we need to configure Passport to manage the login session. Open -`'routes/auth.js'` and add the following code at line 53: +`'routes/auth.js'` and add the following code at line 70, below our Passport strategy: ```js passport.serializeUser(function(user, cb) { @@ -53,7 +51,13 @@ passport.deserializeUser(function(user, cb) { }); ``` -Now, let's retry signing in. Open [http://localhost:3000](http://localhost:3000), +Now, let's retry signing in. Start the server: + +```sh +$ npm start +``` + +Open [http://localhost:3000](http://localhost:3000), click "Sign in", enter your Mailchain address and click "Sign in with Mailchain". Now, check your Mailchain Inbox and click the link. diff --git a/books/tutorials/mailchain/setup.md b/books/tutorials/mailchain/setup.md index 03ff3b5b..72448591 100644 --- a/books/tutorials/mailchain/setup.md +++ b/books/tutorials/mailchain/setup.md @@ -1,32 +1,55 @@ # Set Up Mailchain -Now we need a way to send [Mailchain](https://mailchain.com/) messages from our app. +Now we need a way to send [Mailchain](https://mailchain.com/) messages from our +app. -For the purposes of this tutorial, we suggest you create a Mailchain account for testing. +For the purposes of this tutorial, we suggest you create a Mailchain account for +testing. -Navigate to [Mailchain](https://app.mailchain.com/register) and follow the steps to register. +Navigate to [Mailchain](https://app.mailchain.com/register) and follow the steps +to register. -You will be prompted to save your Secret Recovery Phrase, which we will use later. +You will be prompted to save your Secret Recovery Phrase, which we will use +later. You can also retrieve your Secret Recovery Phrase at any time by navigating to -**Settings > [Secret Recovery Phrase](https://app.mailchain.com/settings/security/)**. -Then click **View** and enter your password to retrieve your Secret Recovery Phrase. +**Settings > +[Secret Recovery Phrase](https://app.mailchain.com/settings/security/)**. Then +click **View** and enter your password to retrieve your Secret Recovery Phrase. -Save your Secret Recovery Phrase somewhere safe and private. We will use it later. +Save your Secret Recovery Phrase somewhere safe and private. We will use it +later. -Now that we have the Secret Recovery Phrase and a Mailchain address, let's create a -`'.env'` file to store them. +Now that we have the Secret Recovery Phrase and a Mailchain address, let's +create a `'.env'` file to store them. ```sh $ touch .env ``` -Add your FROM_ADDRESS and API key. The contents of the file should look something like -this: +Add your FROM_ADDRESS and API key. The contents of the file should look +something like this: ```sh FROM_ADDRESS=user@mailchain.com SECRET_RECOVERY_PHRASE=__INSERT_SECRET_RECOVERY_PHRASE__ ``` +We also need to update our database schema to store a user's Mailchain address +and verification status. Open `'db.js'` and insert the following at line 16: + +```js +mailchain_address TEXT UNIQUE, \ +mailchain_address_verified INTEGER, \ +``` + +We will now delete the database and re-create it. NOTE: This will delete any +data you may have added in this tutorial so far. If you are considering adding +this solution to an existing app, you would simply run a DB migration to alter +your `users` table. + +```sh +$ rm ./var/db/todos.db +``` + Next we will [configure the strategy](../configure/). diff --git a/books/tutorials/mailchain/verify.md b/books/tutorials/mailchain/verify.md index f633a029..545bb81b 100644 --- a/books/tutorials/mailchain/verify.md +++ b/books/tutorials/mailchain/verify.md @@ -3,7 +3,7 @@ Now that we've sent the user a Mailchain message with a magic link, the next step is to verify the Mailchain address when they click the link. -Open `'routes/auth.js'`, add this route at line 66, below the +Open `'routes/auth.js'`, add this route at line 83, below the `'/login/mailchain/check'` route: ```js @@ -58,6 +58,8 @@ Open `'views/login/mailchain/check.ejs'`, add the following code:

    Authentication powered by Passport +
    + & Mailchain