Mobile Session Management

Descope extends support to mobile application development by offering SDKs tailored for Swift, Kotlin, and more. These SDKs incorporate robust token storage methodologies, utilizing the secure environment of each device locally.

This guide shows how to effectively implement session validation and manage the tokens on your mobile app, with our Mobile SDKs.

The session management article gives an overview of the session validation in Descope.

If you're looking to set up backend validation, check out our Backend Validation page.

How Token Storage Works with Mobile SDKs

With Descope's Mobile SDKs at your disposal, you can bypass the need to manually save tokens on the device. The SDKs, designed to cater to the unique needs of each platform, handle token storage and retrieval in an unobtrusive and secure manner in the background.

Swift

Descope's Swift SDK uses iOS's Keychain Services to store, retrieve and manage the session and refresh tokens. Keychain Services provide a secure, encrypted storage mechanism for sensitive user information, including Descope tokens.

Kotlin

Descope's Kotlin SDK employs Android's native EncryptedSharedPreferences to securely store session and refresh tokens locally. The EncryptedSharedPreferences provide a robust, encrypted storage environment to protect sensitive user information, such as Descope tokens.

Flutter

Descope's Flutter SDK stores session and refresh tokens using Keychain Services on iOS and EncryptedSharedPreferences on Android.

React Native

Descope's React Native SDK stores session and refresh tokens using Keychain Services on iOS and EncryptedSharedPreferences on Android. When using React Native, you can access session information outside of the component render-lifecycle using the getCurrentSessionToken(), getCurrentRefreshToken(), and getCurrentUser() helper functions.

Using our SDKs

Install SDK

// 1. Within XCode, go to File > Add Packages
// 2. Search for the URL of the git repo: https://github.com/descope/swift-sdk
// 3. Configure your desired dependency rule
// 4. Click Add Package

Import and initialize SDK

import DescopeKit
import AuthenticationServices
 
do {
    Descope.setup(projectId: "__ProjectID__")
    print("Successfully initialized Descope")
} catch {
    print("Failed to initialize Descope")
    print(error)
}

Sending session token to application server

If you are using Mobile SDK or using Descope Flows, then your application must send the session token to your application server in order to validate the session token using the Descope Backend SDK.

let sessionToken = Descope.sessionManager.session
 
// example fetch call with authentication header
fetch('your_application_server_url', {
  headers: {
    Accept: 'application/json',
    Authorization: 'Bearer '+ sessionToken,
  }
})

Logout using Mobile SDK

If you are integrating using Descope Mobile SDKs, then you must use the Mobile SDK to logout. If you are using Descope Flows with React SDK, refer to the Quick Start for details. If you are using Descope Mobile SDKs without flows, then refer to the sample code below for logout.

guard let refreshJwt = Descope.sessionManager.session?.refreshJwt else { return }
try await Descope.auth.logout(refreshJwt: refreshJwt)
Descope.sessionManager.clearSession()

Checking token expiration

One important step in validating a session token is to ensure that the token has not expired. You can use the refresh token's isExpired property for this purpose.

if let session = Descope.sessionManager.session, session.refreshToken.isExpired {
  print("Session token has expired.")
} else {
  print("Session token is valid.")
}

Handling Authorization

Get Roles from Session Token

Depending on your application's requirements, you might need to know the roles of a user from their session token. You can use the Mobile SDKs roles() function for this purpose.

let sessionToken = Descope.sessionManager.session
 
let roles = sessionToken.roles()
 
print("User Roles: \(roles)")

Get Permissions from Session Token

Depending on your application's requirements, you might need to know the permissions of a user from their session token. You can use the Mobile SDKs permissions() function for this purpose.

let sessionToken = Descope.sessionManager.session
 
let permissions = sessionToken.permissions()
 
print("User Permissions: \(permissions)")

Starting a managed session

After a user finishes a sign in flow successfully, you should use the Descope session manager to manage the user's session. You can also create a DescopeSession object from the AuthenticationResponse value returned by all the authentication APIs.

let authResponse = try await Descope.otp.verify(with: .email, loginId: "andy@example.com", code: "123456")
let session = DescopeSession(from: authResponse)
Descope.sessionManager.manageSession(session)

Authenticate outgoing requests

The session can then be used to authenticate outgoing requests to your backend with a bearer token authorization header.

var request = URLRequest(url: url)
request.setAuthorizationHTTPHeaderField(from: Descope.sessionManager)
let (data, response) = try await URLSession.shared.data(for: request)

Using the session JWT directly

If your backend uses a different authorization mechanism you can of course use the session JWT directly instead of the extension function:

try await Descope.sessionManager.refreshSessionIfNeeded()
guard let sessionJwt = Descope.sessionManager.session?.sessionJwt else { throw ServerError.unauthorized }
request.setValue(sessionJwt, forHTTPHeaderField: "X-Auth-Token")

Descope User

The DescopeUser struct represents an existing user in Descope.

After a user is signed in with any authentication method the DescopeSession object keeps a DescopeUser value in its user property so the user's details are always available.

In the example below we finalize an OTP authentication for the user by verifying the code. The authentication response has a user property which can be used directly or later on when it's kept in the DescopeSession.

let authResponse = try await Descope.otp.verify(with: .email, loginId: "andy@example.com", code: "123456")
print("Finished OTP login for user: \(authResponse.user)")
Descope.sessionManager.session = DescopeSession(from: authResponse)
print("Created session for user \(descopeSession.user.userId)")

The details for a signed in user can be updated manually by calling auth.me with the refreshJwt from the active DescopeSession. If the operation is successful the call returns a new DescopeUser value.

guard let session = Descope.sessionManager.session else { return }
let descopeUser = try await Descope.auth.me(refreshJwt: session.refreshJwt)
session.update(with: descopeUser)

The DescopeUser struct contains the following attributes:

  • userId: The user's unique Descope generated userId.
  • loginIds: An array of loginIds associated to the user.
  • createdAt: The time at which the user was created in Descope.
  • name: Name associated to the user.
  • picture: The user's profile picture.
  • email: Email address associated to the user.
  • isVerifiedEmail: Boolean whether the email address for the user has been verified.
  • phone: Phone number associated to the user.
  • isVerifiedPhone: Boolean whether the phone number for the user has been verified.
Was this helpful?

On this page