Sign members out and handle expired sessions

End a member's Genuin session when they sign out of your app, keep the SDK in step with your own sign-in state, and recover when a Genuin session expires.

A member who signs in to a Genuin SDK holds a Genuin session on that device, whether they used an SSO token, Auto Login, or Genuin's own sign-in sheet. The SDK refreshes that session on its own. It never watches your app's session, so your app decides when the member signs out, when a different member signs in, and how access comes back after a session expires.

How long a session lasts

A session is a pair of tokens that Genuin returns in the gn-access-token and gn-refresh-token response headers.

TokenProductionQAWhen it runs out
Access token14 days3 hoursThe next request returns 401, and the SDK refreshes the session.
Refresh token100 days24 hoursThe refresh fails, and the SDK signs the member out on the device.

Each successful refresh at POST /api/v4/auth/session/refresh returns a new access token and a new refresh token, and the SDK stores both. For example, a member who signs in on 1 March gets a new pair on their first request after 15 March. If that member doesn't open your app again until 15 June, the refresh fails, because the refresh token issued on 1 March expired on 9 June.

Before you begin

  • Sign members in with an SSO token or Auto Login, as described in Choose how members sign in to the Genuin SDK and How Auto Login works.
  • Register a sign-in callback. After a session expires, the SDK calls it the next time the member taps an action that needs an account. Without one, the Genuin sign-in sheet opens instead.
PlatformSign-in callback
AndroidGenuinSDK.registerInterface(GenuinInterface), which calls onLogin(activity)
iOSGenuinSDK.shared.delegate, which calls presentLoginViewController(baseViewController:)
React NativeregisterCallback(), then the NavigateToScreen event with the value Login
FlutterNone in genuin_sdk 1.0.1; the Genuin sign-in sheet opens
Webwindow.genuinAuth, or auth_info with signInUrl and signUpUrl in init

Step 1: Sign the member out with your app

Call the SDK's sign-out from the same code path that signs the member out of your app.

PlatformCallResultEnds the session on Genuin's servers
AndroidGenuinSDK.ssoLogout(context) { success -> }true once Genuin confirms. false when no member is signed in or the request fails.Yes, POST /api/v4/auth/signout
iOSGenuinSDK.shared.ssoLogout { success in }, on the main actorSame as AndroidYes, POST /api/v4/auth/signout
React NativessoLogout()None. The function returns void.Yes, through the native SDK 2.1.5
FlutterGenuinSdk().ssoLogout()A Future<void> that completes before the request doesCalls ssoLogout in native SDK 1.1.9.x
Webwindow.genuin.logout()A PromiseNo. It clears the member stored on the page.

On Android and iOS, a successful sign-out clears the stored tokens, the SDK's cached data, and its pending requests. On iOS it also dismisses SDK screens presented over your app. When the request fails, for example with no network, nothing is cleared, and the member stays signed in on the device.

SignOut.kt
kotlin
import android.content.Context
import com.begenuin.begenuin.GenuinSDK

fun signOutOfGenuin(context: Context) {
    GenuinSDK.ssoLogout(context) { success ->
        // false: nobody was signed in, or the request failed and the member is still
        // signed in on this device. The launch check in Step 2 retries it.
    }
}

Genuin views remember the ssoToken you gave them. On Android and iOS, a view that loads again with its old token signs that member back in. After sign-out, recreate your embeds, placements, and feeds without ssoToken. In React Native, render them without the ssoToken prop.

On the web, logout() removes the stored member and the tokens the embeds use, without a request to Genuin. When no member is stored, it logs GenuinSDK: No user is currently logged in. Logout skipped. and returns.

Sign out on the web
js
async function onSiteSignOut() {
  await window.genuin.logout();
  // Load the next page without `token`, so the embeds stay signed out.
}

Step 2: Keep the SDK in step with your session

The SDK can't see your app's session, so pass the change through each time it happens.

When this happens in your appDo this in the SDK
A member signs inCall ssoLogin with their token. Calling it again with the same token completes without a sign-in request.
A different member signs in on the same deviceCall ssoLogout, then ssoLogin with the new token. A new token on its own clears the previous member from the device but leaves their Genuin session open on the server.
Your backend issues a new token for the same memberKeep passing the token you used when the session started. Each new value clears the SDK's cached data and starts a new Genuin session.
The member signs outCall ssoLogout, and recreate Genuin views without ssoToken.
The member deletes their accountDelete their Genuin account with Delete a member account, then call ssoLogout.
Your app is reinstalledNothing. The Android SDK opts out of Auto Backup, and iOS removes the SDK's stored tokens with the app, so the member starts signed out.

SDK 2.1.6 moves the iOS tokens to the Keychain and clears them on a fresh install, so the reinstall result stays the same.

The most reliable pattern is a check at launch. Sign in the member your app has, or sign out the one it doesn't have. Both calls cost no request when the SDK already matches:

YourApplication.kt
kotlin
import android.app.Application
import com.begenuin.begenuin.GenuinSDK

class YourApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        GenuinSDK.initSDK(this, "<<YOUR_API_KEY>>")
        val token = currentGenuinToken()
        if (token != null) GenuinSDK.ssoLogin(this, token)  // no request when the token is unchanged
        else GenuinSDK.ssoLogout(this)                      // false at once when nobody is signed in
    }

    // Return the token your backend issued for the signed-in user, or null.
    private fun currentGenuinToken(): String? = null
}

ssoLogin compares the token with the one it stored at the last successful sign-in. After a sign-out or an expired session that stored token is gone, so the same call signs the member in again.

Caution: In genuin-react-native 3.0.3 on Android, ssoLogin(token) without a second argument throws, because the module casts the missing parameters to a map. Pass {} when you have no profile fields: ssoLogin('{{SSO_TOKEN}}', {}).

On the web, the page load is the check. Pass token when the visitor is signed in to your site. When an embed initializes without token, the SDK removes the stored member, so a visitor who signed out of your site is signed out of Genuin on the next page:

Follow your site's session on the web
js
const token = window.siteSession?.genuinToken; // undefined when nobody is signed in
window.genuin.init({
  embed_id: "{{EMBED_ID}}",
  api_key: "<<YOUR_API_KEY>>",
  ...(token ? { token } : {}),
});

Pass the same token to every container on the page. To sign a visitor in without a reload, call window.genuin.update({ container_id: "gen-sdk", token: "{{AUTO_LOGIN_TOKEN}}", user_params: {} }).

Step 3: Recover from an expired session

The SDK handles a 401 response in this order:

  1. A request returns 401, because the access token expired, or the session was revoked or the member was removed.
  2. The SDK sends the refresh token to POST /api/v4/auth/session/refresh and retries the waiting requests with the new tokens.
  3. If the refresh fails for any reason, including a request that times out, the SDK signs the member out on the device. On iOS, a request that returns code 5033 skips the refresh and signs out at once.
  4. On Android and iOS, the SDK then runs Auto Login again with the ssoToken of the most recently loaded embed, placement, or feed, if it had one. The web retries with the token from init or update.
  5. Without a token to retry with, the member carries on as a guest. Videos keep playing, and the next action that needs an account calls your sign-in callback.

The Android SDK doesn't attempt the refresh while the device reports no network; it tries again on the next 401. The silent retry in item 4 doesn't use a token you passed only to ssoLogin.

Refresh responseCauseFix
401, code "401", data Unauthorized refresh tokenThe refresh token expired, or the session was signed outSign the member in again with a current token.
401, code "5098"The member's account was deletedDon't sign this member in again.
401, code "5163"The member no longer belongs to your brandContact the Genuin team with the member's id.
401, code "1003"The session belongs to another brand than the one the app now uses, for example after switching API keysSign the member in again under the current key.
No responseThe device lost its connection during the refreshSign the member in again once the device is online.

Your app gets no callback, event, or error when this happens. The launch check from Step 2 restores the session the next time your app starts, because the SDK cleared its stored token. On iOS, run it when the app returns to the foreground too:

SceneDelegate.swift
swift
import UIKit
import GenuinCore

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func sceneWillEnterForeground(_ scene: UIScene) {
        guard let token = currentGenuinToken() else { return }
        GenuinSDK.shared.ssoLogin(ssoToken: token) { success in
            // false: your verification endpoint rejected the token; renew your own session first
        }
    }

    // Return the token your backend issued for the signed-in user, or nil.
    private func currentGenuinToken() -> String? { nil }
}

Caution: The silent retry and the launch check reuse a token you issued earlier. If your backend has expired it, Auto Login fails with code 5031 and the member stays a guest. Issue tokens your verification endpoint accepts for as long as your own session lasts, or pass a fresh one at launch.

Step 4: Test sign-out and expiry

  1. Sign a test member in, call the sign-out for your platform, then tap a reaction. Your sign-in callback runs, or the Genuin sheet opens.
  2. On Android or iOS, turn on airplane mode and sign out again. The call reports false, and the member stays signed in until your launch check retries it.
  3. Test expiry on a QA build, where refresh tokens last 24 hours. Sign in, leave the app closed for a day, then open it and tap a reaction.
  4. For a faster test, delete a QA test member with Delete a member account while they're signed in. Their next request fails, the refresh returns 5098, and the SDK signs them out.

Use a test account for item 4, because a deleted account can't be restored.

Limitations

  • No session events: None of the SDKs report a sign-out, a refresh, or a failed refresh to your app.
  • Mobile sign-out needs the network: ssoLogout clears the device only after Genuin confirms. Android has no local-only sign-out.
  • Web sign-out is local: window.genuin.logout() doesn't end the session on Genuin's servers.
  • One member per device: A new token replaces the previous member on the device, and a new token on the web replaces the stored visitor.
  • Silent retry uses view tokens only: After a failed refresh, the SDK retries with the most recent view's ssoToken, never with a token passed only to ssoLogin.
  • No results in the cross-platform wrappers: React Native's ssoLogin and ssoLogout return nothing, and Flutter's complete before the request finishes.
  • No single logout: Signing out of Genuin doesn't sign the member out of your app or your identity provider, and the reverse is your app's job.

See also

TRUST AND COMPLIANCE

© 2026 Genuin Inc.

Genuin Footer