Suggestion
Provide a lookup for a strategy name, if metadata is not provided by decorator.
Use Cases
Instead of annotating each controller or controller method, we would like to specify a default strategy name to make the application secure by default. In our user experiences, developers sometimes forget the @authenticate decorator, which makes the endpoint accidently public available.
Examples
Here is an example how we currently redefine the AuthenticationStrategyProvider:
import { AuthenticationBindings, AuthenticationMetadata, AuthenticationStrategy, AUTHENTICATION_STRATEGY_NOT_FOUND } from '@loopback/authentication';
import { BindingScope, Getter, inject } from '@loopback/context';
import { extensionPoint, extensions, Provider } from '@loopback/core';
import { RestBindings, Request } from '@loopback/rest';
/**
* An authentication strategy provider responsible for
* resolving an authentication strategy by name.
*
* It declares an extension point to which all authentication strategy
* implementations must register themselves as extensions.
*/
@extensionPoint(
AuthenticationBindings.AUTHENTICATION_STRATEGY_EXTENSION_POINT_NAME,
{ scope: BindingScope.TRANSIENT },
) //this needs to be transient, e.g. for request level context.
export class AuthenticationStrategyProvider implements Provider<AuthenticationStrategy | undefined> {
noAuthUrlPattern: RegExp[] = [
/^\/explorer/,
/^\/openapi.json$/,
/^\/favicon.ico$/,
];
constructor(
@extensions() private authenticationStrategies: Getter<AuthenticationStrategy[]>,
@inject(RestBindings.Http.REQUEST) private request: Request,
@inject(AuthenticationBindings.METADATA) private metadata?: AuthenticationMetadata,
) { }
async value(): Promise<AuthenticationStrategy | undefined> {
const { strategy: name = 'jwt' } = this.metadata || {};
// workaround to whitelist api explorer
if (this.noAuthUrlPattern.some(regexp => regexp.test(this.request.url))) {
// allow unauthenticated access
return undefined;
}
const strategy = await this.findAuthenticationStrategy(name);
if (!strategy) {
// important to throw a non-protocol-specific error here
const error = new Error(`The strategy '${name}' is not available.`);
Object.assign(error, {
code: AUTHENTICATION_STRATEGY_NOT_FOUND,
});
throw error;
}
return strategy;
}
async findAuthenticationStrategy(name: string): Promise<AuthenticationStrategy | undefined> {
const strategies = await this.authenticationStrategies();
const matchingAuthStrategy = strategies.find(a => a.name === name);
return matchingAuthStrategy;
}
}
modified version of https://github.com/strongloop/loopback-next/blob/c944654881140119e44fe9e1db85a0f26e59d658/packages/authentication/src/providers/auth-strategy.provider.ts#L36-L41
Acceptance criteria
TBD - will be filled by the team.
Suggestion
Provide a lookup for a strategy name, if metadata is not provided by decorator.
Use Cases
Instead of annotating each controller or controller method, we would like to specify a default strategy name to make the application secure by default. In our user experiences, developers sometimes forget the
@authenticatedecorator, which makes the endpoint accidently public available.Examples
Here is an example how we currently redefine the AuthenticationStrategyProvider:
modified version of https://github.com/strongloop/loopback-next/blob/c944654881140119e44fe9e1db85a0f26e59d658/packages/authentication/src/providers/auth-strategy.provider.ts#L36-L41
Acceptance criteria
TBD - will be filled by the team.