UNPKG

@tdc/feathers-authentication-api-key

Version:

API Key authentication strategy for @feathers/authentication

104 lines (93 loc) 2.79 kB
import { Params, Service } from "@feathersjs/feathers"; import { NotAuthenticated } from "@feathersjs/errors"; import { IncomingMessage, ServerResponse } from "http"; import { AuthenticationBaseStrategy, AuthenticationResult } from "@feathersjs/authentication"; export class ApiKeyStrategy extends AuthenticationBaseStrategy { private serviceBased: boolean = false; constructor() { super(); } verifyConfiguration() { this.serviceBased = ["service", "entity"].every( prop => prop in this.configuration ); if (!this.serviceBased) { if (!("key" in this.configuration)) { throw new Error( `A static key is missing, when strategy '${this.name}', is not service based` ); } } ["headerField"].forEach(prop => { if (prop in this.configuration) return; throw new Error(`'${prop}' is missing from configuration`); }); } get configuration() { const config = super.configuration || {}; return { errorMessage: "Invalid API key", entity: "api-key", ...config }; } async findEntity(apiKey: string, params: Params) { const { errorMessage, entity } = this.configuration; try { const result = await this.entityService.find({ query: { [entity]: apiKey, $limit: 1 }, paginate: false }); if (result.length === 0) { throw new NotAuthenticated(errorMessage); } return result[0]; } catch (error) { throw new NotAuthenticated(errorMessage); } } async authenticate(authRequest: AuthenticationResult, params: Params) { const { key, errorMessage, entity, revokedField, headerField } = this.configuration; const apiKey = authRequest[entity]; const response = { authentication: { strategy: this.name, [entity]: apiKey }, headers: { ...params.headers, [headerField]: apiKey }, apiKey: true, [entity]: {} }; if (!this.serviceBased) { if (key !== apiKey) throw new NotAuthenticated(errorMessage); return response; } const apiKeyData = await this.findEntity(apiKey, params); if (revokedField in apiKeyData) { if (apiKeyData[revokedField]) { throw new NotAuthenticated("API Key has been revoked"); } } response[entity] = apiKeyData; return response; } async parse(req: IncomingMessage, res: ServerResponse) { const { headerField, entity } = this.configuration; const apiKey = req.headers[headerField]; if (apiKey) { return { strategy: this.name, [entity]: apiKey }; } return null; } }