Skip to content

Angular v15

Glen Hughes edited this page Jan 10, 2024 · 3 revisions

Integrating with an Angular project has a few steps that need to be implemented to work out of the box.

⚠️ Please note: the iProov Web SDK has only been tested with Angular v10 and v15 and may not be compatible with other versions.

The example code below was initially generated with the Angular CL and utilises Angular services to fetch tokens and use the Support Checker.

app.module.ts

import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core"
import { BrowserModule } from "@angular/platform-browser"
import { HttpClientModule } from "@angular/common/http"

import { AppComponent } from "./app.component";
import { IproovComponent } from './iproov/iproov.component'

@NgModule({
  declarations: [AppComponent, IproovComponent], // Include app and iproov component
  imports: [BrowserModule, HttpClientModule],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [
    CUSTOM_ELEMENTS_SCHEMA,
  ],
})
export class AppModule {
  constructor() {
    // your app code
  }
}

app.component.ts

import { Component } from "@angular/core"

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html"m
})
export class AppComponent {
  title = "iProov Web SDK Angular Example"
}

You will then need to inject the component into your application and also tell Angular that we are using custom web components. The code below is from the angular-cli default generated app.

app.module.ts

import { BrowserModule } from "@angular/platform-browser"
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core" // import Custom Elements from Angular

import { AppRoutingModule } from "./app-routing.module"
import { AppComponent } from "./app.component"
import { IproovComponent } from "./iproov.component" // import the iproov component

@NgModule({
  declarations: [
    AppComponent,
    IproovComponent, // include the iproov component
  ],
  imports: [BrowserModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [
    CUSTOM_ELEMENTS_SCHEMA, // define the custom element schema
  ],
})
export class AppModule {}

app.component.html

<div class="content" role="main">
  <h2>iProov Angular Example</h2>
  <!-- pass no attrs here, iproov-me is injected by the component with attrs after token generation -->
  <iproov-component />

  <footer>
    Copyright iProov ltd
  </footer>
</div>

With the app base built, we can then create our services to handle fetching tokens and the support checker.

iproov.component.ts

import { Component, Input } from "@angular/core"
import "@iproov/web-sdk" // import iProov web-sdk
import { iProovSupport, iProovSupportCheck } from "@iproov/web-sdk/iProovSupport.js" // import iProov web-sdk support checker separately from web-sdk package
import { IproovTokenService } from "./iproov-token.service"
import { IproovSupportCheckerService } from "./iproov-support-checker-service"

@Component({
  selector: "iproov-component",
  templateUrl: "./iproov.component.html",
})
export class IproovComponent {
  @Input() token: string = "GENERATED BY IPROOV TOKEN SERVICE"
  @Input() base_url: string = "https://beta.rp.secure.iproov.me"
  @Input() debug: boolean = true
  constructor(
    private tokenService: IproovTokenService,
    private supportChecker: IproovSupportCheckerService
  ) {

    // Check device is supported with a permission request
    // this.supportChecker.checkDeviceIsSupportedWithPermission().then((supportCheck: iProovSupportCheck) => {
    //   console.log("iProov support check response", supportCheck)
    //   // Logic on unsupported devices
    //   if (!supportCheck.supported) {
    //     console.log("Device is not supported")
    //     // Send user on alternative journey
    //   }

    //   // Device is supported, generate token
    //   this.tokenService.getToken().subscribe((response: any) => {
    //     this.token = response.token
    //     this.createIproovMe()
    //   })
    // })

    // Just logs the support check response
    // this.supportChecker.checkDeviceIsSupportedWithEvent()

    // Check device is supported without a permission request
    this.supportChecker.checkDeviceIsSupported().then((supportCheck: iProovSupportCheck) => {
      console.log("iProov support check response", supportCheck)
      // Logic on unsupported devices
      if (!supportCheck.supported) {
        console.log("Device is not supported")
        // Send user on alternative journey
      }

      // Device is supported, generate token
      this.tokenService.getToken().subscribe((response: any) => {
        this.token = response.token
        this.createIproovMe()
      })
    })
  }
  private createIproovMe() {
    // Add your options here 
    const iproovMe = document.createElement("iproov-me")
    iproovMe.setAttribute("token", this.token)
    iproovMe.setAttribute("base_url", this.base_url)
    iproovMe.setAttribute("debug", this.debug ? "true" : "false")
    document.body.appendChild(iproovMe)
  }
}

Add any custom slots you want to use:

iproov.component.html

<template id="iproov-slots">
  <div slot="ready">Ready</div>
  <div slot="button">Click me</div>
  <div slot="passed">You Passed!!</div>
  <div slot="failed">You Failed!!</div>
</template>

See backend guide for interacting with the iProov backend.

iproov-token.service.ts

import { Injectable } from "@angular/core"
import { HttpClient, HttpErrorResponse } from "@angular/common/http"
import { Observable, throwError } from "rxjs"
import { catchError, retry } from "rxjs/operators"

@Injectable({
  providedIn: "root",
})
export class IproovTokenService {
  // replace endPoint value with your backend service
  private endPoint: string = "https://localhost:8085/claim/enrol/token?assurance_type=genuine_presence"
  constructor(private http: HttpClient) {}

  private generateUsername(): string {
    return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
      const r = (Math.random() * 16) | 0,
        v = c == "x" ? r : (r & 0x3) | 0x8
      return v.toString(16)
    })
  }

  getToken(): Observable<string> {
    return this.http
      .post<string>(
        this.endPoint,
        {
          resource: "https://iproov.app",
          user_id: `${this.generateUsername()}@iproov.me`,
          client: "Web SDK Angular Test",
        },
        {
          headers: {
            "Accept": "application/json, text/plain, */*",
            "Content-Type": "application/json",
          },
        }
      )
      .pipe(retry(3), catchError(this.handleError))
  }

  handleError(error: HttpErrorResponse) {
    if (error.status === 0) {
      // A client-side or network error occurred. Handle it accordingly.
      console.error("An error occurred:", error.error)
    } else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong.
      console.error(`Backend returned code ${error.status}, body was: `, error.error)
    }
    // Return an observable with a user-facing error message.
    return throwError(() => new Error("Something bad happened; please try again later."))
  }
}

