A react-native module for the AusweisApp2 SDK. To learn more about AusweisApp2 sdk please refer to its documentation.
The communication with the AusweisApp2 SDK is facillitated by messages and commands. Please refer to AusweisApp2 documentation for the explanation of the commands and messages. Furthermore, you can make use of the example workflows from the documentation, which demonstrate the exchange of commands and messages in different contexts. Currently, only two workflows are supported - AUTH and CHANGE_PIN.
Module - React-Native module that wraps around the AusweisApp2 SDK
SDK - AusweisApp2 core functionality that is used in this module
$ yarn add @jolocom/react-native-ausweis
- Enable the card identifier in your applications
Info.plist. For more details refer to the AusweisApp documentation
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>E80704007F00070302</string>
</array>
<key>NFCReaderUsageDescription</key>
<string>AusweisApp2 needs NFC to access the ID card.</string>-
in Xcode's
Signing & Capabilitiestab, make sure Near Field Communication Tag Reading capability had been added. If this is the first time you toggle the capabilities, the Xcode will generate a .entitlement file for you -
(from the root of your project)
$ cd ios && pod installthis will trigger automatic linking
in AndroidManifest.xml
<uses-permission android:name="android.permission.NFC"/>(for react-native with version < 0.60.0)
$ react-native link @jolocom/react-native-ausweis
To start interacting with the SDK, you first need to initialize it
import { aa2Module } from '@jolocom/react-native-ausweis'
if (!aa2Module.isInitialized) {
try {
await aa2Module.initAa2Sdk()
} catch (e) {
console.error(e)
}
}Note: currently it is a noop method
await aa2Module.disconnectAa2Sdk()When you send a command to the SDK it will respond with a message (or more).
Below is the list of messages supported by the module.
export enum Messages {
init = 'INIT',
apiLevel = 'API_LEVEL',
badState = 'BAD_STATE',
info = 'INFO',
auth = 'AUTH',
accessRights = 'ACCESS_RIGHTS',
enterPin = 'ENTER_PIN',
enterPuk = 'ENTER_PUK',
enterCan = 'ENTER_CAN',
insertCard = 'INSERT_CARD',
certificate = 'CERTIFICATE',
reader = 'READER',
enterNewPin = 'ENTER_NEW_PIN',
changePin = 'CHANGE_PIN',
}Note, there are differences between how the NFC popup is handled on iOS and Android. On iOS, the NFC popup is managed by the SDK and is shown along with the INSERT_CARD message. However, on Android only the INSERT_CARD message is received, allowing the application to proceed with scanning.
Some received messages can be processed with handlers.
Below in the list of available message handlers and their signatures:
type CardInfo = {
inoperative: boolean
deactivated: boolean
retryCounter: number
}
interface EventHandlers {
handlePinRequest: (cardInfo: CardInfo) => void // msg ENTER_PIN
handleCanRequest: (cardInfo: CardInfo) => void // msg ENTER_CAN
handlePukRequest: (cardInfo: CardInfo) => void // msg ENTER_PUK
handleCardInfo: (cardInfo: CardInfo) => void // msg READER
handleCardRequest: () => void // msg INSERT_CARD
handleAuthFailed: (url: string, message: string) => void // msg AUTH (user has cancelled the RUN_AUTH flow or RUN_AUTH flow has failed)
handleAuthSuccess: (url: string) => void // msg AUTH (successful completion of the RUN_AUTH flow)
handleEnterNewPin: () => void // msg ENTER_NEW_PIN
handleChangePinCancel: () => void // msg CHANGE_PIN (success: false)
handleChangePinSuccess: () => void // msg CHANGE_PIN (success: true)
}To handle a message sent by the SDK you have to register a message handler.
aa2Module.setHandlers({
// your handlers
})For example, to handle the ENTER_PUK message, register its handler as follows:
aa2Module.setHandlers({
handlePinRequest: (cardInfo: CardInfo) => {
console.log(cardInfo)
}
})Reset handlers with:
aa2Module.resetHandlers()Similarly to handlers, the user can subscribe to message events. An example can be seen below:
aa2Module.messageEmitter.addListener(Messages.reader, (message: ReaderMessage) => {
...
})In order to communicate with the SDK, the React-Native application must send commands. As a result, the SDK will respond with messages according to the internal protocol. In case the received message does not satisfy the protocol, the command will reject with the Unknown message type error.
Note that each command returns a Promise, which either rejects or resolves based on the received messages. This may vary from command to command.
Nevertheless, messages can also be handled using the handlers registered with aa2Module.setHandlers(${handlers}). Here is the list of available message handlers.
To initiate the AUTH workflow, the module sends the RUN_AUTH command. As a response, the SDK sends both AUTH and ACCESS_RIGHTS messages.
The startAuth Promise will be resolved as soon as the ACCESS_RIGHTS message is received.
const tcTokenUrl = "https://test.governikus-eid.de/DEMO"
await aa2Module.startAuth(tcTokenUrl) // send RUN_AUTH cmdTo initiate the CHANGE_PIN workflow, the module sends the RUN_CHANGE_PIN command. As a response, the SDK will send the CHANGE_PIN message with payload: {success: false} if the workflow was interrupted (i.e. by canceling NFC popup on iOS), or the ENTER_PIN/ENTER_CAN/ENTER_PUK messages if the workflow continues.
Initiate the CHANGE_PIN workflow
aa2Module.setHandlers({
handleCardRequest: () => {
console.log('show NFC popup on Android')
}
handlePinRequest: (cardInfo) => {
console.log('showing pin input')
}
})
const message = await aa2Module.startChangePin()
// Sequence of events happening:
// 1. handler is registered with aa2Module.setHandlers
// 2. sending command aa2Module.startChangePin
// 3. a message is send { msg: "INSERT_CARD" }
// 4. INSERT_CARD handler runs: console.log('show NFC popup on Android')
// 3. user scans eID card
// 4. a message is send { msg: "ENTER_PIN" } and aa2Module.startChangePin promise is resolvedNote this command is part of the AUTH flow and should be sent only after AUTH workflow was initiated with
aa2Module.startAuth(tcTokenUrl)
To get more information about the requester, send the GET_CERTIFICATE command. As a result, it will be resolved with the CERTIFICATE message.
await aa2Module.getCertificate() // send GET_CERTIFICATE cmdNote this command is part of the AUTH flow and should be sent only after AUTH workflow was initiated with
aa2Module.startAuth(tcTokenUrl)
To select which data should be shared within the AUTH workflow, the SET_ACCESS_RIGHTS command is sent together with the choosen fields. As a response, the SDK will send the ACCESS_RIGHTS message.
const optionalFields = ['Address', 'DateOfBirth']
await aa2Module.setAccessRights(optionalFields) // send GET_CERTIFICATE cmdNote this command is part of the AUTH flow and should be sent only after AUTH workflow was initiated with
aa2Module.startAuth(tcTokenUrl)
To accept the selected access rights, the SDK sends the "ACCEPT" command. As a response, the SDK will send INSERT_CARD message. If user has scanned eID card successfully, the commands will be resolved with the ENTER_PIN/ENTER_CAN/ENTER_PUK messages. If user has cancelled the NFC popup, an AUTH message will be sent.
Note, canceling the NFC popup on iOS will cancel the workflow. You need to explicitly send the
CANCELcommand on Android.
// setup handler for the INSERT_CARD message
aa2Module.setHandlers({
handleCardRequest: () => {
console.log('show NFC popup on Android')
}
})
await aa2Module.acceptAuthRequest()
// Sequence of events happening:
// 1. handler is registered with aa2Module.setHandlers
// 2. sending command aa2Module.acceptAuthRequest
// 3. a message is send { msg: "INSERT_CARD" }
// 4. INSERT_CARD handler runs: console.log('show NFC popup on Android')
// 3. user scans eID card
// 4. a message is send { msg: "ENTER_PIN" } and aa2Module.acceptAuthRequest promise is resolvedAs a response to the ENTER_PIN message, the module should send the SET_PIN command (using the setPin method). Afterwards, the SDK can send ENTER_PIN (if the PIN provided doesn't match the one stored on the eID card), ENTER_CAN (if the wrong eID PIN was entered 2 times), ENTER_PUK (if the wrong eID PIN was entered 3 times), ENTER_NEW_PIN (if the corect PIN was entered during the CHANGE_PIN workflow), AUTH (if the AUTH workflow was successfully finished), CHANGE_PIN (if the CHANGE_PIN workflow was finished).
Below is an example of handlers for processing both the wrong PIN and the successful completion of the AUTH workflow.
Note, upon successful completion of AUTH workflow you should send a GET request to url provided as an argument to
handleAuthSuccesshandler
aa2Module.setHandlers({
handleCardRequest: () => {
console.log('show NFC popup on Android')
},
handlePinRequest: () => {
console.log('showing pin again, because wrong pin was entered')
},
handleAuthSuccess: (url) => {
console.log('successful completion of AUTH')
fetch(url)
},
})
await aa2Module.setPin('123456')
// Sequence of events happening:
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.setPin
// 3. a message is send { msg: "INSERT_CARD" }
// 4. INSERT_CARD handler runs: console.log('show NFC popup on Android')
// 3. user scans eID card
// 4. a message is send { msg: "ENTER_PIN" } and aa2Module.setPin promise is resolved
// 5. ENTER-PIN handler runs: console.log('showing pin again, because wrong pin was entered')Below is the example of interrupting the CHANGE_PIN workflow at the step when the eID pin was requested.
Note, on Android you should send the
CANCELcommand if you decide to interrupt the workflow.
aa2Module.setHandlers({
handleCardRequest: () => {
console.log('NFC popup is shown on iOS')
},
handleChangePinCancel: () => {
console.log('CHANGE_PIN workflow was interrupted')
},
})
await aa2Module.setPin('123456')
// Sequence of events happening:
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.setPin
// 3. a message is send { msg: "INSERT_CARD" }
// 4. INSERT_CARD handler runs: console.log('NFC popup is shown on iOS')
// 3. user presses "cancel" btn on NFC popup
// 4. a message is send { msg: "CHANGE_PIN", .success: false } and aa2Module.setPin promise is resolved
// 5. handleChangePinCancel handler runs: console.log('CHANGE_PIN workflow was interrupted')As a response to the ENTER_CAN message, the module should send the SET_CAN command. Following, the SDK responds with the ENTER_PIN message (if the provided CAN was correct), ENTER_CAN (if the provided CAN was incorrect), AUTH (if AUTH workflow was interrupted), CHANGE_PIN (if the CHANGE_PIN workflow was interrupted).
Below is an example of providing the wrong CAN
aa2Module.setHandlers({
handleCardRequest: () => {
console.log('NFC popup is shown on iOS')
},
handleCanRequest: () => {
console.log('wrong CAN')
},
})
await aa2Module.setCan('123456')
// Sequence of events happening:
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.setCan
// 3. a message is send { msg: "INSERT_CARD" }
// 4. INSERT_CARD handler runs: console.log('NFC popup is shown on iOS')
// 5. user scans eID card
// 6. a message is send { msg: "ENTER_CAN" } and aa2Module.setPin promise is resolved
// 7. handleCanRequest handler runs: console.log('wrong can')As a response to the ENTER_PUK message, the module should send the SET_PUK command. Afterwards, the SDK can send the ENTER_PIN message (if the provided PUK was correct), ENTER_PUK (if the provided PUK was incorrect), AUTH (if the AUTH workflow was interrupted), CHANGE_PIN (if CHANGE_PIN workflow was interrupted).
Note in case the card is blocked, the module will reject with
CardError.cardIsBlockederror andhandleChangePinCancelandhandleAuthFailedwill not be called
Below is an example of an attempt to provide the PUK within the CHANGE_PIN workflow but user's card is blocked (used the PUK correctly 10 times).
Note, that the same sequence of messages received will happen if user presses "cancel" on NFC popup on iOS
aa2Module.setHandlers({
handleCardRequest: () => {
console.log('NFC popup is shown on iOS')
}
handleChangePinCancel: () => {
console.log('change_pin workflow was interrupted')
}
})
try {
await aa2Module.setPuk('1234567890')
} catch(e) {
console.log('Error', e)
}
// Sequence of events happening:
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.setPuk
// 3. a message is send { msg: "INSERT_CARD" }
// 4. INSERT_CARD handler runs: console.log('NFC popup is shown on iOS')
// 5. user scans eID card
// 6. a message is send { msg: "CHANGE_PIN", success: false } and aa2Module.setPuk promise is rejected with `CardError.cardIsBlocked`
// 7. handleChangePinCancel won't run !!!Note this command is part of the CHANGE_PIN flow and should be sent only after the
CHANGE_PINworkflow was initiated.
As a response to the ENTER_NEW_PIN message, the module should send the SET_NEW_PIN command. Afterwards, the SDK will send the CHANGE_PIN msg with a (boolean) success property.
Completing CHANGE_PIN workflow by setting a new pin
aa2Module.setHandlers({
handleChangePinSuccess: () => {
console.log('CHANGE_PIN workflow was completed')
}
})
await aa2Module.setNewPin('123456')
// Sequence of events happening:
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.setNewPin
// 3. a message is send { msg: "CHANGE_PIN", success: true } and aa2Module.setNewPin promise is resolved
// 7. handleChangePinSuccess runs: console.log('CHANGE_PIN workflow was completed')To cancel the AUTH or CHANGE_PIN flows, send the CANCEL command.
Note that on iOS, pressing the "cancel" button on NFC popup also cancels the active workflow. Sending a
CANCELcommand while the NFC popup is visible will result in aBAD_STATEmessage.
As a response, the SDK can send the AUTH (if canceled within the AUTH workflow) or CHANGE_PIN (if cancelled within the CHANGE_PIN workflow) messages.
Canceling the AUTH workflow
aa2Module.setHandlers({
handleAuthFailed: (url, message) => {
console.log('AUTH workflow was interrupted')
}
})
await aa2Module.cancelFlow()
// Sequence of events happening:
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.cancelFlow
// 3. a message is send { msg: "AUTH", ...payload } and aa2Module.cancelFlow promise is resolved
// 7. handleAuthFailed runs: console.log('AUTH workflow was interrupted')