UNPKG

@loopback/docs

Version:
244 lines (184 loc) 8.27 kB
# Passport Strategy Adapter _Important: We strongly recommend that users learn LoopBack's [authentication system](https://loopback.io/doc/en/lb4/Loopback-component-authentication.html) before using this module._ This is an adapter module created for plugging in [`passport`](https://www.npmjs.com/package/passport) based strategies to the authentication system in `@loopback/authentication@3.x`. ## Installation ```sh npm i @loopback/authentication-passport --save ``` ## Background `@loopback/authentication@3.x` allows users to register authentication strategies that implement the interface [`AuthenticationStrategy`](https://apidocs.strongloop.com/@loopback%2fdocs/authentication.html#AuthenticationStrategy) Since `AuthenticationStrategy` describes a strategy with different contracts than the passport [`Strategy`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/passport/index.d.ts#L79), 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 1. Create an instance of the passport strategy Taking the basic strategy exported from [`passport-http`](https://github.com/jaredhanson/passport-http) as an example, first create an instance of the basic strategy with your `verify` function. ```ts // Create a file named `my-basic-auth-strategy.ts` to define your strategy below 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()`. 2. Apply the adapter to the strategy ```ts // In file 'my-basic-auth-strategy.ts' import {BasicStrategy} from 'passport-http'; function verify(username: string, password: string, cb: Function) { users.find(username, password, cb); } const basicStrategy = new BasicStrategy(verify); // Apply the adapter export const AUTH_STRATEGY_NAME = 'basic'; export const basicAuthStrategy = new StrategyAdapter( // The configured basic strategy instance basicStrategy, // Give the strategy a name // You'd better define your strategy name as a constant, like // `const AUTH_STRATEGY_NAME = 'basic'`. // You will need to decorate the APIs later with the same name. AUTH_STRATEGY_NAME, ); ``` 3. Register(bind) the strategy to app ```ts 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, }); ``` 4. Decorate your endpoint To authenticate your request with the basic strategy, decorate your controller function like: ```ts import {AUTH_STRATEGY_NAME} from './my-basic-auth-strategy'; class MyController { constructor( @inject(SecurityBindings.USER, {optional: true}) private user: UserProfile, ) {} // Define your strategy name as a constant so that // it is consistent with the name you provide in the adapter @authenticate(AUTH_STRATEGY_NAME) async whoAmI(): Promise<string> { return this.user.id; } } ``` 5. 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](https://loopback.io/doc/en/lb4/Loopback-component-authentication.html#adding-an-authentication-action-to-a-custom-sequence) to rewrite your sequence. You can also find a sample implementation in [this example tutorial](https://loopback.io/doc/en/lb4/Authentication-Tutorial.html#creating-a-custom-sequence-and-adding-the-authentication-action). ### 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](https://loopback.io/doc/en/lb4/Extending-LoopBack-4.html)_ 1. Create a provider for the strategy Use `passport-http` as the example again: ```ts // Create a file named `my-basic-auth-strategy.ts` to define your strategy below class PassportBasicAuthProvider implements Provider<AuthenticationStrategy> { value(): AuthenticationStrategy { // The code that returns the converted strategy } } ``` 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`](https://github.com/jaredhanson/passport-http#usage-of-http-basic). - 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: ```ts // In file 'my-basic-auth-strategy.ts' 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); } // Takes in the verify callback function and returns a configured basic strategy. configuredBasicStrategy(verifyFn: BasicVerifyFunction): BasicStrategy { return new BasicStrategy(verifyFn); } // Applies the `StrategyAdapter` to the configured basic strategy instance. // You'd better define your strategy name as a constant, like // `const AUTH_STRATEGY_NAME = 'basic'` // You will need to decorate the APIs later with the same name convertToAuthStrategy(basic: BasicStrategy): AuthenticationStrategy { return new StrategyAdapter(basic, AUTH_STRATEGY_NAME); } } ``` 2. 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: ```ts // In the main file 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(); // In a real app the function would be imported from a community module function verify(username: string, password: string, cb: Function) { users.find(username, password, cb); } app.bind('authentication.basic.verify').to(verify); registerAuthenticationStrategy(app, PassportBasicAuthProvider); ``` 3. Decorate your endpoint To authenticate your request with the basic strategy, decorate your controller function like: ```ts import {AUTH_STRATEGY_NAME} from './my-basic-auth-strategy'; class MyController { constructor(@inject(SecurityBindings.USER) private user: UserProfile) {} // Define your strategy name as a constant so that // it is consistent with the name you provide in the adapter @authenticate(AUTH_STRATEGY_NAME) async whoAmI(): Promise<string> { return this.user.id; } } ``` 4. 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](https://loopback.io/doc/en/lb4/Loopback-component-authentication.html#adding-an-authentication-action-to-a-custom-sequence) to rewrite your sequence. You can also find a sample implementation in [this example tutorial](https://loopback.io/doc/en/lb4/Authentication-Tutorial.html#creating-a-custom-sequence-and-adding-the-authentication-action).