---
title: "Authentication State"
slug: "authentication-state"
updated: 2026-04-28T03:48:11Z
published: 2026-04-28T03:48:11Z
canonical: "ignite.ticketmaster.com/authentication-state"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://ignite.ticketmaster.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication State

## Authentication Analytics

The Authentication SDK provides callbacks so you can track authentication state changes — configuration, login, token refresh, and logout. You can use these to update your UI, forward events to your analytics platform, or trigger downstream logic.

Both iOS and Android expose a state machine with nearly identical states. The key difference is the delivery mechanism: iOS uses a delegate protocol, while Android uses `LiveData`.

---

## Overview

| Aspect | iOS | Android |
| --- | --- | --- |
| **State API** | `TMAuthenticationDelegate` protocol | `TMAuthentication.getLoginStateLiveData()` |
| **Delivery** | Delegate callback with `ServiceState` enum | `LiveData&lt;ServiceLoginState&gt;` observer |
| **State enum** | `TMAuthentication.ServiceState` (14 states) | `ServiceLoginState` (15 states — includes `LOGIN_EXCHANGING`) |
| **Backend context** | `BackendService?` parameter on each callback | Not provided per-state; query with `getToken(AuthSource)` |
| **Error context** | `Error?` parameter on each callback | Not provided per-state; use `ActivityResult` for login outcome |
| **Federated login details** | States only (e.g., `loginLinkAccountPresented`) | States + `UserAnalyticsDelegate` events for button-level tracking |

---

## Service States

Both platforms share the same state flow. States are grouped into four phases.

### Configuration States

These fire during SDK initialization (`TMAuthentication.Builder.build()`) before any user interaction. During configuration, multiple backend services (Host, Archtics, MicroFlex) may be configured, causing multiple `serviceConfigured` callbacks — one per backend. `serviceConfigurationCompleted` fires only once when all backends have finished configuring.

| iOS (`ServiceState`) | Android (`ServiceLoginState`) | Description |
| --- | --- | --- |
| `serviceConfigurationStarted` | `SERVICE_CONFIGURATION_STARTED` | Configuration has started. |
| `serviceConfigured` | `SERVICE_CONFIGURED` | A specific backend has been configured. May fire multiple times. |
| `serviceConfigurationCompleted` | `SERVICE_CONFIGURATION_COMPLETED` | All backends have finished configuring. The SDK is ready for login. |

**Querying configured services:**

You can check which services were configured at any time:

**iOS**

```swift
// Check which backends are configured via TMAuthentication.BackendService
// The backend parameter in onStateChanged tells you which service was configured
```

**Android**

```kotlin
// Check which backends are configured via the configuration object
val config = tmAuthentication.configuration
val hasHost = config.modernAccounts?.host != null
val hasArchtics = config.modernAccounts?.archtics != null
val hasMfx = config.modernAccounts?.mfx != null
```

### Login States

These fire during the login flow. During login, multiple services may be logged in (for example, Archtics and Host). The `loggedIn` state may fire multiple times — once per backend service. `loginCompleted` fires only once when the entire login process (including link-account flows) has finished.

| iOS (`ServiceState`) | Android (`ServiceLoginState`) | Description |
| --- | --- | --- |
| `loginStarted` | `LOGIN_STARTED` | Login has started. |
| — | `LOGIN_EXCHANGING` | *(Android only)* Token exchange is in progress. |
| `loginPresented` | `LOGIN_PRESENTED` | A login page has been presented for a backend. |
| `loggedIn` | `LOGGED_IN` | The user has logged in to a specific backend. May fire multiple times. |
| `loginAborted` | `LOGIN_ABORTED` | The user manually cancelled the login. |
| `loginFailed` | `LOGIN_FAILED` | Login failed for a specific backend. |
| `loginLinkAccountPresented` | `LOGIN_LINK_ACCOUNT_PRESENTED` | A link-account prompt has been presented. |
| `loginCompleted` | `LOGIN_COMPLETED` | The entire login process has completed. |

**Querying logged-in services:**

**iOS**

```swift
// The backend parameter in onStateChanged tells you which service was logged in
```

**Android**

```kotlin
// Check which backends have valid tokens
AuthSource.entries.forEach { source ->
    val token = tmAuthentication.getToken(source)
    if (token != null) {
        Log.d("Auth", "$source is logged in")
    }
}
```

### Token Refresh States

