2.11.1 • Published 2 years ago

@pass-culture/id-check v2.11.1

Weekly downloads
-
License
UNLICENSED
Repository
github
Last release
2 years ago

@pass-culture/id-check

ID Check module can be used to implement identity check in an existing application.

It is build with React Native, and it supports iOS, Android and Web targets.

Table of Contents


Installation

yarn add @pass-culture/id-check

You must install the peer dependencies.

react-native

yarn add react-native-modal

If you have not done it yet, install all the peerDependencies (see package.json)

If you want to use the repo instead of the node_module in a project, run:

yarn link "@pass-culture/id-check"

react-native-web

yarn add modal-enhanced-react-native-web react-native-svg-web react-native-web-lottie

Edit your resolve.alias webpack configuration with:

+ 'react-native-modal$': 'modal-enhanced-react-native-web',
+ 'react-native-svg': 'react-native-svg-web',
+ 'lottie-react-native': 'react-native-web-lottie',

Edit your moduleNameMapper jest configuration with:

+ 'react-native-modal$': 'modal-enhanced-react-native-web',
+ 'react-native-svg': 'react-native-svg-web',
+ 'lottie-react-native': 'react-native-web-lottie',

API

Those are exports exposed:

Export nameTypeDescription
IdCheckContextProviderReact.ComponentThe IdCheck context
useIdCheckContextReact.HookRead the whole IdCheck context (can be useful to know the id check state)
IdCheckAnalyticsInterfaceInterfaceInterface used to create a custom Id Check analytics client
IdCheckErrorMonitoringInterfaceInterfaceInterface used to create a custom error monitoring client
routesArray<Route>Array of all IDCheck routes
IdCheckRootStackParamListInterfaceStack params for each screens required by the route. Only for TypeScript to know each Id Check route params
initialRouteNamestringThe home screen name of Id Check
linkingConfigLinkingOptionsLinking configuration for React Navigation
IdCheckHomePageReact.ComponentThe Id Check Home page including error boundary, auth persistence, auth and security checkpoint
cameraOptionsCameraOptionsDefault options used in react-native-image-picker when taking pictures
imageLibraryOptionsImageLibraryOptionsDefault options used in react-native-image-picker when opening image gallery
CampaignTrackerInterfaceInterfaceInterface used for tracking campaign events: startIdCheckTrack, uploadDocuments, accountCreated and email
IdCheckRetentionClientInterfaceInterface used to create a retention client, used when retention mode is active

Required for demonstration purpose by the Native application, we also added those to exports:

Export nameTypeDescription
IdCheckErrorsEnumEnum with all Id Check errors
IdCheckErrorIdCheckErrorError object used to throw Id Check custom error
withAsyncErrorBoundaryHoCError boundary higher order component for Id Check
EduconnectReact.ComponentEduconnect page that navigates to educonnect webview

Usage

You must wrap your React application within an <IdCheckContextProvider />.

The module can be configured by injecting props into the ID Check context:

ID Check context propsTypeRequiredDefaultDescription
Initialization
initialStepStepNoid-checkInitial step (only useful in retention mode)
URLs
jouveApiBaseUrlstringYesBase URL used for Id Check API call
homePageUrlstringYesBase URL used for success redirection
supportEmailstringYesEmail address used for support links
dsmUrlstringYesURL for DSM links
personalDataDocUrlstringYesURL for personal data documentation
cguDocUrlstringYesURL for usage right documentation
dmsFrenchCitizenshipUrlstringYesURL for DMS french citizen
dmsForeignCitizenshipUrlstringYesURL for DMS foreign citizen
Features flips
displayDmsRedirectionbooleanNoDisplay a DMS redirections when active
retentionbooleanYesSet and switch to retention mode
shouldUseEduConnectbooleanYesEnable eduConnect identification method
Services
analyticsIdCheckAnalyticsInterfaceYesServices used for tracking analytics events
errorMonitoringIdCheckErrorMonitoringInterfaceYesServices used for error monitoring
campaignTrackerCampaignTrackerInterfaceYesServices used for campaign tracking
requestLicenceTokenPromise<{ licence_token: string, expiration_timestamp: number }>NoFetch request client can be provided to allow user to get a new licence_token when necessary
retentionClientIdCheckRetentionClient<RetentionIdDocumentResponse>NoServices used when retention is active
eduConnectClientEduConnectClientNoServices used when eduConnect identification method is active
Events
onAbandon({ pageName, form }: { pageName: string, form: Record<string, unknown> }) => voidYesCallback used when user abandon the identity check
onSuccess() => voidYesCallback used when user successfully end the identity check
Camera
imagePickerOptionsImagePickerOptionsNo(cf. API)Reconfigure react-native-image-picker options used when taking pictures or opening gallery
Utilities
debugbooleanNofalseEnable verbose analytics mode, useful for troubleshooting session issues

