UNPKG

@feathersjs/authentication

Version:

Add Authentication to your FeathersJS app.

195 lines 7.94 kB
"use strict"; 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 commons_1 = require("@feathersjs/commons"); const options_1 = require("./options"); const debug = (0, commons_1.createDebug)('@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; this.isReady = false; 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.defaultOptions, 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) { var _a; // 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; if (this.isReady) { (_a = strategy.setup) === null || _a === void 0 ? void 0 : _a.call(strategy, this, name); } } /** * 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); } /** * Returns a single strategy by name * * @param name The strategy name * @returns The authentication strategy or undefined */ getStrategy(name) { return this.strategies[name]; } /** * 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 */ async createAccessToken(payload, optsOverride, secretOverride) { 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 */ async verifyAccessToken(accessToken, optsOverride, secretOverride) { 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 = 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 */ async authenticate(authentication, params, ...allowed) { 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, { ...params, authenticated: true }); } async handleConnection(event, connection, authResult) { const strategies = this.getStrategies(...Object.keys(this.strategies)).filter((current) => typeof current.handleConnection === 'function'); for (const strategy of strategies) { await 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 */ async parse(req, res, ...names) { 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 = await authStrategy.parse(req, res); if (value !== null) { return value; } } return null; } async setup() { var _a; this.isReady = true; for (const name of Object.keys(this.strategies)) { const strategy = this.strategies[name]; await ((_a = strategy.setup) === null || _a === void 0 ? void 0 : _a.call(strategy, this, name)); } } } exports.AuthenticationBase = AuthenticationBase; //# sourceMappingURL=core.js.map