Mobile Widget SDKs
Authentication
The mobile app obtains a short-lived embed token from its own trusted backend. Returning.AI access credentials never enter the app.
Server-authenticated mobile widget
The native SDK owns the widget exchange while your backend owns customer identity and long-lived credentials.
Request an embed token
Signed-in mobile appCall your own authenticated backend. Do not send a customer identifier selected by an untrusted app screen.
- Your backend
Read the current host session and map it to the identifiers configured for the target Returning.AI widget.
Mint the embed token
Your backend and Returning.AIUse server-only access credentials to call the Returning.AI token endpoint and return only the short-lived embed token.
Exchange inside the native SDK
Mobile Widget SDKThe provider supplies the embed token. The SDK authenticates the configured widget with its exact clientOrigin.
Deliver the access token
SDK-owned WebViewThe WebView receives only the exchanged access token and expiry. The embed token does not cross the bridge.
Mint the token on your backend
Your backend calls the Returning.AI endpoint after it has authenticated the app user. Replace the example identifier with the configured mapping for that widget.
POST https://api-v2.returning.ai/v2/api/widget-access-keys/token
Content-Type: application/json
{
"accessId": "SERVER_ACCESS_ID",
"accessKey": "SERVER_ACCESS_KEY",
"userIdentifiers": {
"data-customer-id": "VALUE_FROM_TRUSTED_HOST_SESSION"
}
}
// Returning.AI response:
// { "data": { "embedToken": "...", "expiresIn": 900 } }Flatten the successful upstream response for the app. Keep the response non-cacheable and return safe errors without upstream bodies or credentials.
200 OK
Cache-Control: no-store
Content-Type: application/json
{
"embedToken": "SHORT_LIVED_TOKEN",
"expiresIn": 900
}Never bundle dashboard credentials
Do not place accessId, accessKey, or a signing secret in mobile source, environment files, application packages, WebView HTML, or logs.
Connect the token provider
Each platform exposes the same asynchronous provider contract using its native language:
- Flutter
Future<String> Function()- Android
suspend fun invoke(): String- iOS
@Sendable () async throws → String- React Native
() → Promise<string>
Allow the exact client origin
clientOrigin is an HTTPS origin without a path, query, or fragment. It is configured per widget. Another widget working with the same origin does not prove this widget is allowlisted.
An allowlist miss normally returns 403 Domain not authorized during native authentication and may appear as a WebView HTTP 502.
Return a fresh token after expiry
When the widget session expires, the SDK clears its native access-token cache. The next authentication request calls the provider again. Fetch a new embed token from your backend instead of returning a cached value.
Continue with a platform guide: Flutter, Android, iOS, or React Native.