Navigation configuration

Since it can work on iOS, Android and Web, we highly recommend to use React Navigation 5 for your application routing.

initialRouteName

The initialRouteName is IdCheckV2, it can be reconfigured by passing initialRouteName to the Id Check Context.

React Navigation 5

It is the default navigation.

React Router 5

For demonstration purpose, we can use React Router in the Web Application of Id Check.

This is possible thanks to @pass-culture/react-navigation-to-react-router-adpater.

The adapter only have support for React Navigation method used by Id Check. We may later extend it's support if we decide to use React Router for the Web version of App Native

Create an ID Check Analytics client

Using IdCheckAnalyticsInterface, you can create your own analytics client and track ID Check events:

import React from 'react'
import { IdCheckAnalyticsInterface } from '@pass-culture/id-check'

export const idCheckAnalyticsClient: IdCheckAnalyticsInterface = {
  cancelSignUp({ pageName }) {},
  identityError() {},
  idValid() {},
  invalidAge() {},
  invalidDate() {},
  invalidDocument() {},
  invalidTwice() {},
  processCompleted() {},
  wrongSideDocument() {},
  externalLink({ href, canOpen }) {},
  fileSizeExceeded() {},
  permissionsBlocked() {},
  // method below only active when `debug` is on
  hasValidSession({ valid, accessToken, accessTokenExpiresAt }) {},
  startCheckTokens() {},
  endCheckTokens() {},
  getJouveToken({
    appIsAllowedToRenewLicenceToken,
    isLocalLicenceToken,
    licenceToken,
    licenceTokenExpirationTimestamp,
    success,
    accessToken,
    accessTokenExpiresAt,
  }) {},
  getLicenceToken({ isError, errorCode, licenceToken, licenceTokenExpirationTimestamp }) {},
  startDmsTransmission() {},
  takeIdCheckPicture() {},
  confirmIdCheckPicture() {},
}

Create an ID Check Error Monitoring client

Using IdCheckErrorMonitoringInterface<Scope, MonitoringUser, CaptureContext>, you can create your own error monitoring client and track ID Check errors:

As an example with @sentry/react-native:

import * as SentryModule from '@sentry/react-native' // or @sentry/react
import { CaptureContext, User } from '@sentry/types'
import { IdCheckErrorMonitoringInterface } from '@pass-culture/id-check'

export const errorMonitoring: IdCheckErrorMonitoringInterface<
  SentryModule.Scope,
  User,
  CaptureContext
> = {
  captureException: SentryModule.captureException,
  captureEvent: SentryModule.captureEvent,
  captureMessage: SentryModule.captureMessage,
  configureScope: SentryModule.configureScope,
  init: SentryModule.init,
  setUser: SentryModule.setUser,
}
  • captureException: will be call within the AsyncErrorBoundary, which is wrapping every Id Check screens.
  • captureEvent: when provided, can be used to capture event when debug is ON.
  • captureMessage: when provided, can be used to capture message when debug is ON.
  • configureScope: method can be used to reconfigure the error monitoring context.
  • init: initialize the error monitoring service.
  • setUser: add a user to the error monitoring scope.

You MUST call the error monitoring init from within your application at the very beginning.

Create an Id Check Retention Client

Retention mode was created to validate Identity Document asynchronously. In this mode, document will be upload to any backend, which will be in charge of the Identity Check processing.

After creating a retention service on your serveur, you'll have to create a retentionClient, this is the signature:

export type IdCheckRetentionClient = {
  confirmProfile: (values?: Partial<UserProfile>) => Promise<void | EmptyResponse>
  uploadDocument: (file: IdCheckFile) => Promise<IdDocumentResponse | EmptyResponse>
}

Since it is asynchronous, you can use an empty object {} in your response as you may not have the IdDocumentResponse.

To activate the retention, you must set within the Id Check Context retention=true.

