Skip to content

refresh token #6427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
touagueni opened this issue Sep 23, 2020 · 6 comments
Closed

refresh token #6427

touagueni opened this issue Sep 23, 2020 · 6 comments

Comments

@touagueni
Copy link

Hi everyone!

I am using npm 6.14.8.

I have a working implementation of authentication from the loopback4-example-shopping. when trying to add the refresh token capability, I am facing the following:

Unhandled error in POST /refresh-login: 500 ResolutionError: The key 'services.authentication.jwt.refresh.tokenservice' is not bound to any value
in context RequestContext-fFKtBWS_Tw2PmEVjTh7oKQ-3 (context: RequestContext-fFKtBWS_Tw2PmEVjTh7oKQ-3, binding: services.authentication.jwt.refresh.tokenservice, resolutionPath: controllers.AuthController --> @AuthController.constructor[6])
at RequestContext.getValueOrPromise (C:\avokap\backend\node_modules@loopback\context\src\context.ts:810:13)
at C:\avokap\backend\node_modules@loopback\context\src\resolver.ts:159:20
at C:\avokap\backend\node_modules@loopback\context\src\resolution-session.ts:157:13
at tryCatchFinally (C:\avokap\backend\node_modules@loopback\context\src\value-promise.ts:222:14)
at Object.tryWithFinally (C:\avokap\backend\node_modules@loopback\context\src\value-promise.ts:197:10)
at Function.runWithInjection (C:\avokap\backend\node_modules@loopback\context\src\resolution-session.ts:156:12)
at resolve (C:\avokap\backend\node_modules@loopback\context\src\resolver.ts:143:38)
at C:\avokap\backend\node_modules@loopback\context\src\resolver.ts:246:12
at Object.resolveList (C:\avokap\backend\node_modules@loopback\context\src\value-promise.ts:169:28)
at resolveInjectedArguments (C:\avokap\backend\node_modules@loopback\context\src\resolver.ts:224:10)
at Object.instantiateClass (C:\avokap\backend\node_modules@loopback\context\src\resolver.ts:62:25)
at C:\avokap\backend\node_modules@loopback\context\src\binding.ts:748:29
at Binding._getValue (C:\avokap\backend\node_modules@loopback\context\src\binding.ts:604:14)
at C:\avokap\backend\node_modules@loopback\context\src\binding.ts:479:23
at C:\avokap\backend\node_modules@loopback\context\src\resolution-session.ts:122:13
at tryCatchFinally (C:\avokap\backend\node_modules@loopback\context\src\value-promise.ts:222:14)

Please, can anyone help?

Many Thanks in advance

Tofik

@raymondfeng
Copy link
Contributor

@raymondfeng
Copy link
Contributor

Please also make sure you use the latest version of loopback4-example-shopping as we recently updated it to use newest LoopBack versions.

@touagueni
Copy link
Author

touagueni commented Sep 23, 2020

Hi Raymond,

Please, see below the content of the src/application.ts file:

import {authenticate, AuthenticationComponent} from '@loopback/authentication';
import {AuthorizationComponent} from '@loopback/authorization';
import {BootMixin} from '@loopback/boot';
import {
  ApplicationConfig,
  BindingKey,
  createBindingFromClass
} from '@loopback/core';
import {
  model,
  property,
  RepositoryMixin,
  SchemaMigrationOptions
} from '@loopback/repository';
import {RestApplication} from '@loopback/rest';
import {
  RestExplorerBindings,
  RestExplorerComponent
} from '@loopback/rest-explorer';
import {ServiceMixin} from '@loopback/service-proxy';
import path from 'path';
import {JWTAuthenticationStrategy} from './authentication-strategies/jwt-strategy';
import {MongoDataSource} from './datasources/mongo.datasource';
import {
  PasswordHasherBindings, RefreshTokenServiceBindings, TokenServiceBindings,
  TokenServiceConstants,
  UserServiceBindings
} from './keys';
import {User} from './models';
import {MyAuthenticationSequence} from './sequence';
import {BcryptHasher} from './services/hash.password.bcryptjs';
import {JWTService} from './services/jwt-service';
import {MyUserService} from './services/user.service';
import YAML = require('yaml');

export {ApplicationConfig};




/**
 * Information from package.json
 */
export interface PackageInfo {
  name: string;
  version: string;
  description: string;
}
export const PackageKey = BindingKey.create<PackageInfo>('application.package');

const pkg: PackageInfo = require('../package.json');

@model()
export class NewUser extends User {
  @property({
    type: 'string',
    required: true,
  })
  password: string;
}
@authenticate.skip()

