Docs

Sign-in for mobile apps

Provider sign-in and email links that open your app (authorization code + PKCE), universal links hosted by Sovaria, device sessions and refresh-token rotation.

Updated Oct 17, 2026Open in console

Redirect URIs

A sign-in or email link may only open a redirect URI listed on one of your registered apps — exact matches, no wildcards. Two kinds work:

  • Your app's own scheme: com.example.app://auth-callback.
  • A universal link / App Link on your project host: https://<ref>.sovaria.in/auth/v1/app-callback. Sovaria serves /.well-known/apple-app-site-association and /.well-known/assetlinks.json there from your registered apps, so you only add the Associated Domains entitlement (applinks:<ref>.sovaria.in) or the Android intent filter.

Sign in with Google, Apple, GitHub…

final start = await sovaria.auth.getOAuthSignInUrl('google', redirectTo: 'com.example.app://auth-callback');
final result = await FlutterWebAuth2.authenticate(url: start.url.toString(), callbackUrlScheme: 'com.example.app');
await sovaria.auth.handleDeepLink(Uri.parse(result));   // exchanges ?code=…&type=sso with the verifier
await sovaria.auth.sendMagicLink(email, redirectTo: 'com.example.app://auth-callback');
AppLinks().uriLinkStream.listen((uri) => sovaria.auth.handleDeepLink(uri));     // signs in
// or the 6-digit code from the same email:
await sovaria.auth.verifyEmailCode(email: email, code: code);

await sovaria.auth.resetPasswordForEmail(email, redirectTo: 'com.example.app://reset');
final link = await sovaria.auth.handleDeepLink(uri);                              // type == 'recovery'
await sovaria.auth.confirmPasswordReset(token: link!.token!, newPassword: newPassword);

A link sent with a challenge only works with the verifier the requesting install holds — opening it on another device (or in another app) fails with PKCE_VERIFIER_MISMATCH. SMS codes work as before: sendSmsOtp / verifySmsOtp.

Devices and sessions

Pass a stable device (id kept in secure storage, platform, name, app version). Every session is tied to it and keeps it across token refreshes.

final devices = await sovaria.auth.listDevices();   // current: true marks this phone
await sovaria.auth.signOutDevice(deviceId);           // ends its sessions now, removes its push tokens
  • Refresh tokens rotate on every refresh. Two refreshes racing with the same token within the reuse window (10 s by default, Authentication › Sessions) get the same new pair.
  • A rotated refresh token presented again after that window means it was copied: every session of the user ends and they sign in again.
  • Device headers: X-Sovaria-Device-ID, X-Sovaria-Device-Name, X-Sovaria-Device-Platform, X-Sovaria-App-Version. They label sessions; they never grant anything.
Something unclear or missing on this page?Tell us