Error handling

  • uploadDocument is called to upload the identity document. If the success code is not 200/204, you must handle the error accordingly using the ApiError, see example below.
  • confirmProfile is called at the end. If the success code is not 200/204, it will display service-unavailable error.

Retention Example

import {
  ApiError as IdCheckApiError,
  IdCheckErrors,
  IdCheckRetentionClient,
  UserProfile,
  IdCheckFile,
  LocalStorageService,
} from '@pass-culture/id-check'

import { api } from 'api/api'
import { ActivityEnum, BeneficiaryInformationUpdateRequest } from 'api/gen'
import { ApiError } from 'api/helpers'

export const idCheckRetentionClient: IdCheckRetentionClient = {
  confirmProfile(values?: Partial<UserProfile>) {
    return api.patchnativev1beneficiaryInformation({
      ...(values?.address ? { address: values?.address } : {}),
      ...(values?.city ? { city: values?.city } : {}),
      ...(values?.email ? { email: values?.email } : {}),
      ...(values?.phone ? { phone: values?.phone } : {}),
      ...(values?.postalCode ? { postalCode: values?.postalCode } : {}),
      ...(values?.status ? { activity: values?.status as ActivityEnum } : {}),
    } as BeneficiaryInformationUpdateRequest)
  },
  uploadDocument: async (file: IdCheckFile) => {
    let error, token
    try {
      token = await LocalStorageService.getLicenceToken()
      if (!token) {
        error = new IdCheckApiError('Auth required', 400, {
          code: IdCheckErrors['auth-required'],
        })
      }
    } catch (err) {
      error = err
    }
    if (error) {
      return Promise.reject(error)
    }
    try {
      const data = new FormData()
      data.append('token', token)
      data.append('identityDocumentFile', file as Blob)
      return await api.postnativev1identityDocument({
        body: data,
      })
    } catch (err) {
      error = err
      if (err instanceof ApiError) {
        if (err.content.code === 'EXPIRED_TOKEN') {
          error = new IdCheckApiError(err.content.message, err.statusCode, {
            code: IdCheckErrors['auth-token-expired'],
          })
        } else if (err.content.code === 'INVALID_TOKEN') {
          error = new IdCheckApiError(err.content.message, err.statusCode, {
            code: IdCheckErrors['auth-required'],
          })
        } else if (err.content.code === 'FILE_SIZE_EXCEEDED') {
          error = new IdCheckApiError(err.content.message, err.statusCode, {
            code: IdCheckErrors['file-size-exceeded'],
          })
        } else if (err.content.code === 'SERVICE_UNAVAILABLE') {
          error = new IdCheckApiError(err.content.message, err.statusCode, {
            code: IdCheckErrors['validation-unavailable'],
          })
        }
      }
      return Promise.reject(error)
    }
  },
}

Add ID Check routes to your existing application

You can use the export from the module to create routes in your application:

  • routes: necessary to add ID Check routes to your applications.
  • initialRouteName: can be necessary if your application home page is ID Check home, or to remap the ID Check home route.

Navigate to ID Check

  1. When navigating to ID Check route, you can provide a licence_token and it's expiration_timestamp (in ms), if:
    • the licence_token is expired:
      • requestLicenceToken exist in the context: we get a new licence token, if:
        • it fail with 400 http status code, user see TooManyAttempt error page
        • it succeed, user continue to ID Check home
      • requestLicenceToken does not exist in the context, we can't start id check:
        • it fail: user see SessionExpired error page (Usually for Webapp v1 which MUST pass licence_token and expiration_timestamp query param to the base URL endpoint of the standalone Id Check V2 App)
    • the licence_token is invalid:
      • it fail: user see SessionExpired error page

requestLicenceToken

A fetch client that does a unique request can be provided to automatically get a new licence_token when needed.

This is useful in the native application since the user and can call the secure API /native/v1/id_check_token endpoint.

Example

Within your App.js in a new project:

import React, { createRef } from 'react'
import { initialRouteName, routes, linkingConfig, RootStackParamList } from '@pass-culture/id-check'
import { NavigationContainer, NavigationContainerRef } from '@react-navigation/native'
import { createStackNavigator } from '@react-navigation/stack'

import { errorMonitoring, analytics } from './services'

const navigationRef = createRef<NavigationContainerRef>()
const Stack = createStackNavigator<RootStackParamList>()

