Session

Read who the SDK is acting for, follow the session as it changes, and sign out.

Preview

This page describes a pre-release version of the SDK. Names, versions and APIs on this page can change before the release.

A session is the identity the SDK acts for on this device, together with the services that run for it. Every request the SDK sends to Folio belongs to the current session, and the data the SDK keeps on the device, such as the vault, belongs to the identity of that session.

SessionStore is the store that reports the session to your app. It tells you which identity is current, whether the services for it are running, and it signs the person out. To sign in, use AuthStore.

Guests and accounts

The SDK always acts for an identity. There are two kinds:

  • Guest (Transient): an identity that Folio creates for this device without asking the person anything. The SDK creates it the first time the runtime starts on a device, and again after a sign-out. A guest has a user id and no email address.
  • Account (Authenticated): an identity the person signed in to with the authentication ceremony. It has a user id and an email address.

A sign-in can also end on a guest identity: when the account that Folio signs the person in to is itself a guest account, the identity stays Transient.

When a guest signs in to an account, the SDK carries the vault records of the guest over to the account. The data of the guest stays on the device until that transfer has finished; if the app stops before then, the SDK resumes the transfer the next time the account's services start.

FolioSdk.create restores the session that was saved on the device, or creates a guest session when there is none, before it returns. When it cannot, create fails with a SessionStartError. A runtime that exists therefore always has a session. See Runtime.

Mount the store

SessionStore takes no init value. Mount it on the runtime, read its state and close it when your app no longer needs it.

Swift
let session = try SessionStore.mount(runtime: sdk)

let cancellable = session.$state
    .map(\.identity)
    .sink { identity in
        switch identity {
        case .unresolved:
            showSignedOut()
        case let .transient(userId):
            showGuest(userId)
        case let .authenticated(userId, email):
            showAccount(userId, email)
        }
    }

On iOS SessionStore is an ObservableObject that publishes its state as @Published state, updated on the main actor; on Android state is a StateFlow<SessionUiModel>; on the web read state and register a listener with subscribe, which returns the function that removes it. mount takes the runtime, a FolioSdk. Close the store with close() when you no longer need it. To read the states one by one instead, see Subscriptions.

React

On the web, useSessionStore from @folio/sdk/stores mounts SessionStore for the component that calls it. It needs a FolioSDKProvider from @folio/sdk/provider above that component.

import { FolioSDKProvider } from '@folio/sdk/provider';
import { useSessionStore } from '@folio/sdk/stores';
import { type FolioSdk, SessionAction } from '@folio/sdk';

function App({ runtime }: { runtime: FolioSdk }) {
    return (
        <FolioSDKProvider runtime={runtime}>
            <Profile />
        </FolioSDKProvider>
    );
}

function Profile() {
    const { store, state } = useSessionStore();
    if (store === undefined || state === undefined) return null;
    if (state.identity.type !== 'AUTHENTICATED') return <p>Guest</p>;
    return (
        <button disabled={state.signingOut} onClick={() => store.dispatch(SessionAction.signOut)}>
            Sign out {state.identity.value.email}
        </button>
    );
}

useSessionStore returns { store, state }. Both are undefined until the store is mounted after the first render. The hook re-renders the component on every state change, and closes the store when the component unmounts or the runtime changes.

Mounting the store does not start or change a session. The store follows the session the runtime already has and reports every change to it, whichever store or event caused the change: a sign-in through AuthStore, a sign-out, or a session that Folio ended.

State

The state of the store is SessionUiModel.

FieldTypeMeaning
identityRuntimeIdentityThe identity the session acts for.
statusSessionStatusWhether the services for that identity are running.
noticeSessionNoticeReason?Why the account session ended without a sign-out from your app. Empty otherwise.
deviceIdString?The id the Folio backend gave this installation. Empty until the first session start.
signingOutBool / Boolean / booleantrue from the moment you dispatch signOut until the sign-out has finished or failed.
errorSessionStartError?Why the last sign-out failed. Cleared when you dispatch signOut again.

Until the store has read the session for the first time, its state holds the defaults: identity Unresolved, status Device, no notice and no device id.

RuntimeIdentity

CaseFieldsMeaning
UnresolvednoneNo identity. The SDK has no session for anyone, for example during a sign-out, or after one when no new guest session could be created.
TransientuserIdA guest.
AuthenticateduserId, emailA signed-in account. email is empty when no email address is known for the account: after a recovery started with a phone number, or when Folio returns none for a sign-in.
PlatformSpelling
Swift.unresolved, .transient(userId:), .authenticated(userId:email:)
KotlinRuntimeIdentity.Unresolved, RuntimeIdentity.Transient(userId), RuntimeIdentity.Authenticated(userId, email)
TypeScript{ type: 'UNRESOLVED' }, { type: 'TRANSIENT', value: { userId } }, { type: 'AUTHENTICATED', value: { userId, email } }

