Authentication
An authenticated chat knows which of your users it talks to. Pass an auth provider to start, and the SDK asks it for a token whenever the chat needs one: after the chat connects, when you call authenticate(), and within 30 seconds of the previous token's expiry
The provider gets the chat id and returns a JWT, or an opaque bearer token, for the user signed in to your app. The chat id comes from the chat page and the SDK cannot verify it, so issue the token only for the user signed in to your app, and never treat the chat id as proof of who the user is or what they may see. Tokens come from your backend: never put a signing key or another long-lived secret in the app
Token provider
KindlyWebViewSDK.start(botKey: "YOUR_BOT_KEY", market: "general", authTokenProvider: { chatId in
try await MyBackend.kindlyToken(chatId: chatId)
})Providers are @Sendable closures, so read shared state through an actor or another thread-safe type
Credentials provider
When your identity provider issues more than one token, return credentials instead of a token. The Kindly platform verifies a chat's credentials the way the bot is configured: a JWT your backend signs, a JWT from your identity provider with or without its access token, or an opaque token it introspects
KindlyWebViewSDK.start(botKey: "YOUR_BOT_KEY", market: "general", authCredentialsProvider: { chatId in
let tokens = try await MyIdentityProvider.tokens()
return KindlyAuthCredentials(
idToken: tokens.idToken,
accessToken: tokens.accessToken,
issuer: "https://idp.example.com",
expiresAt: tokens.expiry
)
})start takes one provider, a token provider or a credentials provider. expiresAt is a Date, and KindlyAuthCredentials(idToken:accessToken:issuer:expiresAtUnixSeconds:) takes Unix seconds instead
Credentials need at least one of idToken and accessToken. The SDK sends the idToken as the bearer token when there is one and the accessToken otherwise, so a provider that issues only an access token works, and next to an idToken a different accessToken goes along as its companion. Credentials with neither leave the chat anonymous, and the Flutter and React Native packages log one warning
Set issuer for opaque tokens and for bots with more than one identity provider. Set expiresAt when the expiry cannot be read from the token, as with an opaque token, because credentials without a known expiry are never refreshed ahead of time. An expiresAt above 1e12, a millisecond value, is converted to seconds
Timeouts and failures
The SDK waits 15 seconds for a provider. If it throws, returns an empty token or does not answer in time, the chat continues anonymously and a late answer is discarded. The Flutter and React Native packages stop waiting for your callback after 12 seconds (KindlyWebViewSDK.authCallbackTimeout in Flutter, KindlyWebViewSDK.authCallbackTimeoutMs in React Native), so their answer always reaches the native SDK in time, and a callback that returns null leaves the chat anonymous too
On Android, React Native pauses JavaScript timers while the chat screen is in front, so neither the package's own 12-second and 4-second limits nor a setTimeout in your callback fires until the chat is hidden. The native SDK's bounds apply instead: after 15 seconds without a token the chat continues anonymously, and after 5 seconds without a Link Interception the link opens outside the app. fetch and promises keep working while the chat is shown
The SDK calls the provider at most six times a minute and runs one call at a time per chat. A token must be printable ASCII without spaces, at most 16 KiB, and an issuer printable ASCII of at most 2,048 characters. Credentials that break these rules leave the chat anonymous
Sign in and sign out
try await KindlyWebViewSDK.authenticate() // after the user signs in
try await KindlyWebViewSDK.deauthenticate() // after the user signs outauthenticate() throws KindlyWebViewError.noAuthProvider when start got no provider
authenticate() makes the loaded chat authenticate again with your provider and keeps the conversation, and without a loaded page the next page authenticates as it loads. Use it when a user signs in while the chat runs anonymously. After deauthenticate() the chat continues anonymously and the SDK refuses token requests until the next authenticate()
Called while the chat page is still loading, both take effect once it has loaded, in call order. If that page fails to load, they fail with the chat-not-ready error, see Errors
deauthenticate() keeps the conversation. When a user signs out of your app, also call End Chat, which deletes the stored conversation