Noiseless Peaceful Morning

    This package has been deprecated

    Author message:

    All packages in the @keystone-alpha namespace are now available in the @keystonejs namespace, starting at version 5.0.0. To upgrade, update package.json to point to "@keystonejs/passport-auth": "^5.0.0" and update any require/import statements in your code.

    @keystone-alpha/passport-auth

    2.1.1 • Public • Published

    Passport Auth Strategy

    Enable KeystoneJS authentication via services such as Google, Twitter, Facebook, GitHub, and any others supported by passport.js.

    Authentication Flows

    This package enables three authentication flows;

    1. Single Step Account Creation & Authentication
    2. Multi Step Account Creation & Authentication
    3. Existing Account Authentication

    Single Step Account Creation & Authentication

    When creating a new account in KeystoneJS, the service (Google, Twitter, etc) provides some basic user information such as name and, if enabled, email. Often this information alone is enough to create a new KeystoneJS account, so it is the default authentication flow known as Single Step Account Creation.

    For example, when logging in with Google, the user will;

    • Click "Login with Google"
    • Be redirected to google.com's authentication page if not already logged in
    • Be asked to grant permission for your KeystoneJS app
    • Be redirected to your application's callback URL
    • This package will create a new account & authenticate the user, then trigger onAuthenticated() (see the API docs below)

    Multi Step Account Creation & Authentication

    Sometimes the information provided by the service is not enough to create a new account in KeystoneJS. For example, your application may require the user's age, or want to confirm the email address provided by the service.

    The default Single Step Flow can be extended to pause account creation while we gather the extra information from the user. Pausing even works across page refreshes. This is known as Multi Step Account Creation.

    For example, when logging in with Google, the user will (differences from the Single Step Flow are bolded):

    • Click "Login with Google"
    • Be redirected to google.com's authentication page if not already logged in
    • Be asked to grant permission for your KeystoneJS app
    • Be redirected to your application's callback URL
    • Be redirected to a form to gather more information
    • Submit the form which will resume account creation & authentication
    • This package will create a new account & authenticate the user, then trigger onAuthenticated() (see the API docs below)

    Existing Account Authentication

    When a user has previously created an account via a given service, this package will use information stored in the idField (see the API docs below) to match the account and authenticate them:

    • Click "Login with Google"
    • Be redirected to google.com's authentication page if not already logged in
    • Be redirected to your application's callback URL
    • This package will authenticate the existing user, then trigger onAuthenticated() (see the API docs below)

    API

    Usage

    Single Step With Google

    NOTE: The below can be done with any of the supported strategies (Twitter, Facebook, etc).

    To run this example: keystone dev, then visit http://localhost:3000/auth/google to start the Google authentication process.

    index.js

    const { Keystone } = require('@keystone-alpha/keystone');
    const { MongooseAdapter } = require('@keystone-alpha/adapter-mongoose');
    const { GraphQLApp } = require('@keystone-alpha/app-graphql');
    const { AdminUIApp } = require('@keystone-alpha/app-admin-ui');
    
    const { GoogleAuthStrategy } = require('@keystone-alpha/passport-auth');
    
    const cookieSecret = '<Something super secret>';
    
    const keystone = new Keystone({
      name: 'Login With Google Example',
      adapter: new MongooseAdapter(),
    });
    
    keystone.createList('User', {
      fields: {
        name: { type: Text },
        email: { type: Text },
    
        // This field name must match the `idField` setting passed to the auth
        // strategy constructor below
        googleId: { type: Text },
      },
    });
    
    const googleStrategy = keystone.createAuthStrategy({
      type: GoogleAuthStrategy,
      list: 'User',
      config: {
        idField: 'googleId',
        appId: '<Your Google App Id>',
        appSecret: '<Your Google App Secret>',
        cookieSecret,
        hostURL: 'http://localhost:3000',
        apiPath: '/admin/api',
        loginPath: '/auth/google',
        callbackPath: '/auth/google/callback',
    
        // Once a user is found/created and successfully matched to the
        // googleId, they are authenticated, and the token is returned here.
        // NOTE: By default KeystoneJS sets a `keystone.sid` which authenticates the
        // user for the API domain. If you want to authenticate via another domain,
        // you must pass the `token` as a Bearer Token to GraphQL requests.
        onAuthenticated: (token, req, res) => {
          console.log(token);
          res.redirect('/');
        },
    
        // If there was an error during any of the authentication flow, this
        // callback is executed
        onError: (error, req, res) => {
          console.error(error);
          res.redirect('/?error=Uh-oh');
        },
      },
    });
    
    module.exports = {
      keystone,
      apps: [new GraphQLApp({ cookieSecret }), new AdminUIApp()],
    };

    Multi Step With Google

    NOTE: The below can be done with any of the supported strategies (Twitter, Facebook, etc).

    Due to the extra route used for gathering the user's name, this example implements an All-in-one Custom Server and should be run with node server.js, then visit http://localhost:3000/auth/google to start the Google authentication process.

    server.js

    const { Keystone } = require('@keystone-alpha/keystone');
    const { MongooseAdapter } = require('@keystone-alpha/adapter-mongoose');
    const { GraphQLApp } = require('@keystone-alpha/app-graphql');
    const { AdminUIApp } = require('@keystone-alpha/app-admin-ui');
    const express = require('express');
    
    const { GoogleAuthStrategy } = require('@keystone-alpha/passport-auth');
    
    const cookieSecret = '<Something super secret>';
    
    const keystone = new Keystone({
      name: 'Login With Google Example',
      adapter: new MongooseAdapter(),
    });
    
    keystone.createList('User', {
      fields: {
        name: { type: Text },
        email: { type: Text },
    
        // This field name must match the `idField` setting passed to the auth
        // strategy constructor below
        googleId: { type: Text },
      },
    });
    
    const googleStrategy = keystone.createAuthStrategy({
      type: GoogleAuthStrategy,
      list: 'User',
      config: {
        idField: 'googleId',
        appId: '<Your Google App Id>',
        appSecret: '<Your Google App Secret>',
        cookieSecret,
        hostURL: 'http://localhost:3000',
        apiPath: '/admin/api',
        loginPath: '/auth/google',
        callbackPath: '/auth/google/callback',
    
        loginPathMiddleware: (req, res, next) => {
          // An express middleware executed before the Passport social signin flow
          // begins. Useful for setting cookies, etc.
          // Don't forget to call `next()`!
          next();
        },
    
        callbackPathMiddleware: (req, res, next) => {
          // An express middleware executed before the callback route is run. Useful
          // for logging, etc.
          // Don't forget to call `next()`!
          next();
        },
    
        // Called when there's no existing user for the given googleId
        // Default: resolveCreateData: () => ({})
        resolveCreateData: ({ createData, actions: { pauseAuthentication } }, req, res) => {
          // If we don't have the right data to continue with a creation
          if (!createData.name) {
            // then we pause the flow
            pauseAuthentication();
            // And redirect the user to a page where they can enter the data.
            // Later, the `resolveCreateData()` method will be re-executed this
            // time with the complete data.
            res.redirect(`/auth/google/step-2`);
            return;
          }
    
          return createData;
        },
    
        // Once a user is found/created and successfully matched to the
        // googleId, they are authenticated, and the token is returned here.
        // NOTE: By default KeystoneJS sets a `keystone.sid` which authenticates the
        // user for the API domain. If you want to authenticate via another domain,
        // you must pass the `token` as a Bearer Token to GraphQL requests.
        onAuthenticated: (token, req, res) => {
          console.log(token);
          res.redirect('/');
        },
    
        // If there was an error during any of the authentication flow, this
        // callback is executed
        onError: (error, req, res) => {
          console.error(error);
          res.redirect('/?error=Uh-oh');
        },
      },
    });
    
    keystone
      .prepare({
        apps: [new GraphQLApp({ cookieSecret }), new AdminUIApp()],
        dev: process.env.NODE_ENV !== 'production',
      })
      .then(async ({ middlewares }) => {
        await keystone.connect();
        const app = express();
        app.use(middlewares);
    
        // Sample page to collect a name, submits to the completion step which will
        // create a user
        app.use(`/auth/google/step-2`, express.urlencoded({ extended: true }), (req, res, next) => {
          if (req.method === 'POST') {
            const { name } = req.body;
            // Continue the authentication flow with additional data the user
            // submitted.
            // This data is merged into other data required by Keystone and will
            // trigger the resolveCreateData() method again.
            return googleStrategy.resumeAuthentication({ name }, req, res, next);
          }
    
          res.send(`
              <form method="post">
                <label>
                  What is your name? <input type="text" name="name" />
                </label>
                <button type="submit">Submit</button>
              </form>
            `);
        });
    
        app.listen(port, error => {
          if (error) throw error;
          console.log(`Ready. App available at http://localhost:${port}`);
        });
      })
      .catch(error => {
        console.error(error);
        process.exit(1);
      });

    Using other PassportJs Strategies

    You can create your own strategies to work with KeystoneJS by extending the PassportAuthStrategy class:

    const PassportWordPress = require('passport-wordpress').Strategy;
    const { PassportAuthStrategy } = require('@keystone-alpha/passport-auth');
    
    class WordPressAuthStrategy extends PassportAuthStrategy {
      constructor(keystone, listKey, config) {
        super(WordPressAuthStrategy.authType, keystone, listKey, config, PassportWordPress);
      }
    }
    
    WordPressAuthStrategy.authType = 'wordpress';
    
    module.exports = WordPressAuthStrategy;

    Keywords

    none

    Install

    npm i @keystone-alpha/passport-auth

    DownloadsWeekly Downloads

    0

    Version

    2.1.1

    License

    MIT

    Unpacked Size

    33 kB

    Total Files

    9

    Last publish

    Collaborators

    • dominikwilkowski
    • jedwatson
    • jesstelford
    • mitchellhamilton
    • molomby
    • nathansimpson95
    • timl