okyc_flutter 0.1.1
okyc_flutter: ^0.1.1 copied to clipboard
OKYC identity verification for Flutter: the hosted KYC/KYB flow in a secure, full-screen WebView with native permissions, file picking and results.
okyc_flutter #
Flutter SDK for OKYC. It opens a verification session's hosted flow in a hardened WebView and returns a typed result. It follows the shared mobile SDK contract: protocol v1 bridge, result mapping and WebView rules. Full guide: docs.okyc.stream/mobile/flutter.
- Android and iOS (Flutter ≥ 3.24, Dart ≥ 3.5, Android minSdk 24, iOS 15).
- Built on
webview_flutter4.x plus a small native plugin that handles screenshot blocking, Android camera permission and the Android file chooser.
Install #
flutter pub add okyc_flutter
iOS #
Set the minimum iOS version to 15.0 (Podfile platform :ios, '15.0', or the Runner target's deployment target when using Swift Package Manager). Then add the camera strings to Info.plist:
<key>NSCameraUsageDescription</key>
<string>Take a selfie and photograph your documents to verify your identity.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Choose a photo of your document to verify your identity.</string>
Android #
The plugin's manifest already declares INTERNET and CAMERA, the <queries> for camera and document pickers, and a FileProvider scoped to cache/okyc/. Nothing else is needed.
Usage #
Your server creates the session with its secret key (POST /v1/sessions) and sends the app only the url. Never ship a secret key in the app.
import 'package:okyc_flutter/okyc_flutter.dart';
final result = await Okyc.start(
context,
OkycConfig(sessionUrl: url /* https://verify.okyc.stream/s/ses_…#t=st_… */, locale: 'en'),
onEvent: (e) => debugPrint('${e.type} ${e.payload}'), // analytics only
);
switch (result) {
case OkycCompleted(:final sessionId, :final status):
// status is a hint (`approved`, `rejected`, `in_review`…). Trust only your server:
// the session.completed webhook, or GET /v1/sessions/{id}.
await myBackend.refreshKyc(sessionId);
case OkycCancelled():
// The user closed the flow. The same link can be reopened while it is valid.
break;
case OkycFailed(:final code, :final message):
// OkycFailureCode.invalidConfig | loadFailed | networkError | navigationBlocked | permissionDenied | flowError
showError(message);
}
Okyc.start pushes a full-screen route with an ✕ close button. Both ✕ and the Android back gesture ask "Exit verification?" before returning OkycCancelled. The route closes itself about 2 s after the flow reports complete, so the user sees the result screen.
If you want to place the flow in your own layout, embed OkycVerification(config:, onResult:) directly. Your app then owns the navigation and the exit confirmation.
OkycConfig #
| Field | Default | |
|---|---|---|
sessionUrl |
required | https://…/s/ses_…#t=st_…. Plain http is accepted only for localhost, 127.0.0.1, 10.0.2.2 and ::1. |
locale |
null |
Sent as ?locale=. The token stays in the URL fragment. |
theme |
system |
Sent as ?theme=; light or dark forces the flow's theme. |
allowedHosts |
[] |
Extra hosts (or https://host:port origins) allowed inside the WebView. |
blockScreenshots |
true |
Android FLAG_SECURE. On iOS, a privacy cover in the app switcher and while the screen is recorded. |
autoCloseDelay |
2s |
Time between complete and the result. |
confirmExit |
true |
Ask before closing. |
title |
Verify your identity |
App bar title. |
Security behaviour #
-
Bridge. Messages arrive on the
OkycFlutterJavaScript channel. They are dropped if they:- arrive while the WebView shows any page other than the session's own origin (DigiLocker, your
allowedHosts), - are larger than 10 KB,
- don't match
{source:'okyc', v:1}, - have an unknown
type, - carry a different session id, or
- have a nested payload.
Callbacks never receive PII, only step names and statuses.
- arrive while the WebView shows any page other than the session's own origin (DigiLocker, your
-
Navigation. The WebView may only visit:
- the session's own origin,
- DigiLocker (
digilocker.meripehchaan.gov.in,*.digilocker.gov.in,api.digitallocker.gov.in), and - your
allowedHosts.
Other
httpslinks on the top-level page open in the system browser; plainhttplinks and links inside frames are refused. Every other scheme is refused, includingfile:,javascript:,data:,intent:andtel:. A run of refused navigations (more than 5 in 3 s) ends the flow withnavigation_blocked. -
Camera. Access is granted only while the WebView shows the session origin. On Android it is also granted only after the OS permission. iOS asks through WebKit (
allowsInlineMediaPlayback, and no user gesture is required for media). -
Files. On Android,
<input type=file>opens the system picker, with a camera option. Withcapture, it opens the camera directly. Photos taken this way are deleted from the app cache when the flow ends. WebView file access is off. -
Cleanup. When the flow finishes, the SDK clears the flow's
sessionStorageandlocalStorage, the WebView cache and the camera photos, and turns screenshot blocking off. The WebView shares cookies with your app, so the SDK doesn't clear them. If your app has no other web views, callWebViewCookieManager().clearCookies()after the result to also sign out of DigiLocker. -
Debugging. WebView debugging (Chrome and Safari inspectors) is on only in debug builds.
Limitations #
- The minimum is Flutter 3.24, not the 3.22 in the contract table, because the current
webview_flutterplatform packages need Dart 3.5. - iOS can't block user screenshots. The SDK hides content in the app switcher and during screen recording or mirroring.
- On Android, clearing the WebView cache clears the whole app's WebView cache, not just the flow's.