npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@tygr/auth-server

v2.0.3

Published

Authentication middleware for tygr

Downloads

5

Readme

This package has moved to @taylorgrinn/auth-server

Tygr Auth Server Middleware

This is an express middleware and router to be used with the @tygr/auth react component.

Installation

npm i --save @tygr/auth-server
yarn add @tygr/auth-server

Add the middleware and router to your app

import bodyParser from 'body-parser';
import express from 'express';
import useAuth from '@tygr/auth-server';

const [authMiddleware, authRouter] = useAuth({
  // Provide a secret key or list of keys to use for creating sessions.
  secret: 'ssshhh',
  // In order to implement the reset password form, use this option to send
  // an email using nodemailer or another email solution. Must return a promise
  async sendCode(email, code) {
    console.log(`Emailing code: ${code} to ${email}`);
    /* Implementation not shown */
  },
  delay: 1000, // Add an optional delay to all authentication requests. Useful for preventing brute force attacks from a single IP or just letting users appreciate your loading screens.
});

const app = express();
export default app;

app.use(
  bodyParser.json(), // JSON necessary to parse requests from the @tygr/auth react component
  authMiddleware
);

app.use('/auth', authRouter);

This is all the setup you need for a minimal working example with local login, register, and reset password functionality.

Setup the external providers (Google, Github, Facebook)

Create API keys for each or any of the services:

Add the keys, as well as the external location of your authentication server, to the useAuth options:

const [authMiddleware, authRouter] = useAuth({
  ...,
  authBaseUrl: 'https://tygr.info/api/auth', // Used for callbacks after authentication
  google: {
    clientId: 'blahblahblah',
    clientSecret: 'blahblahblah',
    scope: [], // Optional: scopes allow you to get more user information
  },
  github: {
    clientId: 'blahblahblah',
    clientSecret: 'blahblahblah',
    scope: [], // Optional: scopes allow you to get more user information
  },
  facebook: {
    clientId: 'blahblahblah',
    clientSecret: 'blahblahblah',
    scope: [], // Optional: scopes allow you to get more user information
    profileFields: [] // Optional: profile fields need to be specified for user object
  }
});

...

/**
 * Make sure to include the pathname you decide to use here ('/auth')
 * in the `authBaseUrl` option above.
 */
app.use('/auth', authRouter)

For the scope options, the email scope is already included in all authentication requests by default for both github and google.

When creating the keys for each provider, you'll also have to specify the callback urls in this format:

  • Google: `${authBaseUrl}/google/callback`
  • Github: `${authBaseUrl}/github/callback`
  • Facebook: `${authBaseUrl}/facebook/callback`

Setup better storage options

By default, the sessions and user data are stored in-memory. This is volatile and not recommended for production use. You may pass in a store for the sessions and a Users model for storing users.

The store interface is described here in the express-session library.

The Users interface defines what will probably be static methods on your Users' model class. I designed it specifically to work with sequelize right out of the gate, but it can be adapted for any storage mechanism you'd like. There are five methods to implement and four required fields on the User object.


