UNPKG

@feathersjs/authentication

Version:

Add Authentication to your FeathersJS app.

184 lines 8.43 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthenticationBase = void 0; const merge_1 = __importDefault(require("lodash/merge")); const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); const uuid_1 = require("uuid"); const errors_1 = require("@feathersjs/errors"); const debug_1 = __importDefault(require("debug")); const options_1 = __importDefault(require("./options")); const debug = (0, debug_1.default)('@feathersjs/authentication/base'); /** * A base class for managing authentication strategies and creating and verifying JWTs */ class AuthenticationBase { /** * Create a new authentication service. * @param app The Feathers application instance * @param configKey The configuration key name in `app.get` (default: `authentication`) * @param options Optional initial options */ constructor(app, configKey = 'authentication', options = {}) { if (!app || typeof app.use !== 'function') { throw new Error('An application instance has to be passed to the authentication service'); } this.app = app; this.strategies = {}; this.configKey = configKey; app.set('defaultAuthentication', app.get('defaultAuthentication') || configKey); app.set(configKey, (0, merge_1.default)({}, app.get(configKey), options)); } /** * Return the current configuration from the application */ get configuration() { // Always returns a copy of the authentication configuration return Object.assign({}, options_1.default, this.app.get(this.configKey)); } /** * A list of all registered strategy names */ get strategyNames() { return Object.keys(this.strategies); } /** * Register a new authentication strategy under a given name. * @param name The name to register the strategy under * @param strategy The authentication strategy instance */ register(name, strategy) { // Call the functions a strategy can implement if (typeof strategy.setName === 'function') { strategy.setName(name); } if (typeof strategy.setApplication === 'function') { strategy.setApplication(this.app); } if (typeof strategy.setAuthentication === 'function') { strategy.setAuthentication(this); } if (typeof strategy.verifyConfiguration === 'function') { strategy.verifyConfiguration(); } // Register strategy as name this.strategies[name] = strategy; } /** * Get the registered authentication strategies for a list of names. * @param names The list or strategy names */ getStrategies(...names) { return names.map(name => this.strategies[name]) .filter(current => !!current); } /** * Create a new access token with payload and options. * @param payload The JWT payload * @param optsOverride The options to extend the defaults (`configuration.jwtOptions`) with * @param secretOverride Use a different secret instead */ createAccessToken(payload, optsOverride, secretOverride) { return __awaiter(this, void 0, void 0, function* () { const { secret, jwtOptions } = this.configuration; // Use configuration by default but allow overriding the secret const jwtSecret = secretOverride || secret; // Default jwt options merged with additional options const options = (0, merge_1.default)({}, jwtOptions, optsOverride); if (!options.jwtid) { // Generate a UUID as JWT ID by default options.jwtid = (0, uuid_1.v4)(); } return jsonwebtoken_1.default.sign(payload, jwtSecret, options); }); } /** * Verifies an access token. * @param accessToken The token to verify * @param optsOverride The options to extend the defaults (`configuration.jwtOptions`) with * @param secretOverride Use a different secret instead */ verifyAccessToken(accessToken, optsOverride, secretOverride) { return __awaiter(this, void 0, void 0, function* () { const { secret, jwtOptions } = this.configuration; const jwtSecret = secretOverride || secret; const options = (0, merge_1.default)({}, jwtOptions, optsOverride); const { algorithm } = options; // Normalize the `algorithm` setting into the algorithms array if (algorithm && !options.algorithms) { options.algorithms = Array.isArray(algorithm) ? algorithm : [algorithm]; delete options.algorithm; } try { const verified = yield jsonwebtoken_1.default.verify(accessToken, jwtSecret, options); return verified; } catch (error) { throw new errors_1.NotAuthenticated(error.message, error); } }); } /** * Authenticate a given authentication request against a list of strategies. * @param authentication The authentication request * @param params Service call parameters * @param allowed A list of allowed strategy names */ authenticate(authentication, params, ...allowed) { return __awaiter(this, void 0, void 0, function* () { const { strategy } = authentication || {}; const [authStrategy] = this.getStrategies(strategy); const strategyAllowed = allowed.includes(strategy); debug('Running authenticate for strategy', strategy, allowed); if (!authentication || !authStrategy || !strategyAllowed) { const additionalInfo = (!strategy && ' (no `strategy` set)') || (!strategyAllowed && ' (strategy not allowed in authStrategies)') || ''; // If there are no valid strategies or `authentication` is not an object throw new errors_1.NotAuthenticated('Invalid authentication information' + additionalInfo); } return authStrategy.authenticate(authentication, Object.assign(Object.assign({}, params), { authenticated: true })); }); } handleConnection(event, connection, authResult) { return __awaiter(this, void 0, void 0, function* () { const strategies = this.getStrategies(...Object.keys(this.strategies)) .filter(current => typeof current.handleConnection === 'function'); for (const strategy of strategies) { yield strategy.handleConnection(event, connection, authResult); } }); } /** * Parse an HTTP request and response for authentication request information. * @param req The HTTP request * @param res The HTTP response * @param names A list of strategies to use */ parse(req, res, ...names) { return __awaiter(this, void 0, void 0, function* () { const strategies = this.getStrategies(...names) .filter(current => typeof current.parse === 'function'); debug('Strategies parsing HTTP header for authentication information', names); for (const authStrategy of strategies) { const value = yield authStrategy.parse(req, res); if (value !== null) { return value; } } return null; }); } } exports.AuthenticationBase = AuthenticationBase; //# sourceMappingURL=core.js.map