Ghost/ghost/magic-link
Fabien 'egg' O'Carroll 6957c2725b Refactored magic-link to be more generic (#202)
no-issue

This removes the concept of `subject` & `payload` from the function
signatures, making the implementation a little more generic, and less
JWT centric.

We also replace getUserFromToken and getPayloadFromToken with a single
method getDataFromToken, which will contain all the necessary data.

* Updated members-api to use new magic-link module

This updates the usage of magic-link to work with the new interface

* Fixed labels not saving for new members

Due to how bookshelf-relations works, we must fetch the labels before
saving a member, otherwise the labels are all deleted.

* Used a proper class rather than constructor function

This just moves the code to a more modern standard

* Updated methods to be async

This prepares us for a future where token generation and validation may
require access to storage and thus be an asyncronous operation
2020-09-17 15:42:01 +01:00
..
test Refactored magic-link to be more generic (#202) 2020-09-17 15:42:01 +01:00
.eslintrc.js Created @tryghost/magic-link module (#50) 2019-09-03 11:07:03 +08:00
index.js Refactored magic-link to be more generic (#202) 2020-09-17 15:42:01 +01:00
LICENSE 2020 2020-01-07 19:06:08 +00:00
package.json Published new versions 2020-08-11 09:10:32 +01:00
README.md Refactored magic-link to be more generic (#202) 2020-09-17 15:42:01 +01:00
tsconfig.json Created @tryghost/magic-link module (#50) 2019-09-03 11:07:03 +08:00

Magic Link

Install

npm install @tryghost/magic-link --save

or

yarn add @tryghost/magic-link

Usage

const util = require('util');
const crypto = require('crypto');
const nodemailer = require('nodemailer');
const MagicLink = require('@tryghost/magic-link');

async function main() {
    const generateKeyPair = util.promisify(crypto.generateKeyPair);
    const {publicKey, privateKey} = await generateKeyPair('rsa', {
        modulusLength: 4096,
        publicKeyEncoding: {
            type: 'pkcs1',
            format: 'pem'
        },
        privateKeyEncoding: {
            type: 'pkcs1',
            format: 'pem'
        }
    });

    // https://nodemailer.com/about/#example
    const testAccount = await nodemailer.createTestAccount();

    const transporter = nodemailer.createTransport({
        host: 'smtp.ethereal.email',
        port: 587,
        secure: false, // true for 465, false for other ports
        auth: {
            user: testAccount.user, // generated ethereal user
            pass: testAccount.pass // generated ethereal password
        }
    }, {
        from: '"Your App" <signin@example.com>',
        subject: 'Whatever'
    });

    const service = MagicLink({
        transporter,
        publicKey,
        privateKey,
        getSigninURL(token) {
            return `http://example.com/signin?token=${token}`
        }
    });

    /**
     *  POST /signin
     */
    const {url, info} = await service.sendMagicLink({
        email: 'test@example.com',
        tokenData: {
            id: 'some-id'
        }
    });

    // https://nodemailer.com/about/#example
    // Preview only available when sending through an Ethereal account
    console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
    // Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...

    /**
     *  GET /signin
     */
    const data = await service.getDataFromToken(token);
    // createSomeKindOfSession(user);
}

main();

Develop

This is a mono repository, managed with lerna.

Follow the instructions for the top-level repo.

  1. git clone this repo & cd into it as usual
  2. Run yarn to install top-level dependencies.

Run

  • yarn dev

Test

  • yarn lint run just eslint
  • yarn test run lint and tests

Copyright & License

Copyright (c) 2013-2020 Ghost Foundation - Released under the MIT license.