# auth-server-helper version: 3.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 ```js 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 ```js 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 ```js 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 } ); // 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. ```js 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: ```js { 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 ### Invalidating tokens after they are delivered to the client ```js const {blacklist} = require('@sapphirecode/auth-server-helper'); blacklist.add_signature(token_id); // the token id is returned from any function that creates tokens ``` ### Exporting and importing public keys to validate tokens across server instances ```js const {keystore} = require('@sapphirecode/auth-server-helper'); const export = keystore.export_verification_data(); // second instance keystore.import_verification_data(export); ``` ### Exporting and importing blacklist entries across server instances ```js 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. ```js const {keystore, blacklist} = require('@sapphirecode/auth-server-helper'); // clear keystore keystore.reset_instance(); // clear blacklist blacklist.clear(); // clear blacklist items older than 10 seconds blacklist.clear(Date.now() - 10000); ``` ## License MIT © Timo Hocker