7.0 KiB
auth-server-helper
version: 4.0.x
customizable and simple authentication
Installation
npm:
npm i --save auth-server-helper
yarn:
yarn add auth-server-helper
Usage
1. put a gateway in front of the routes you want to secure
const {create_gateway} = require('@sapphirecode/auth-server-helper');
const gateway = create_gateway({
redirect_url: '/auth', // if defined, unauthorized requests will be redirected
cookie: { name: 'auth_cookie' }, // if defined, access tokens will be read from or written to this cookie,
refresh_cookie: { name: 'refresh_cookie' }, // if defined, refresh tokens will be read and used to automatically refresh client tokens (requires the refresh_settings attribute)
refresh_settings: {
// same as settings for allow_access under section 2
// the options data, redirect_to and leave_open are not supported here
}
});
// express
app.use(gateway);
// node http
http.createServer((main_req, main_res) =>
gateway(main_req, main_res, (req, res) => {
// your request handler
});
);
the gateway will forward any authorized requests to the next handler and redirect all others to the specified url
1.1. Creating a gateway for manual processing of requests
const {GatewayClass} = require('@sapphirecode/auth-server-helper');
const gateway = new GatewayClass({ /* options */ }); // options are the same as for create_gateway above
// process a request
if (gateway.authenticate(http_request)) { // returns true if request is valid and sets req.connection.token_id and .token_data
console.log('access granted');
} else {
gateway.redirect(response); // redirects the client, triggers deny if no redirect_url was set in options
// or
gateway.deny(response); // sends status 403
}
2. creating the auth endpoint
const {create_auth_handler} = require('@sapphirecode/auth-server-helper');
const handler = create_auth_handler(
async (req) => {
if (req.user === 'foo' && req.password === 'bar')
const {access_token_id, refresh_token_id} = await req.allow_access({
access_token_expires_in: 600, // seconds until access tokens expire
include_refresh_token: true, // should the answer include a refresh token? default: false
refresh_token_expires_in: 3600, // seconds until refresh tokens expire (required if refresh tokens are generated)
data: {user: 'foo'}, // additional custom data to include in the token
});
if (req.user === 'part' && req.password === 'baz')
const part_id = await req.allow_part(
60, // seconds until part_token expires
'some_module', // next module handler (defined below)
{foo: 'bar'} // custom data to attach to the token
);
// all allow_ functions return a token id, which can later be used to invalidate specific tokens from the server side
req.deny();
},
{
refresh: {
/*...same options as allow_access */
}, // define the behaviour of refresh tokens. Refresh tokens will not be accepted if this option is undefined
modules: {
some_module(req) {
// request handlers for part_tokens
// access custom data:
const auth_data = req.request.connection.auth;
auth_data.token_id; // token id
auth_data.token_data; // custom data
// the same works in handlers after the gateway, information is always stored in request.connection.auth
},
},
cookie: { name: 'auth_cookie' }, // if defined, access tokens will be stored in this cookie,
refresh_cookie: { name: 'refresh_cookie' }, // if defined, refresh tokens will be stored in this cookie
parse_body: true // read the request body into a string (default false)
}
);
// express
app.use(handler);
// node http
// ... create server, on path /auth run the handler
handler(req, res); // the handler will also return true if allow_access or allow_part was called
after the auth handler, the request will be completed, no additional content should be served here. (Read 2.1 for info on disabling this)
2.1. Processing Auth Requests without closing the response object
to prevent the auth handler from closing the response object you can provide additional options on each of the allow/deny functions.
allow_access({leave_open: true, ...});
allow_part(
60,
'some_module',
{foo: 'bar'},
true // additional flag to leave request open
);
invalid('error description', true);
deny(true);
if this flag is set, no data will be written to the response body and no data will be sent. Status code and Headers will still be set.
Defining Custom Cookie Settings
By default all cookies will be sent with 'Secure; HttpOnly; SameSite=Strict' Attributes
In the appropriate settings object, you can set the following options:
{
name: 'foo', // name of the cookies
secure: true, // option to enable or disable the Secure option default: true
http_only: true, // option to enable or disable HttpOnly default: true
same_site: 'Strict', // SameSite property (Strict, Lax or None) default: 'Strict'. Set this to null to disable
expires: 'Mon, 10 Jan 2022 09:28:00 GMT', // Expiry date of the cookie
max_age: 600, // Maximum age in Seconds
domain: 'example.com', // Domain property
path: '/cookies_here' // Path property
}
For Documentation on the different Cookie Attributes see https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#creating_cookies
Invalidating tokens after they are delivered to the client
const {blacklist} = require('@sapphirecode/auth-server-helper');
await blacklist.add_signature(token_id); // the token id is returned from any function that creates tokens
Logout function
const {logout} = require('@sapphirecode/auth-server-helper');
// create a new express route
app.get('logout',(req,res)=>{
// call the gateway's logout function
gateway.logout(req);
// respond ok
res.status(200);
res.end();
})
Exporting and importing public keys to validate tokens across server instances
const {keystore} = require('@sapphirecode/auth-server-helper');
const export = keystore.export_verification_data();
// second instance
keystore.import_verification_data(export);
These keys can also be live synchronized with redis to allow sessions to be shared between servers
const {keystore} = require('@sapphirecode/auth-server-helper');
keystore.sync_redis('redis://localhost');
Exporting and importing blacklist entries across server instances
const {blacklist} = require('@sapphirecode/auth-server-helper');
const export = blacklist.export_blacklist();
// second instance
blacklist.import_blacklist(export);
Clearing Keystore and Blacklist
Resetting the Keystore instance generates a new instance id and deletes all imported or generated keys.
const {keystore, blacklist} = require('@sapphirecode/auth-server-helper');
// clear keystore
keystore.reset_instance();
// clear blacklist
await blacklist.clear();
// clear blacklist items older than 10 seconds
await blacklist.clear(Date.now() - 10000);
License
MIT © Timo Hocker timo@scode.ovh