| iOS (`ServiceState`) | Android (`ServiceLoginState`) | Description |
| --- | --- | --- |
| `tokenRefreshed` | `TOKEN_REFRESHED` | The user's auth token has been refreshed. May fire multiple times during the app's lifetime. |

### Logout States

When you call logout, by default the system logs out of **all** currently configured services. This means the `loggedOut` state may fire multiple times — once per backend. `logoutCompleted` fires only once at the end.

| iOS (`ServiceState`) | Android (`ServiceLoginState`) | Description |
| --- | --- | --- |
| `logoutStarted` | `LOGOUT_STARTED` | Logout has started. |
| `loggedOut` | `LOGGED_OUT` | The user has logged out of a specific backend. May fire multiple times. |
| `logoutCompleted` | `LOGOUT_COMPLETED` | The entire logout process has completed. |

---

## Setup

### iOS

Set yourself as the delegate on the shared `TMAuthentication` instance:

```swift
TMAuthentication.shared.delegate = self
```

Then conform to `TMAuthenticationDelegate`:

```swift
extension MyViewController: TMAuthenticationDelegate {

    func onStateChanged(
        backend: TMAuthentication.BackendService?,
        state: TMAuthentication.ServiceState,
        error: (Error)?) {

        // Handle state change
    }
}
```

**Parameters:**

| Name | Type | Description |
| --- | --- | --- |
| `backend` | `TMAuthentication.BackendService?` | The backend service (Host, Archtics, etc.) the state relates to. `nil` for global state changes. |
| `state` | `TMAuthentication.ServiceState` | The current authentication state. |
| `error` | `Error?` | An error, if one occurred during the state transition. |

> [!WARNING]
> **Note:** Always include an `@unknown default` case to handle new states that may be added in future SDK versions.

### Android

Observe the login state `LiveData` from your `TMAuthentication` instance:

```kotlin
tmAuthentication.getLoginStateLiveData().observe(this) { state ->
    Log.d("Auth", "State changed: $state")
}
```

Android also provides login outcomes via `ActivityResult`:

```kotlin
private val loginLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    when (result.resultCode) {
        Activity.RESULT_OK -> handleLoginSuccess()
        Activity.RESULT_CANCELED -> handleLoginCancelled()
    }
}
```

> [!NOTE]
> **Note:** Use both mechanisms together — `getLoginStateLiveData()` gives you granular state transitions, while `ActivityResult` gives you the final login outcome.

---

## Federated Login Events (Android)

In addition to the `ServiceLoginState` state machine, the Android SDK emits button-level federated login analytics through `UserAnalyticsDelegate`. These provide more detail about user interactions during the link-account flow:

| Action | Description |
| --- | --- |
| `ACTION_FED_LOGIN_LINK_ACCOUNTS_SCREEN_SHOWED` | Link-accounts screen was presented |
| `ACTION_FED_LOGIN_LINK_ACCOUNTS_SCREEN_DISMISSED` | Link-accounts screen was dismissed |
| `ACTION_FED_LOGIN_SCREEN_DISMISSED_AFTER_SUCCESS_LOGIN_NO_LINK` | Login dismissed after success without linking |
| `ACTION_FED_LOGIN_LINK_ACCOUNTS_BUTTON_PRESSED` | User pressed "Link Accounts" |
| `ACTION_FED_LOGIN_NO_THANKS_BUTTON_PRESSED` | User pressed "No Thanks" |

> [!NOTE]
> **Note:** These `actionName` strings are prefixed with `com.ticketmaster.presencesdk.eventanalytic.action.`.

```kotlin
UserAnalyticsDelegate.handler.observe(this) { data ->
    data?.let {
        if (it.actionName.contains("FED_LOGIN")) {
            Log.d("AuthAnalytics", "Federated login event: ${it.actionName}")
        }
    }
}
```

---

## Session Expiration

### iOS

