@taylorgrinn/auth-mysql-redis
TypeScript icon, indicating that this package has built-in type declarations

1.0.0-alpha.1 • Public • Published

Tay Auth MySQL Redis

This is an express authentication server meant to be used with Nginx's auth_request command.

Installation

npm i --save @taylorgrinn/auth-mysql-redis
yarn add @taylorgrinn/auth-mysql-redis

Usage

Use the default async function to create an authentication server.

const createServer = require('@taylorgrinn/auth-mysql-redis').default;

const PORT = 8080;

createServer({
  secret: 'sshhhh',
}).then((auth) =>
  auth.listen(PORT, () => console.log(`Auth server listening on port ${PORT}.`))
);

The secret option or AUTH_SECRET environment variable must be set.

By default, it will use an in-memory store and Users model which will be cleared every time the server restarts.

To connect to a Redis instance, either supply the option redis.url or the environment variable REDIS_URL.

To connect to a MySQL server, specify both the host and database using either mysql.host or MYSQL_HOST and either mysql.database or MYSQL_DB.

createServer({
  secret: 'sssshhh',
  redis: {
    url: 'redis://localhost:6379',
  },
  mysql: {
    host: 'localhost',
    database: 'tay_dev',
  },
});

The server will send a 401 Unauthorized status code for anyone not logged in and a 200 Success status code otherwise. To customize this behavior, pass in a verify RequestHandler. Within this handler, req.user will contain the user info.

createServer({
  secret: 'ssshhhh',
  verify(req, res) {
    console.log('Verifying request', req.originalUrl);
    if (req.user.email === 'taylor@mail.com') res.sendStatus(200);
    else res.sendStatus(403);
  },
});

Nginx setup

Create an internal location for verifying requests using the auth server.

location = /verify {
    internal;
    proxy_pass http://localhost:8080/verify$request_uri;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
}

Where localhost:8080 is the location of the authentication server accessible to Nginx.

In order to login or register an account, you'll need to expose the /auth REST API from the authentication server.

location /auth {
    proxy_pass http://localhost:8080/auth;
}

You can use auth_request /verify; to protect any location.

location / {
    auth_request /verify;
    index index.html;
    try_files $uri $uri.html $uri/ =404;
}

Finally you'll need to build a portal which will be served when a 401 status is received from the authentication server.

location = /portal.html {
    internal;
}

error_page 401 /portal.html;

portal.html must exist at the root of the website and should allow users to login or register an account.

You can see an example of all this together at demo/nginx.conf

Setup the external providers (Google, Github, Facebook)

In order to set up external providers, the authBaseUrl option or AUTH_BASE_URL environment variable must be set to the publicly available address of the auth REST API. In the Nginx config above, it is available at /auth, so the authBaseUrl will be https://taydev.org/auth.

Create API keys for each or any of the services:

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`

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

createServer({
  ...,
  authBaseUrl: 'https://taydev.org/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
  }
});

For the scope options, the email scope is already included in all authentication requests by default.

Auth Server 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.
verify optional express.RequestHandler This handler will be called for each authentication request from the web server. It should call res.sendStatus(403) for forbidden requests or res.sendStatus(200) for an allowed request. If a request is not handled (ie next() was called), a 200 Success response will be sent.
sendCode optional (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
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 required for external 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

Redis Options

option required env var type description
redis.url required REDIS_URL string The Redis connection url to use.
redis.user optional REDIS_USER string The user to log in to the Redis instance as.
redis.password optional REDIS_PASSWORD string Password to use for connecting to the Redis instance.
redis.name optional REDIS_NAME string A name to assign the Redis connection.
redis.database optional REDIS_DB number The database to connect to [0-15]
redis.ttl optional REDIS_TTL number The number of seconds a session should last (1 day by default).
redis.prefix optional REDIS_PREFIX string A string to prepend each session in the Redis database (sess: by default).

Other options are documented in RedisClientOptions from the @redis/client package and RedisStoreOptions from the connect-redis package.

MySQL Options

When connecting to MySQL, this library creates a users table in the configured database. The host and database are required options.

option required env var type description
mysql.host required MYSQL_HOST string The hostname to connect to.
mysql.port optional MYSQL_PORT number The port the MySQL server is running on.
mysql.user optional MYSQL_USER string The username to use for the MySQL server.
mysql.password optional MYSQL_PASS string The password to use for the MySQL server.
mysql.database required MYSQL_DB string The database to create the 'users' table in.

Other options are specified in PoolOptions from the mysql2 package.

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 option or the CORS environment variable.

createServer({
  ...,
  cors: ['https://taydev.org', 'https://localhost:8081'],
});

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

The cors option or CORS environment variable 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 whitelist will be set to the comma-separated list value.

# .env file (or however you set env vars)
CORS=https://taydev.org,https://localhost:8081

/auth REST API

The auth server accepts application/json, multipart/form-data, and application/x-www-form-urlencoded bodies. The JSON format is shown below.

route method body return description
/register POST { email: string, password: string } User Register a new account.
/login POST { email: string, password: string } User Login to an existing account.
/verify GET User Verify that you are logged in an access the current user.
/logout PUT { success: boolean } Logout of the current account.
/user DELETE { success: boolean } Delete the current user account

Add a login link for each external provider configured (google, facebook, or github). The query paramter redirect is required and should be URI encoded.

<a href="/auth/google?redirect=https%3A%2F%2Ftaydev.org">Google Login</a>

In order to come back to the current page after authentication, use location.href for the redirect.

<script>
  function authFacebook() {
    const redirect = encodeURIComponent(location.href);
    location.href = '/auth/facebook?redirect=' + redirect;
  }
</script>
<button onclick="authFacebook()">Facebook Login</button>

Readme

Keywords

Package Sidebar

Install

npm i @taylorgrinn/auth-mysql-redis

Weekly Downloads

0

Version

1.0.0-alpha.1

License

ISC

Unpacked Size

35.4 kB

Total Files

10

Last publish

Collaborators

  • taylorgrinn