Description
I'm following Feather's API key auth strategy as listed here. My application only has API key auth and no other auth stratagies.
I've set up my API key to be read from the header field x-api-key
and when running through Postman, the API key auth works as expected. With a correct x-api-key
field in a request header, the request authenticates as expected.
I'm struggling to get the Swagger UI to send the header through, even though it looks like it's configured correctly.
My authentication is set up like this:
import { AuthenticationBaseStrategy, AuthenticationService } from '@feathersjs/authentication';
import { NotAuthenticated } from '@feathersjs/errors';
import { services } from '#src/enums';
class ApiKeyStrategy extends AuthenticationBaseStrategy {
app;
constructor(app) {
super();
this.app = app;
}
async authenticate(authentication) {
const { apiKey } = authentication;
const { total } = await this.app.service(services.API_KEYS).find({ query: { apiKey, $limit: 0 } });
const hasAccess = total === 1;
if (!hasAccess) {
throw new NotAuthenticated('Incorrect API Key');
}
return { apiKey: true };
}
}
export const authentication = app => {
const authentication = new AuthenticationService(app);
authentication.register('apiKey', new ApiKeyStrategy(app));
// Not sure if I need to configure Swagger for the authentication here?
app.use('authentication', authentication);
};
My Swagger instance is configured like this:
import feathersSwagger from 'feathers-swagger';
export const swagger = app => {
const title = app.get('title');
const description = app.get('description');
const version = app.get('version');
app.configure(
feathersSwagger({
prefix: /^(api|commands|subscriptions)\//,
specs: {
info: { title, description, version },
components: { securitySchemes: { ApiKeyAuth: { type: 'apiKey', in: 'header', name: 'x-api-key' } } },
security: [{ ApiKeyAuth: [] }]
},
include: { paths: ['api', 'commands', 'subscriptions'] },
ui: feathersSwagger.swaggerUI()
})
);
};
These are then configured in my app.js
file like so:
app.configure(swagger);
app.configure(authentication);
app.configure(api); // Configure all /api/xxx endpoints
app.configure(commands); // Configure all /commands/xxx endpoints
app.configure(subscriptions); // Configure all /subscriptions/xxx endpoints
My endpoints are each configures like this:
import { authenticate } from '@feathersjs/authentication';
import { hooks as schemaHooks } from '@feathersjs/schema';
import swagger from 'feathers-swagger';
import { claims, methods, services } from '#src/enums';
import { ApiKeysService, getOptions } from './api-keys.class.js';
import { apiKeysDocs } from './api-keys.schema.js';
const path = services.API_KEYS;
const allowedMethods = [methods.FIND, methods.GET, methods.CREATE, methods.PATCH, methods.REMOVE];
const apiKeyDocs = swagger.createSwaggerServiceOptions({
schemas: {
// ...
},
docs: {
description: 'An API key REST service',
securities: ['ApiKeyAuth']
}
});
export const apiKeys = app => {
app.use(path, new ApiKeysService(getOptions(app)), {
methods: allowedMethods,
events: [],
docs: apiKeysDocs
});
app.service(path).hooks({
// ...
});
};
In the Swagger UI, I can see the correct authentication UI:
But when making requests whilst authentication, the header doesn't appear to be attached to the request:
I've tried setting cors in my app.js
like so, but the x-api-key
request header is still not being set:
app.use(
cors({
origin: '*', // Adjust based on your security needs
allowedHeaders: ['x-api-key', 'Content-Type']
})
);
Does anyone know what I'm missing? Would really like to be able to test the API via the Swagger UI.
Bonus question: Is there a way I could have my sub-endpoints (/api/
, /commands/
, /subscriptions/
) grouped together in Swagger UI, so that I could collapse them independently? I've tried using tags, but these set all the /api/
endpoints under one tag