import { IncomingMessage, ServerResponse } from 'http'; import auth from './Authority'; interface AccessSettings { access_token_expires_in?: number include_refresh_token?: boolean refresh_token_expires_in?: number } class AuthRequest { public request: IncomingMessage; public response: ServerResponse; public constructor (req: IncomingMessage, res: ServerResponse) { this.request = req; this.response = res; } private default_header () { this.response.setHeader ('Cache-Control', 'no-store'); this.response.setHeader ('Pragma', 'no-cache'); this.response.setHeader ('Content-Type', 'application/json'); } public allow_access ({ access_token_expires_in, include_refresh_token, refresh_token_expires_in }: AccessSettings): void { this.default_header (); this.response.writeHead (200); const res = { token_type: 'bearer', access_token: auth.sign ('access_token', access_token_expires_in), expires_in: access_token_expires_in, scope }; if (include_refresh_token) { res.refresh_token = auth.sign ('refresh_token', refresh_token_expires_in); res.refresh_token_expires_in = refresh_token_expires_in; } this.response.end (JSON.stringify (res)); } public invalid (error_description) { this.default_header (); this.response.writeHead (400); this.response.end (JSON.stringify ({ error: 'invalid_request', error_description })); } public deny () { this.default_header (); this.response.writeHead (401); this.response.end (JSON.stringify ({ error: 'invalid_client' })); } } type AuthRequestHandler = (req: AuthRequest) => void|Promise; interface CreateHandlerOptions { refresh?: AccessSettings; modules?: Record; } export default function create_auth_handler ( default_handler: AuthRequestHandler, { refresh, modules }: CreateHandlerOptions ) { return function process_request ( req: IncomingMessage, res: ServerResponse ): Promise|void { const request = new AuthRequest (req, res); const token = (/Bearer (?.+)/ui).exec (req.headers.authorization); if (token === null) return default_handler (request); const token_data = auth.verify (token.groups.token); if (!token_data.valid) { request.deny (); return Promise.resolve (); } if (token_data.type === 'refresh_token') { request.allow_access (refresh); return Promise.resolve (); } if (token_data.type === 'part_token' && Object.keys (modules) .includes (token_data.next_module)) return modules[token_data.next_module] (request); request.invalid ('invalid bearer token'); return Promise.resolve (); }; }