BaseUser (You may add any other properties you'd like) | property | type | description | | -------- | --------------------- | ---------------------------------------------------------------------------- | | id | string | Unique identifier generated by uuid. This should be the 'primary key' | | email | string | Unique email address for each user. | | password | string (or undefined) | Hashed password for the user if they signed in locally | | provider | string | The authentication method (either 'local', 'google', or 'github') |


BaseUsers | method | param | returns | description | | -------------- | --------- | --------------------- | ----------------------------------------------------------------------------------------------------------- | | create | User | Promise<User> | Create a new user. No need to check if the user already exists. For sequelize, no setup is necessary as the base model includes this method with the correct signature, given that the model extends the BaseUser interface correctly | | findByEmail | string | Promise<User | null> | Find a user account by an email address | | findAndUpdate | User | Promise<any> | Find a user using the id, which will not change, and update the rest of the user properties | | findAndDestroy | User | Promise<any> | Find a user using either the id or email then delete them | | sanitize | User | Partial<User> | Synchronously create a user object that is safe to be sent back to the user. The password hash should be removed at least |

All Options

Order of precedence: env var > option > default
Array environment variables are comma separated: MY_VAR=thing1,thing2

| option | required | env var | type | description | | ---------------------- | --------------------- | ----------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | secret | required | AUTH_SECRET | string | string[] | Provide a secret key or list of keys to use for creating sessions | | sendCode | required | | (emailAddress: string, code: string) => Promise<any> | Send a reset code to a specified email address. The user can then copy this code into the reset password form to recover access to their account | | store | recommended | | See here | Provide a store to use for session data. Defaults to an in memory store which is not recommended for a production environment | | Users | recommended | | See above | Provide a Users model to store user data. Defaults to an in memory Users model which is not recommended for a production environment | | delay | optional | AUTH_DELAY | number | Milliseconds to delay each request to the auth server. | | cors | optional | CORS | boolean (string[] if using env var) | Set the cookie properties: sameSite: true, secure: true. This will allow cookies to be loaded from any domain and requires the authentication server to be served over https. See the demo folder for an example of serving https://localhost using custom certificates. See below for more info | | httpOnly | optional | HTTP_ONLY | boolean | Whether the cookie willl have the httpOnly flag. True, by default. | | authBaseUrl | optional | AUTH_BASE_URL | string | The external address of your authentication server. This option is required for an identity provider like google or github to redirect users back after signing in but not for local sign in, register or reset password | | google.clientID | required for google | GOOGLE_CLIENT_ID | string | Client ID given by Google. | | google.clientSecret | required for google | GOOGLE_CLIENT_SECRET | string | Client secret given by Google. | | google.scope | optional | GOOGLE_SCOPE | string[] | Scope of information or abilities to be requested by you to the user for their Google account. The 'email' scope is added to all requests in addition to any you specify here | | github.clientID | required for github | GITHUB_CLIENT_ID | string | Client ID given by Github. | | github.clientSecret | required for github | GITHUB_CLIENT_SECRET | string | Client secret given by Github. | | github.scope | optional | GITHUB_SCOPE | string[] | Scope of information or abilities to be requested by you to the user for their Github account. The 'user:email' scope is added to all requests in addition to any you specify here | | facebook.clientID | required for facebook | FACEBOOK_CLIENT_ID | string | Client ID given by Facebook. | | facebook.clientSecret | required for facebook | FACEBOOK_CLIENT_SECRET | string | Client secret given by Facebook. | | facebook.scope | optional | FACEBOOK_SCOPE | string[] | Scope of information or abilities to be requested by you to the user for their Facebook account. The 'email' scope is added to all requests in addition to any you specify here | | facebook.profileFields | optional | FACEBOOK_PROFILE_FIELDS | string[] | Profile fields to include when authenticating. The 'email' field is added to all requests in addition to any you specify here |

Setup cors for cross-domain authentication

If your authentication server is on a different domain than your client, or you have multiple clients logging in to the same authentication server, you can use the cors middleware and the cors option:

import useAuth, { cors } from '@tygr/auth-server';


const [authMiddleware, authRouter] = useAuth({
  ...,
  cors: true,
});

app.use(cors('https://tygr.info', 'http://localhost:8081'));

The cors middleware takes in any number of whitelisted domains and adds the relevant headers to all requests from each of them.

The cors option changes the way cookies are set. Specifically, it makes them available on any domain and makes them secure, only available when the authentication server is served over https. Check out the demo folder to see an example of serving https://localhost with a self-signed certificate.

If the CORS environment variable is set, the cors options will be set to true and the whitelist will be set to the comma-separated list value of the CORS environment variable:

# .env file (or however you set env vars)
CORS=https://tygr.info,http://localhost:8081
/**
 * You still have to use the cors middleware but the whitelist
 * will be supplied by the environment variable
 */
app.use(cors());