function App() {
  function onSuccess() {
    console.log('success')
  }

  function onAbandon() {
    console.log('abandon')
  }

  return (
    <IdCheckContextProvider
      retention={false}
      errorMonitoring={errorMonitoring}
      analytics={analytics}
      onSuccess={onSuccess}
      onAbandon={onAbandon}>
      <NavigationContainer
        linking={linkingConfig}
        fallback={<div>Chargement...</div>}
        ref={navigationRef}>
        <Navigator
          initialRouteName={initialRouteName}
          screenOptions={{
            headerShown: false,
            cardShadowEnabled: false,
            cardStyle: {
              backgroundColor: 'transparent',
              flex: 1,
            },
          }}>
          {routes.map((route: Route) => (
            <Screen
              key={route.name}
              name={route.name}
              component={route.component}
              options={route.options}
              // Below is extra features used by @pass-culture/react-navigation-to-react-router-adapter
              // eslint-disable-next-line @typescript-eslint/ban-ts-comment
              // @ts-ignore
              from={route.from}
              path={route.path}
              strict={route.strict}
              exact={route.exact}
              push={route.push}
              to={route.to}
            />
          ))}
        </Navigator>
      </NavigationContainer>
    </IdCheckContextProvider>
  )
}

export default App
2.11.0

2 years ago

2.11.1

2 years ago

2.10.16

2 years ago

2.10.17

2 years ago

2.10.18

2 years ago

2.10.19

2 years ago

2.10.20

2 years ago

2.10.21

2 years ago

2.10.10

3 years ago

2.10.11

3 years ago

2.10.12

3 years ago

2.10.13

3 years ago

2.10.14

3 years ago

2.10.15

3 years ago

2.10.9

3 years ago

2.10.7

3 years ago

2.10.8

3 years ago

2.10.5

3 years ago

2.10.6

3 years ago

2.10.4

3 years ago

2.10.1

3 years ago

2.10.2

3 years ago

2.10.3

3 years ago

2.9.5

3 years ago

2.10.0

3 years ago

2.6.1

3 years ago

2.6.0

3 years ago

2.8.1

3 years ago

2.8.0

3 years ago

2.9.2

3 years ago

2.9.1

3 years ago

2.9.4

3 years ago

2.9.3

3 years ago

2.7.0

3 years ago

2.9.0

3 years ago

2.7.2

3 years ago

2.7.1

3 years ago

2.8.3

3 years ago

2.8.2

3 years ago

2.5.4

3 years ago

2.5.3

3 years ago

2.5.2

3 years ago

2.5.0

3 years ago

2.5.1

3 years ago

2.4.7

3 years ago

2.4.6

3 years ago

2.4.5

3 years ago

2.4.4

3 years ago

2.4.3

3 years ago

2.4.2

3 years ago

2.4.1

3 years ago

2.4.0

3 years ago

2.3.2

3 years ago

2.3.4

3 years ago

2.3.3

3 years ago

2.3.0

3 years ago

2.3.1

3 years ago

2.2.1

3 years ago

2.2.0

3 years ago

2.2.2

3 years ago

2.1.9

3 years ago

2.1.10

3 years ago

2.1.8

3 years ago

2.1.2

3 years ago

2.1.1

3 years ago

2.0.16

3 years ago

2.1.4

3 years ago

2.1.3

3 years ago

2.1.6

3 years ago

2.1.5

3 years ago

2.1.7

3 years ago

2.1.0

3 years ago

2.0.16-beta

3 years ago

2.0.19

3 years ago

2.0.17

3 years ago

2.0.18

3 years ago

2.0.24

3 years ago

2.0.16-beta.5

3 years ago

2.0.16-beta.4

3 years ago

2.0.22

3 years ago

2.0.16-beta.3

3 years ago

2.0.23

3 years ago

2.0.16-beta.2

3 years ago

2.0.20

3 years ago

2.0.21

3 years ago

2.0.15

3 years ago

2.0.13

3 years ago

2.0.14

3 years ago

2.0.12

3 years ago

2.0.11

3 years ago

2.0.10

3 years ago

2.0.9

3 years ago

2.0.8

3 years ago

2.0.7

3 years ago

2.0.6

3 years ago

2.0.5

3 years ago

2.0.4

3 years ago

2.0.3

3 years ago

2.0.2

3 years ago

2.0.1

3 years ago

2.0.0

3 years ago