SessionStatus

The status tells you whether the services that belong to the identity, such as the vault, are running.

ValueSwiftKotlinTypeScriptMeaning
Device.deviceSessionStatus.DEVICE'DEVICE'No identity is active. Nothing that belongs to a user is running.
Activating.activatingSessionStatus.ACTIVATING'ACTIVATING'The SDK is starting the services for a signed-in account.
Active.activeSessionStatus.ACTIVE'ACTIVE'The services for the current identity, guest or account, are running.
Deactivating.deactivatingSessionStatus.DEACTIVATING'DEACTIVATING'The SDK is stopping the services of the previous identity.

On iOS and Android SessionStatus is an enum. On the web it is a string, and the constant object SessionStatus holds the same strings, for example SessionStatus.ACTIVE is 'ACTIVE'.

The status moves through these values when the identity changes:

  • To an account: Activating, then Active once the account's services have started.
  • To a guest: straight to Active.
  • To no identity: Deactivating, then Device.

If the services for the new identity cannot start, the SDK goes back to the previous identity with status Device: the store reports that identity again, with its services stopped.

SessionNoticeReason

notice tells your app that the account session has ended although your app did not sign out, so that it can tell the person. It has one case:

CaseSwiftKotlinTypeScriptMeaning
SessionEnded.sessionEndedSessionNoticeReason.SessionEnded{ type: 'SESSION_ENDED' }Folio ended the account session. See Expired sessions.

On the web the constant SessionNoticeReason.sessionEnded holds the same value. notice is cleared when the identity becomes a signed-in account again and when you dispatch DismissNotice.

Actions

SessionAction has two actions.

ActionSwiftKotlinTypeScriptWhat it does
SignOut.signOutSessionAction.SignOutSessionAction.signOutSigns out. See Sign out.
DismissNotice.dismissNoticeSessionAction.DismissNoticeSessionAction.dismissNoticeClears notice. Does nothing when no notice is shown.
Swift
try session.dispatch(action: .signOut)

Sign out

SignOut ends the current session, whether it belongs to an account or to a guest, and leaves the device with a new guest session. While it runs, signingOut is true. A second SignOut while one is running does nothing.

The SDK signs out in this order:

  1. It stops the services of the current identity, such as the vault.
  2. It asks Folio to end the session. When Folio cannot be reached, the SDK goes on with the sign-out on the device.
  3. It deletes the session tokens from the device.
  4. It deletes the saved session of the previous identity from the device.
  5. It forgets the identity: identity becomes Unresolved and status goes through Deactivating to Device.
  6. It creates a new guest session: identity becomes Transient with a new user id and status becomes Active.

When the sign-out has finished, signingOut is false and error is empty. When a step fails, signingOut is false and error holds the reason. For example, when the device is offline, step 6 fails with a Network error: the person is signed out, identity stays Unresolved, and there is no guest session.

The sign-out ends the session. It does not delete the account.

Expired sessions

The SDK renews the session tokens by itself while the app runs. When Folio has ended the session and it can no longer be renewed, the runtime itself ends it; no store has to be mounted for that.

  • A guest gets a new session and keeps its vault.
  • An account ends as if your app had signed out: the device is left with a new guest session, and notice becomes SessionEnded, unless the account was deleted. To continue with the account, sign the person in again.

A mounted AuthStore returns to Idle and drops the sign-in that was in progress.

Errors

SessionStartError

SessionStartError is the error of FolioSdk.create and the type of SessionUiModel.error.

CaseFieldsMeaning
Backendstatus, code, messageFolio rejected the request. status is the HTTP status, code the Folio error code.
NetworkmessageFolio could not be reached.
ScopemessageThe services of the new identity could not be started, or the runtime was closed while the session changed.
CoreerrorThe SDK failed on the device, for example because its storage could not be read or written. error is a CoreError.
PlatformSpelling
Swift.backend(status:code:message:), .network(message:), .scope(message:), .core(error:)
KotlinSessionStartError.Backend(status, code, message), SessionStartError.Network(message), SessionStartError.Scope(message), SessionStartError.Core(error)
TypeScript{ type: 'BACKEND', value: { status, code, message } }, { type: 'NETWORK', value: { message } }, { type: 'SCOPE', value: { message } }, { type: 'CORE', value: { error } }

status is a UInt16 on iOS, an Int on Android and a number on the web. code and message are strings.

dispatch itself fails with a CoreError when the store cannot take the action, for example after the runtime was shut down. For what a closed store throws, see Store errors.

See also

  • Authentication: sign a person in, recover an account, verify a sensitive operation.
  • Runtime: create the runtime that holds the session.
  • Storage: what the SDK keeps on the device.

On this page