export class AvokapApplication extends BootMixin(
  ServiceMixin(RepositoryMixin(RestApplication)),
) {
  constructor(options?: ApplicationConfig) {
    super(options);

    this.setUpBindings();

    // Bind authentication component related elements
    this.component(AuthenticationComponent);
    this.component(AuthorizationComponent);
    /****** */


    // authentication
    this.add(createBindingFromClass(JWTAuthenticationStrategy));

    // Set up the custom sequence
    this.sequence(MyAuthenticationSequence);

    // Set up default home page
    this.static('/', path.join(__dirname, '../public'));

    // Customize @loopback/rest-explorer configuration here
    this.bind(RestExplorerBindings.CONFIG).to({
      path: '/explorer',
    });
    this.component(RestExplorerComponent);

    this.projectRoot = __dirname;
    // Customize @loopback/boot Booter Conventions here
    this.bootOptions = {
      controllers: {
        // Customize ControllerBooter Conventions here
        dirs: ['controllers'],
        extensions: ['.controller.js'],
        nested: true,
      },
    };
  }

  setUpBindings(): void {
    // Bind package.json to the application context
    this.bind(PackageKey).to(pkg);

    this.bind(TokenServiceBindings.TOKEN_SECRET).to(
      TokenServiceConstants.TOKEN_SECRET_VALUE,
    );

    this.bind(TokenServiceBindings.TOKEN_EXPIRES_IN).to(
      TokenServiceConstants.TOKEN_EXPIRES_IN_VALUE,
    );

    this.bind(TokenServiceBindings.TOKEN_SERVICE).toClass(JWTService);

    // // Bind bcrypt hash services
    this.bind(PasswordHasherBindings.ROUNDS).to(10);
    this.bind(PasswordHasherBindings.PASSWORD_HASHER).toClass(BcryptHasher);

    this.bind(UserServiceBindings.USER_SERVICE).toClass(MyUserService);

    /*********************************************************** */
    // Bind datasource
    this.dataSource(MongoDataSource, UserServiceBindings.DATASOURCE_NAME);
    //Bind datasource for refreshtoken table
    this.dataSource(MongoDataSource, RefreshTokenServiceBindings.DATASOURCE_NAME);

    /************************************************************ */

  }

  // Unfortunately, TypeScript does not allow overriding methods inherited
  // from mapped types. https://github.com/microsoft/TypeScript/issues/38496
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  async start(): Promise<void> {
    // Use `databaseSeeding` flag to control if products/users should be pre
    // populated into the database. Its value is default to `true`.
    if (this.options.databaseSeeding !== false) {
      await this.migrateSchema();
    }
    return super.start();
  }

  async migrateSchema(options?: SchemaMigrationOptions): Promise<void> {
    await super.migrateSchema(options);

    // // Pre-populate products
    // const productRepo = await this.getRepository(ProductRepository);
    // await productRepo.deleteAll();
    // const productsDir = path.join(__dirname, '../fixtures/products');
    // const productFiles = fs.readdirSync(productsDir);

    // for (const file of productFiles) {
    //   if (file.endsWith('.yml')) {
    //     const productFile = path.join(productsDir, file);
    //     const yamlString = fs.readFileSync(productFile, 'utf8');
    //     const product = YAML.parse(yamlString);
    //     await productRepo.create(product);
    //   }
    // }

    // // Pre-populate users
    // const passwordHasher = await this.get(
    //   PasswordHasherBindings.PASSWORD_HASHER,
    // );
    // const userRepo = await this.getRepository(UserRepository);
    // await userRepo.deleteAll();
    // const usersDir = path.join(__dirname, '../fixtures/users');
    // const userFiles = fs.readdirSync(usersDir);

    // for (const file of userFiles) {
    //   if (file.endsWith('.yml')) {
    //     const userFile = path.join(usersDir, file);
    //     const yamlString = YAML.parse(fs.readFileSync(userFile, 'utf8'));
    //     const input = new NewUser(yamlString);
    //     const password = await passwordHasher.hashPassword(input.password);
    //     input.password = password;
    //     const user = await userRepo.create(_.omit(input, 'password'));

    //     await userRepo.userCredentials(user.id).create({password});
    //   }
    // }

    // // Delete existing shopping carts
    // const cartRepo = await this.getRepository(ShoppingCartRepository);
    // await cartRepo.deleteAll();

    // // Delete existing orders
    // const orderRepo = await this.getRepository(OrderRepository);
    // await orderRepo.deleteAll();
  }
}

@raymondfeng
Copy link
Contributor

@raymondfeng
Copy link
Contributor

You'll have to add this.bind(RefreshTokenServiceBindings.REFRESH_TOKEN_SERVICE).toClass(...) if you register all bindings without using the jwt component.

@touagueni
Copy link
Author

Raymond I only had to use the application.ts from the shpping application provided example.
it works now, much appreciated.
cheers
T

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants