This is a quick list of the most common Authentication use cases.
Login
AndroidManifest.xml code:
<activity
android:name="com.ticketmaster.authenticationsdk.internal.modernaccounts.presentation.ModernAccountsLoginScreen"
android:screenOrientation="portrait"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- YOUR SCHEME will be provided in your app settings, copy it to this location -->
<data android:scheme="psdkscheme[client scheme name]" />
</intent-filter>
</activity>
SportsXR Only AndroidManifest.xml code:
<activity
android:name="com.ticketmaster.authenticationsdk.internal.modernaccounts.presentation.ModernAccountsLoginScreen"
android:screenOrientation="portrait"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- YOUR SCHEME will be provided in your app settings, copy it to this location -->
<data android:scheme="psdkscheme[client scheme name]" />
</intent-filter>
</activity>
<activity
android:name="com.ticketmaster.authenticationsdk.internal.sportxr.presentation.SportXRLoginScreen"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- YOUR SCHEME will be provided in your app settings, copy it to this location -->
<data android:scheme="psdkscheme[client scheme name]" />
<data android:host="login" />
</intent-filter>
</activity>
Example Kotlin code:
private var tmAuthentication: TMAuthentication? = null
private val brandingColor: Int by lazy { BuildConfig.BRANDING_COLOR.toColorInt() }
private suspend fun buildAuthenticationClient(): TMAuthentication {
return TMAuthentication.Builder(
apiKey = BuildConfig.CONSUMER_KEY,
clientName = BuildConfig.TEAM_NAME
)
.modernAccountsAutoQuickLogin(false) // Optional: show screen before login
.colors(TMAuthentication.ColorTheme(
lightColors = lightColorScheme(
primary = Color(brandingColor),
secondary = Color(brandingColor),
onPrimary = Color.White
),
darkColors = darkColorScheme(
primary = Color(brandingColor),
secondary = Color(brandingColor),
onPrimary = Color.White
)
)) // Optional: define colors for the Authentication page
.region(TMXDeploymentRegion.US) // Region that the SDK will use. Default is US
.environment(TMXDeploymentEnvironment.Production) // Environment that the SDK will use. Default is Production
.build(this) // Pass activity context
}
private val loginLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
when (result.resultCode) {
Activity.RESULT_OK -> {
// Successful sign in
val accessTokenData = result.data
?.getParcelableExtra<AccessTokenData>(Constants.ACCESS_TOKEN_DATA)
?: AccessTokenData()
// Handle successful login (e.g., navigate to next screen)
}
Activity.RESULT_CANCELED -> {
// User cancelled the sign in process
}
}
}
private fun launchLogin() {
tmAuthentication?.getLoginIntent(this)?.let { intent ->
loginLauncher.launch(intent)
}
}
//Initialize and launch in your lifecycle:
override fun onCreate(savedInstanceState: Bundle?) {
//...
lifecycleScope.launch {
tmAuthentication = buildAuthenticationClient()
launchLogin()
}
}import TicketmasterAuthentication
// Tickets SDK handles login for you, so this call is optional
// call after `TMAuthentication.shared.configure(...)`
TMAuthentication.shared.login { authToken in
print("Login Completed")
print(" - AccessToken: \(authToken.accessToken.prefix(20))...")
print(" - IdToken: \(authToken.idToken.prefix(20))...")
} aborted: { oldAuthToken, backend in
print("Login Aborted by User")
} failure: { oldAuthToken, error, backend in
print("Login Error: \(error.localizedDescription)")
}
Refresh Token
suspend fun getAccessToken() {
if (tmAuthentication == null) {
tmAuthentication = getClient()
}
if (tmAuthentication!!.configuration == null) {
// show an error
return
}
val archticsAccessToken = tmAuthentication.getToken(AuthSource.ARCHTICS)
val hostAccessToken = = tmAuthentication.getToken(AuthSource.HOST)
if (archticsAccessToken.isNullOrEmpty() && hostAccessToken.isNullOrEmpty()) {
val intent = tmAuthentication.getLoginIntent(activity)
loginLauncher.launch(intent)
}
}
suspend fun refreshAccessToken() {
// Ensure authentication client is initialized
if (tmAuthentication == null) {
tmAuthentication = buildAuthenticationClient()
}
// Verify configuration was loaded successfully
if (tmAuthentication?.configuration == null) {
Log.e("MainActivity", "Failed to load authentication configuration")
return
}
// Retrieve tokens from both auth sources
val archticsAccessToken = tmAuthentication?.getToken(AuthSource.ARCHTICS)
val hostAccessToken = tmAuthentication?.getToken(AuthSource.HOST)
// Launch login if no valid tokens exist
if (archticsAccessToken.isNullOrEmpty() && hostAccessToken.isNullOrEmpty()) {
Log.d("MainActivity", "No valid tokens found, launching login")
launchLogin()
} else {
// Log available tokens for debugging
archticsAccessToken?.let {
Log.d("MainActivity", "Archtics access token retrieved")
}
hostAccessToken?.let {
Log.d("MainActivity", "Host access token retrieved")
}
}
}
import TicketmasterAuthentication
// Tickets SDK handles refresh for you, so this call is optional
// call after `TMAuthentication.shared.configure(...)`
TMAuthentication.shared.validToken { authToken in
print("Token Refreshed (if needed)")
print(" - AccessToken: \(authToken.accessToken.prefix(20))...")
print(" - IdToken: \(authToken.idToken.prefix(20))...")
} aborted: { oldAuthToken, backend in
print("Refresh Login Aborted by User")
} failure: { oldAuthToken, error, backend in
print("Refresh Error: \(error.localizedDescription)")
}
Member Info
suspend fun getUserDetails() {
// Retrieve tokens from both auth sources
val archticsAccessToken = tmAuthentication?.getToken(AuthSource.ARCHTICS)
val hostAccessToken = tmAuthentication?.getToken(AuthSource.HOST)
// Launch login if no valid tokens exist
if (archticsAccessToken.isNullOrEmpty() && hostAccessToken.isNullOrEmpty()) {
Log.d("MainActivity", "No valid tokens found, launching login")
launchLogin()
} else {
val userdetails = tmAuthentication.fetchUserDetails()
}
}
import TicketmasterAuthentication
// Tickets SDK handles login for you, so this call is optional
// call after `TMAuthentication.shared.configure(...)`
TMAuthentication.shared.memberInfo { memberInfo in
print("MemberInfo Completed")
print(" - UserID: \(memberInfo.localID ?? "<nil>")")
print(" - Email: \(memberInfo.email ?? "<nil>")")
} failure: { oldMemberInfo, error, backend in
print("MemberInfo Error: \(error.localizedDescription)")
}
Logout
//TicketsSDKClient and TMAuthentication already has it's own logout logic, so this call is optional
//unless you add your own logout button somewhere
suspend fun logout() {
TicketsSDKSingleton.logout {
// The listener to be called after the logout process is completed
//remove the fragment from the container (requires the container id)
supportFragmentManager.findFragmentById(R.id.tickets_sdk_view)?.let {
supportFragmentManager.beginTransaction().remove(it).commit()
}
// Start LoginIntent
TicketsSDKSingleton.getLoginIntent(this@MainActivity)
?.let { loginLauncher.launch(it) }
}
}
import TicketmasterAuthentication
// TMTicketsViewController has it's own logout button, so this call is optional
// unless you add your own logout button somewhere
// call after `TMAuthentication.shared.configure(...)`
TMAuthentication.shared.logout { backends in
print("Logout Completed")
print(" - Backends Count: \(backends?.count ?? 0)")
}
Multi-Team authentication
The Authentication SDK allows users to stay signed into multiple teams at the same time, without signing out between switches. This section is also referenced from the Configuration page.
The flow works as follows:
Configure Team 1’s API key
User signs into Team 1
User views Team 1 tickets
Switch to Team 2: configure Team 2’s API key
User signs into Team 2
User views Team 2 tickets
Switch back to Team 1
User is still signed into Team 1 — no re-authentication required
User views Team 1 tickets
Two important constraints apply:
You must enable ephemeral web browser sessions (see Non-ephemeral vs. ephemeral login below). This prevents Team 1’s OAuth token from being returned to Team 2 during sign-in, but it also disables the shared login feature.
The Tickets SDK stores one team’s tickets at a time. Tickets are re-fetched automatically when switching teams — no extra code is required.
Video of multi-team sign-in (three Archtics teams):
Non-ephemeral vs. ephemeral login
Non-ephemeral
TMAuthentication.Builder()
.apiKey("")
// ...
.forceNewSession(false)
.build()TMAuthentication.shared.forceEphemeralWebBrowserSession = falseBy default, iOS uses a non-ephemeral login session. Cookies persist between sessions, so a user who is already signed into their Team Archtics account can also sign into Ticketmaster Host without re-entering their password.
Video showing single password entry:
Ephemeral
TMAuthentication.Builder()
.apiKey("")
// ...
.forceNewSession(true)
.build()TMAuthentication.shared.forceEphemeralWebBrowserSession = trueCookies are not stored between sessions. Use this mode for multi-team scenarios — it prevents Team 1’s credentials from being returned to Team 2 during sign-in. The trade-off is that the user must sign into Team Archtics and Host separately.
Video showing separate password entry per team:
Logout and multiple teams
Logout signs the user out of the current team and Host only. When the user switches to a different team, they’ll be prompted to sign back into Host.
Video showing logout and team switch:
To avoid requiring a Host re-login when switching teams, you can turn off combined login. This shows the team’s tickets without requiring the user to sign back into Host.
iOS
TMAuthentication.shared.useCombinedLogin = falseVideo showing optional Host sign-in: