Passport Strategy Adapter
Important: We strongly recommend that users learn LoopBack's
authentication system
before using this module.
This is an adapter module created for plugging in
passport
based strategies to the
authentication system in @loopback/authentication@3.x
.
Stability: :warning:Experimental:warning:
Experimental packages provide early access to advanced or experimental
functionality to get community feedback. Such modules are published to npm
using 0.x.y
versions. Their APIs and functionality may be subject to
breaking changes in future releases.
Installation
npm i @loopback/authentication-passport --save
Background
@loopback/authentication@3.x
allows users to register authentication
strategies that implement the interface
AuthenticationStrategy
Since AuthenticationStrategy
describes a strategy with different contracts
than the passport
Strategy
,
and we'd like to support the existing 500+ community passport strategies, an
adapter class is created in this package to convert a passport strategy to
the one that LoopBack 4 authentication system wants.
Usage
Simple Usage
- Create an instance of the passport strategy
Taking the basic strategy exported from
passport-http
as an example,
first create an instance of the basic strategy with your verify
function.
import {BasicStrategy} from 'passport-http';
function verify(username: string, password: string, cb: Function) {
users.find(username, password, cb);
}
const basicStrategy = new BasicStrategy(verify);
It's a similar configuration as you add a strategy to a passport
by calling
passport.use()
.
- Apply the adapter to the strategy
import {BasicStrategy} from 'passport-http';
function verify(username: string, password: string, cb: Function) {
users.find(username, password, cb);
}
const basicStrategy = new BasicStrategy(verify);
export const AUTH_STRATEGY_NAME = 'basic';
export const basicAuthStrategy = new StrategyAdapter(
basicStrategy,
AUTH_STRATEGY_NAME,
);
- Register(bind) the strategy to app
import {Application, CoreTags} from '@loopback/core';
import {AuthenticationBindings} from '@loopback/authentication';
import {basicAuthStrategy} from './my-basic-auth-strategy';
app
.bind('authentication.strategies.basicAuthStrategy')
.to(basicAuthStrategy)
.tag({
[CoreTags.EXTENSION_FOR]:
AuthenticationBindings.AUTHENTICATION_STRATEGY_EXTENSION_POINT_NAME,
});
- Decorate your endpoint
To authenticate your request with the basic strategy, decorate your controller
function like:
import {AUTH_STRATEGY_NAME} from './my-basic-auth-strategy';
class MyController {
constructor(
@inject(AuthenticationBindings.CURRENT_USER, {optional: true})
private user: UserProfile,
) {}
@authenticate(AUTH_STRATEGY_NAME)
async whoAmI(): Promise<string> {
return this.user.id;
}
}
- Add the authentication action to your sequence
This part is same as registering a non-passport based strategy. Please make sure
you follow the documentation
adding-an-authentication-action-to-a-custom-sequence
to rewrite your sequence. You can also find a sample implementation in
this example tutorial.
With Provider
If you need to inject stuff (e.g. the verify function) when configuring the
strategy, you may want to provide your strategy as a provider.
Note: If you are not familiar with LoopBack providers, check the documentation
in
Extending LoopBack 4
- Create a provider for the strategy
Use passport-http
as the example again:
class PassportBasicAuthProvider implements Provider<AuthenticationStrategy> {
value(): AuthenticationStrategy {
}
}
The Provider should have two functions:
-
A function that takes in the verify callback function and returns a configured
basic strategy. To know more about the configuration, please check
the configuration guide in module passport-http
.
-
A function that applies the StrategyAdapter
to the configured basic strategy
instance. Then in the value()
function, you return the converted strategy.
So a full implementation of the provider is:
import {BasicStrategy, BasicVerifyFunction} from 'passport-http';
import {StrategyAdapter} from `@loopback/passport-adapter`;
import {AuthenticationStrategy} from '@loopback/authentication';
class PassportBasicAuthProvider implements Provider<AuthenticationStrategy> {
constructor(
@inject('authentication.basic.verify') verifyFn: BasicVerifyFunction,
);
value(): AuthenticationStrategy {
const basicStrategy = this.configuredBasicStrategy(verify);
return this.convertToAuthStrategy(basicStrategy);
}
configuredBasicStrategy(verifyFn: BasicVerifyFunction): BasicStrategy {
return new BasicStrategy(verifyFn);
}
convertToAuthStrategy(basic: BasicStrategy): AuthenticationStrategy {
return new StrategyAdapter(basic, AUTH_STRATEGY_NAME);
}
}
- Register the strategy provider
Register the strategy provider in your LoopBack application so that the
authentication system can look for your strategy by name and invoke it:
import {addExtension} from '@loopback/core';
import {MyApplication} from '<path_to_your_app>';
import {PassportBasicAuthProvider} from '<path_to_the_provider>';
import {
AuthenticationBindings,
registerAuthenticationStrategy,
} from '@loopback/authentication';
const app = new MyApplication();
function verify(username: string, password: string, cb: Function) {
users.find(username, password, cb);
}
app.bind('authentication.basic.verify').to(verify);
registerAuthenticationStrategy(app, PassportBasicAuthProvider);
- Decorate your endpoint
To authenticate your request with the basic strategy, decorate your controller
function like:
import {AUTH_STRATEGY_NAME} from './my-basic-auth-strategy';
class MyController {
constructor(
@inject(AuthenticationBindings.CURRENT_USER) private user: UserProfile,
) {}
@authenticate(AUTH_STRATEGY_NAME)
async whoAmI(): Promise<string> {
return this.user.id;
}
}
- Add the authentication action to your sequence
This part is same as registering a non-passport based strategy. Please make sure
you follow the documentation
adding-an-authentication-action-to-a-custom-sequence
to rewrite your sequence. You can also find a sample implementation in
this example tutorial.