See full documentation for the Support Checker

iproov-support-checker.service.ts

import { Injectable } from "@angular/core"
import { iProovSupport, iProovSupportCheck } from "@iproov/web-sdk/iProovSupport" // import support checker from iproov web sdk package

@Injectable({
  providedIn: "root",
})
export class IproovSupportCheckerService {
  public checkDeviceIsSupported(): Promise<iProovSupportCheck> {
    // ensure assurance_type matches token generated assurance_type
    const iProovSupportChecker = new iProovSupport(console, { assurance_type: "genuine_presence" }) 
    return iProovSupportChecker.check()
  }
  public checkDeviceIsSupportedWithEvent() {
    // ensure assurance_type matches token generated assurance_type
    const iProovSupportChecker = new iProovSupport(console, { assurance_type: "genuine_presence" })
    iProovSupportChecker.addEventListener("check", (event: any) => {
      const { supported, granted, is_native_bridge } = event.detail
      console.log("iProov support check response", event.detail)
      if (supported === false) {
        // go to fallback UX
      }
      if (supported && granted) {
        // full permission and granted, we can definitely iProov!
        if (is_native_bridge) {
          // if native bridge mode has been detected then permission checks have been circumvented as they aren't needed
        }
      }
      if (supported && granted === null) {
        // browser API support, but we haven't run a permission check (see checkWithPermission)
      }
      if (supported && granted === false) {
        // browser API support, but camera access denied - try again or advise user before proceeding
      }
    })
    iProovSupportChecker.check()
  }
  public checkDeviceIsSupportedWithPermission(): Promise<iProovSupportCheck> {
    const iProovSupportChecker = new iProovSupport()
    return iProovSupportChecker.checkWithPermission()
  }
}