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 & Capabilities
tab, 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 install
this 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 cmd
To 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 resolved
Note 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 cmd
Note 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 cmd
Note 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
CANCEL
command 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 resolved
As 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
handleAuthSuccess
handler
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
CANCEL
command 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.cardIsBlocked
error andhandleChangePinCancel
andhandleAuthFailed
will 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_PIN
workflow 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
CANCEL
command while the NFC popup is visible will result in aBAD_STATE
message.
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')