Online and offline presentments (ISO 18013) 

This page explains how to use the public MobileIDInPersonSharing API for ISO 18013 presentments. It covers both offline QR-based sessions and online sessions started from encoded engagement data, plus the request, consent, transfer, and error-handling flow shared by both modes.

What This Covers 

  • creating an ISO 18013 handler with MobileID.iso()
  • starting an offline session or an online session
  • retaining the session and receiving delegate callbacks
  • reading the verifier request and selected data items
  • accepting or declining a request
  • tracking transfer progress
  • handling ISO 18013 errors

Public API Surface 

Session Setup 

  • MobileID.iso() -> ISO18013
  • ISO18013.createSession() -> Session
  • ISO18013.createSession(encodedData:shouldProceedOnSSLError:) -> Session
  • Session.start(delegate:)
  • Session.end()
  • SessionDelegate

Request And Transfer 

  • Request
  • Request.items
  • Request.verifierInfo
  • Request.respond(decision:) -> Transfer
  • UserSharingDecision.accept(_:)
  • UserSharingDecision.decline
  • Transfer
  • Transfer.start(delegate:) async throws
  • Transfer.progress
  • TransferDelegate
  • TransferProgress

Data And Errors 

  • DataItem
  • ISO18013.Error
  • ISO18013.Error.userVisibleCode

End-To-End Flow 

diagram

1. Create The ISO 18013 Handler 

Start from the MobileID instance you already created during app bootstrap:

Swift
1import MobileIDInPersonSharing
2
3let iso18013 = mobileID.iso()

Use the same handler type for both offline and online sessions.

2. Start An Offline Session 

Offline sessions are the QR-based presentment path. Create the session, keep it alive for as long as the presentment is active, and start it with a SessionDelegate: typically begins from a QR code and uses Bluetooth for the reader connection. Start them by creating the session with iso18013.createSession() and keeping the returned session alive for the duration of the interaction.

Swift
1import MobileIDInPersonSharing
2import UIKit
3
4final class OfflinePresentmentCoordinator: NSObject, SessionDelegate {
5 private let navigationController: UINavigationController
6 private let iso18013: ISO18013
7 private var session: Session?
8
9 init(iso18013: ISO18013, navigationController: UINavigationController) {
10 self.iso18013 = iso18013
11 self.navigationController = navigationController
12 }
13
14 func start() {
15 let session = iso18013.createSession()
16 self.session = session
17 session.start(delegate: self)
18 }
19
20 func session(_ session: Session, generated qrCode: QrCode) {
21 // Show the QR code to the verifier.
22 }
23
24 func connectionHasBeenEstablished(for session: Session) {
25 // Update the UI when the reader connects.
26 }
27
28 func session(_ session: Session, hasReceived request: Request) {
29 presentDecisionUI(for: request)
30 }
31
32 func sessionHasFinishedSuccessfully(_ session: Session) {
33 self.session = nil
34 }
35
36 func session(_ session: Session, hasEncountered error: ISO18013.Error) {
37 self.session = nil
38 print("ISO 18013 error: \(error.userVisibleCode)")
39 }
40
41 func notification(_ request: AuthenticationRequest, promptedForAuthentication authenticationPrompt: PinViewController) {}
42 func notification(_ request: AuthenticationRequest, promptedForAuthentication authenticationPrompt: FaceViewController) {}
43 func didFinishAuthentication(of request: AuthenticationRequest) {}
44 func notificationDidBecomeBusy(_ request: AuthenticationRequest, expectedInterval: NavigatorBusyStateInterval) {}
45 func notificationDidBecomeIdle(_ request: AuthenticationRequest) {}
46
47 private func presentDecisionUI(for request: Request) {
48 let items = request.items
49 let verifierName = request.verifierInfo?.organizationName
50 print("Requested items: \(items), verifier: \(String(describing: verifierName))")
51 }
52}

The session must be retained for the entire presentment. Call end() when you want to stop the flow explicitly.

3. Start An Online Session 

Online sessions use encoded engagement data provided by the verifier or deep-link flow:

Swift
1import MobileIDInPersonSharing
2
3let onlineSession = iso18013.createSession(
4 encodedData: engagementPayload,
5 shouldProceedOnSSLError: false
6)
7onlineSession.start(delegate: sessionDelegate)

Use the online variant when the engagement is already encoded and you want the same request/transfer flow without the QR-based engagement step.

4. Accept Or Decline A Request 

When the delegate receives a Request, inspect the requested items and decide whether to share a credential:

Swift
1func handle(request: Request, credential: EnrolledCredential) async {
2 let transfer = request.respond(decision: .accept(credential))
3 do {
4 try await transfer.start(delegate: self)
5 } catch {
6 print("Transfer failed: \(error)")
7 }
8}
9
10func decline(request: Request) {
11 let transfer = request.respond(decision: .decline)
12 Task {
13 try? await transfer.start(delegate: self)
14 }
15}

Request.items tells you which data elements the verifier asked for. Request.verifierInfo is optional and can be used to display the organization name if the system provides it.

Only share a credential the user has explicitly chosen. If the user declines, the transfer still runs so the request can be completed cleanly with an empty response.

5. Track Transfer Progress 

TransferDelegate lets you observe write progress while the response is being sent:

Swift
1extension OfflinePresentmentCoordinator: TransferDelegate {
2 func transfer(_ transfer: Transfer, made progress: TransferProgress) {
3 print("Sent \(progress.itemsSent) of \(progress.itemsTotal)")
4 }
5}

TransferProgress exposes:

  • itemsSent
  • itemsTotal
  • fractionCompleted
  • isCompleted

Treat the progress callbacks as UI hints. They are useful for loading indicators and accessibility announcements, but they should not drive business logic. Online sessions usually complete in a single response handoff, so progress is often less granular than an offline transfer.

6. Handle Presentment Errors 

ISO18013.Error covers QR parsing, connection, MSO validity, authentication, and response failures.

Common examples include:

  • invalidQRCodePayload
  • invalidMdocPayload
  • expiredMSO
  • connectionFailed
  • authenticationKeyExpired
  • invalidAuthentication
  • credentialLocked
  • invalidResponse

Use userVisibleCode when you need a stable support code for logs or customer care.

Implementation Notes 

  • Keep the Session alive until the request/transfer flow completes.
  • Use the offline session when the verifier starts from a QR code.
  • Use the online session when the verifier provides encoded engagement data.
  • Present only the credential the user selected.
  • Read Request.items before building your consent UI so the user can see what will be shared.
  • Call Session.end() when the flow is no longer needed.
  • Getting Started
  • Credential Wallet And Lifecycle
  • Digital Credential API (ISO/IEC 18013-7 Annex C)
  • PIN And Liveness Verification