Session expiration is handled via `TMTicketsOrderDelegate`. See [Analytics - Actions](/v1/docs/analytics-4#user-actions) for details.

### Android

Observe session expiration (401 errors) via the `sessionExpiredDelegate` Flow:

```kotlin
lifecycleScope.launch {
    TicketsSDKSingleton.sessionExpiredDelegate.collect {
        Log.d("Auth", "Session expired")
        TicketsSDKSingleton.logout {
            launchLogin()
        }
    }
}
```

---

## Complete Examples

### iOS

```swift
TMAuthentication.shared.delegate = self

extension MyViewController: TMAuthenticationDelegate {

    func onStateChanged(
        backend: TMAuthentication.BackendService?,
        state: TMAuthentication.ServiceState,
        error: (Error)?) {

        if let backend = backend {
            if let error = error {
                print("Auth: .\(state.rawValue) backend: \(backend.description) error: \(error.localizedDescription)")
            } else {
                print("Auth: .\(state.rawValue) backend: \(backend.description)")
            }
        } else {
            if let error = error {
                print("Auth: .\(state.rawValue) error: \(error.localizedDescription)")
            } else {
                print("Auth: .\(state.rawValue)")
            }
        }

        switch state {
        // Configuration
        case .serviceConfigurationStarted:
            break
        case .serviceConfigured:
            break
        case .serviceConfigurationCompleted:
            // SDK is ready — you can now trigger login
            break

        // Login
        case .loginStarted:
            break
        case .loginPresented:
            break
        case .loggedIn:
            break
        case .loginAborted:
            break
        case .loginFailed:
            if let error = error {
                print("Login failed: \(error.localizedDescription)")
            }
        case .loginLinkAccountPresented:
            break
        case .loginCompleted:
            // Login fully complete — safe to update UI
            break

        // Token
        case .tokenRefreshed:
            break

        // Logout
        case .logoutStarted:
            break
        case .loggedOut:
            break
        case .logoutCompleted:
            // Logout fully complete — update UI
            break

        @unknown default:
            break
        }
    }
}
```

### Android

```kotlin
class MainActivity : AppCompatActivity() {

    private lateinit var tmAuthentication: TMAuthentication

    private val loginLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        when (result.resultCode) {
            Activity.RESULT_OK -> showEventsScreen()
            Activity.RESULT_CANCELED -> Log.d("Auth", "Login cancelled or failed")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setupSDK()
    }

    private fun setupSDK() {
        lifecycleScope.launch {
            TMAuthentication.Builder(
                apiKey = BuildConfig.CONSUMER_KEY,
                clientName = BuildConfig.TEAM_NAME
            )
                .region(TMXDeploymentRegion.US)
                .environment(TMXDeploymentEnvironment.Production)
                .build(this@MainActivity)
                .fold(
                    onSuccess = { auth ->
                        tmAuthentication = auth
                        observeAuthState()
                    },
                    onFailure = { error ->
                        Log.e("Auth", "Configuration failed: ${error.message}")
                    }
                )
        }
    }

    private fun observeAuthState() {
        // Observe granular state transitions
        tmAuthentication.getLoginStateLiveData().observe(this) { state ->
            Log.d("Auth", "State: $state")

            when (state) {
                ServiceLoginState.SERVICE_CONFIGURATION_COMPLETED -> {
                    // SDK is ready — launch login
                    launchLogin()
                }
                ServiceLoginState.LOGIN_COMPLETED -> {
                    // Login fully complete
                    showEventsScreen()
                }
                ServiceLoginState.LOGIN_FAILED -> {
                    Log.e("Auth", "Login failed")
                }
                ServiceLoginState.LOGIN_LINK_ACCOUNT_PRESENTED -> {
                    Log.d("Auth", "Link account screen presented")
                }
                ServiceLoginState.LOGOUT_COMPLETED -> {
                    // Logout complete — return to login screen
                    launchLogin()
                }
                else -> { }
            }
        }
    }

    private fun launchLogin() {
        loginLauncher.launch(tmAuthentication.getLoginIntent(this))
    }

    private fun showEventsScreen() {
        TicketsSDKSingleton.getEventsFragment(this)?.let { fragment ->
            supportFragmentManager.beginTransaction()
                .replace(R.id.fragmentContainer, fragment)
                .commit()
        }
    }
}
```

---

## Common Patterns

### Waiting for Login to Complete

On both platforms, wait for `loginCompleted` / `LOGIN_COMPLETED` before updating your UI. The `loggedIn` / `LOGGED_IN` state fires per-backend and login may still be in progress.

### Handling Multiple Backends

During login with multiple backends (e.g., Host + Archtics), you will see a sequence like:

```plaintext
LOGIN_STARTED
LOGIN_PRESENTED     (for Archtics)
LOGGED_IN           (for Archtics)
LOGIN_PRESENTED     (for Host)
LOGGED_IN           (for Host)
LOGIN_COMPLETED     (once, at the end)
```

The same pattern applies to configuration and logout — intermediate states fire per-backend, while the `*_COMPLETED` state fires once at the end.

---

## Related Documentation

- [Authentication](/v1/docs/authentication-1) — Authentication setup and configuration
- [Configuration](/v1/docs/configuration-1) — SDK configuration guide
