# Providers

This directory contains providers contributing additional bindings, for example custom sequence actions.

## Overview

A [provider](http://loopback.io/doc/en/lb4/Creating-components.html#providers) is a class that provides a `value()`
function. This function is called `Context` when another entity requests a value to be injected.

## Basic Usage

These are the optional bindings that can be used to extend the functionality of this service.

### BEARER_TOKEN_VERIFIER

This provides a function that is used to verify the Bearer Token for endpoints using the Bearer Token authentication.

Implementation for this can be seen [here](../modules/auth/providers/bearer-token-verify.provider.ts);

### CODEREADER_PROVIDER

This provides a function that can process the authorization code (used in KeyCloak and Google Oauth authentications)
before being verified. This can be used to decrypt a code or to retrieve it from Cache/Redis.

Sample implementation -

```ts
export class CodeReaderProvider implements Provider<CodeReaderFn> {
  constructor(
    @repository(CodeRepository)
    private readonly codeRepo: CodeRepository,
  ) {}

  value(): CodeReaderFn {
    return async token => {
      let codeModel = await this.codeRepo.get(token);
      if (!codeModel?.code) {
        return token;
      }
      await this.codeRepo.delete(token);
      return codeModel.code;
    };
  }
}
```

Here `CodeRepository` is a Redis Repository, implementation for such a key pair repository can be seen
[here](https://loopback.io/doc/en/lb4/Repository.html#access-keyvalue-stores).

### CODEWRITER_PROVIDER

This provides a function that can process the authorization code before it is passed to the client, it can be used to
store the token in a cache and pass only a key, or to encrypt the token.

Sample implementation -

```ts
export class CodeWriterProvider implements Provider<CodeWriterFn> {
  constructor(
    @repository(CodeRepository)
    private readonly codeRepo: CodeRepository,
  ) {}

  value(): CodeWriterFn {
    return async token => {
      let key = uuidv4();
      await this.codeRepo.set(key, {code: token});
      return key;
    };
  }
}
```

Here `CodeRepository` is a Redis Repository, implementation for such a key pair repository can be seen
[here](https://loopback.io/doc/en/lb4/Repository.html#access-keyvalue-stores).

`uuidv4` is function to from [this](https://www.npmjs.com/package/uuid).

### PRE_LOCAL_SIGNUP_PROVIDER

This provides a function that creates the object stored in the JWT token for signup requests.

Sample implementation for this can be seen [here](./local-presignup.provider.ts)

### LOCAL_SIGNUP_PROVIDER

This provides a function that gets the data from the signup token and is responsible for performing all tasks required
to signup a user. You can also find an implementation of this provider in
[auth-basic-example](../../../../sandbox/auth-basic-example/).

Sample implementation -

```ts
export class LocalSignupProvider implements Provider<UserSignupFn<UserSignupDto, {userId: string | undefined}>> {
  constructor(
    @service(UserService)
    private readonly userService: UserService,
  ) {}

  value(): UserSignupFn<UserSignupDto, {userId: string | undefined}> {
    return async (model: UserSignupDto, tokenInfo?: AnyObject) => {
      if (!model.userData) {
        throw new HttpErrors.BadRequest('userData missing');
      }
      if (tokenInfo?.email && model.email === tokenInfo.email) {
        await this.userService.updateUser(model.userData, model.email);
      } else {
        throw new HttpErrors.BadRequest('Invalid Email');
      }
    };
  }
}
```

### BEARER_SIGNUP_VERIFY_PROVIDER

The provider for this key is used to verify a signup token generated by the signup endpoint.

```ts
this.bind(VerifyBindings.BEARER_SIGNUP_VERIFY_PROVIDER).toProvider(SignupBearerVerifyProvider);
```

```ts
export class SignupBearerVerifyProvider implements Provider<VerifyFunction.BearerFn<UserInviteDto>> {
  constructor() {}

  value(): VerifyFunction.BearerFn<UserInviteDto> {
    return async (token: string) => {
      let result: UserInviteDto;
      try {
        result = verify(token, process.env.JWT_SECRET as string, {
          issuer: process.env.JWT_ISSUER,
        }) as UserInviteDto;
      } catch (error) {
        throw new HttpErrors.Unauthorized('TokenExpired');
      }
      if (await this.userOpsService.checkUserSignedUp(result.email)) {
        throw new HttpErrors.Forbidden('TokenAlreadyUsed');
      }
      return result;
    };
  }
}
```

## Related Resources

You can check out the following resource to learn more about providers, components, sequences, and binding keys.

- [Providers](http://loopback.io/doc/en/lb4/Creating-components.html#providers)
- [Binding Keys](http://loopback.io/doc/en/lb4/Decorators.html)
