Fetch channel best practices
The fetch channel lets the application retrieve the out-of-band operations that are pending for the device, using the PendingOutOfBandOperations java, swift, objc, flutter, react native API. Instead of waiting for a push notification, a scanned QR code or a followed link, the application asks the backend which operations are waiting to be processed and completes them from within the application.
This chapter describes when to use the fetch channel and the best practices to follow. For the API description and code to obtain an OutOfBandPayload from a pending operation, see Out-of-band payload from pending operations (fetch channel). For conceptual information, see Using fetch.
When to use the fetch channel
The fetch channel is a complement to the other out-of-band channels, not a replacement for them. It is most valuable in the following scenarios.
Missed push
The primary use case is the missed push scenario. A push notification can fail to reach the device for many reasons: the device was offline when the notification was sent, the push service was temporarily unavailable, or the user disabled notifications for the application. In all of these cases the operation still exists in the backend and can be retrieved through the fetch channel, so the user is not blocked.
Accessibility
The fetch channel also improves accessibility. A user who cannot scan a QR code or reliably follow a link, for example a visually impaired user, can still complete an operation that was dispatched through a QR code or link channel. Because the fetch channel surfaces the pending operation directly inside the application, the operation can be completed without a camera scan.
For this reason, do not blindly filter the retrieved operations down to the push channel only when accessibility matters. Consider also surfacing the operations that were dispatched through the link and QR code channels.
Do not poll
Fetch pending operations in response to a meaningful trigger, such as the application coming to the foreground or an explicit user action, and never in a continuous polling loop. Polling generates unnecessary load on the backend and drains the battery and the mobile data of the device without improving the user experience.
To avoid redundant network requests, guard the fetch behind a few simple conditions:
- Do not fetch when no user is registered on the device, because there cannot be any pending operation.
- Do not fetch again if a recent fetch already returned the pending operations. A short throttling window, for example five seconds, is enough to prevent a foreground event and an immediately following user action from triggering two network requests.
- Do not fetch when an incoming push notification, link or QR code is already going to start the operation, because that would be redundant.
Both the Nevis Access App for Android and for iOS follow this model: they fetch on foreground and on explicit user action, keep a single fetch in flight at a time, and reuse the cached result within a short throttling window.
Filtering operations
The pendingOutOfBandOperations call returns every operation that is currently pending for the device. The operations are already ordered by their creation time, so the most recent operation is the last one in the list.
You can filter the returned operations by their dispatch channel, using the dispatchChannel java, swift, objc, flutter, react native property, or by their creation time. As described in the Accessibility section, choose the set of channels to react to based on the needs of the user, and do not restrict the fetch channel to push operations only when accessibility is a concern.
The following snippet shows two alternative filtering policies: reacting to the push channel only, or reacting to a wider set of channels for accessibility. These policies are mutually exclusive. Pick the single policy that fits your application, so that an operation is not processed more than once.
- Android/Kotlin
- Android/Java
- iOS/Swift
- iOS/Objective-C
- Flutter/Dart
- React Native/TypeScript
loading...
loading...
loading...
loading...
loading...
loading...
Avoiding duplicate redemption
Any out-of-band operation is started by redeeming the token contained in the out-of-band payload, and a token can only be redeemed once. An attempt to redeem the same token more than once results in an error: OutOfBandOperationError.TokenAlreadyRedeemed. See Out-of-band payload from pending operations (fetch channel) for details.
Duplicate redemption is easy to trigger when the fetch channel is combined with the push, QR code or link channels, because the same operation can reach the application through more than one channel. To detect duplicates, use the redeem token as the identifier of the operation. The token is available through the payload.redeemData.token property chain and uniquely identifies the operation.
The redeem token, not a separate operation identifier, is the value to use for deduplication. The PendingOutOfBandOperation object does not expose an operation identifier; the redeem token serves this purpose.
Keep a cache of the tokens that were already redeemed during the runtime of the application, and filter the retrieved operations against that cache before handling them. Both the Nevis Access App for Android and for iOS maintain such a cache of redeemed tokens for exactly this purpose.
A cache of already-redeemed tokens is not enough on its own to prevent a race. The same operation can arrive through the push and the fetch channel at almost the same time, and each arrival can pass the check before the other has redeemed the token. To close this window, dispatch the operations through a single serialized pipeline, and mark the token as in progress before starting the redemption rather than only after it succeeds. Remove the token from the in-progress set again if the redemption fails, so the user can retry. The Nevis Access App for iOS serializes its operation handling for this reason.
- Android/Kotlin
- Android/Java
- iOS/Swift
- iOS/Objective-C
- Flutter/Dart
- React Native/TypeScript
loading...
loading...
loading...
loading...
loading...
loading...
Combining with other channels
When the fetch channel is combined with push notifications, reconcile the local state after each fetch. If the application shows a local notification for a missed push, cancel the notifications whose operation is no longer in the pending list, so the user is not presented with an operation that was already handled or that timed out. Caching the redeemed tokens, as described in Avoiding duplicate redemption, also prevents the application from starting an operation that was already completed through another channel.
Prerequisites and error handling
Keep the following in mind when integrating the fetch channel:
- The fetch channel is served by nevisFIDO. It is available with the Nevis Authentication Cloud, and with the Nevis Identity Suite from nevisFIDO version 7.2402.1.2 or later.
- The fetch channel calls the Get Device Out-of-band Operations endpoint of nevisFIDO.
- For users whose first registration was done with Android SDK 3.6.1 or 3.6.2, this operation does not call the endpoint and returns an empty result, because of a known issue. See the caution in Out-of-band payload from pending operations (fetch channel) for details.
- The result carries both the retrieved operations and any errors that occurred. When the device is registered against more than one backend, the fetch can succeed for some backends and fail for others, so the result can contain operations and errors at the same time. Process the available operations and handle every returned error, rather than treating the result as all-or-nothing. For example,
ClockSkewTooBigindicates a discrepancy between the system clock of the device and the backend. For the complete list, see Error handling. - Because the fetch channel accesses a protected endpoint without explicit user interaction, it relies on the device being able to sign the request. See Security considerations for more information.