SDK

Android SDK (Kotlin)

Native Android authentication with OAuth 2.0 PKCE, encrypted storage, and biometric login.

Key Features

OAuth 2.0 Authorization Code + PKCE
EncryptedSharedPreferences token storage
BiometricPrompt (via a separate BiometricAuth class)
Automatic token refresh
Chrome Custom Tab login
Dedicated Jetpack Compose helpers
Kotlin Coroutines & Flow
Session management

Requirements

  • Android API 24+ (Android 7.0)
  • Kotlin 1.8+
  • Android Studio Hedgehog+

Installation

Add the dependency to your module-level build.gradle.

// build.gradle.kts (Module)
dependencies {
    implementation("com.idenplane:idenplane-android:1.0.0")
}

// settings.gradle.kts — add repository if needed
dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
}

Configuration

Construct an AuthConfig and pass it directly to IdenplaneClient — there is no separate builder.

import com.idenplane.sdk.IdenplaneClient
import com.idenplane.sdk.AuthConfig

val config = AuthConfig(
    serverUrl = "https://auth.example.com",
    realm = "my-realm",
    clientId = "my-android-app",
    redirectUri = "myapp://callback",
)
val idenplane = IdenplaneClient(applicationContext, config)

Login with PKCE

login() is a suspend function that just launches a Chrome Custom Tab — it does not return the result directly. Complete the flow in your Activity's onNewIntent/onResume.

// Launch login (opens Chrome Custom Tab)
lifecycleScope.launch {
    idenplane.login(activity)
}

// In your Activity:
override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    lifecycleScope.launch {
        val success = idenplane.handleRedirectIntent(intent)
        if (success) {
            val user = idenplane.getUserInfo()
            println("Logged in as ${user.name}")
        }
    }
}

Biometric Authentication

BiometricAuth is a separate class wrapping BiometricPrompt — it is not a method on IdenplaneClient.

import com.idenplane.sdk.BiometricAuth

val biometric = BiometricAuth(activity)

if (biometric.isBiometricAvailable) {
    lifecycleScope.launch {
        biometric.authenticate(title = "Verify your identity")
        // Execution continues here only after successful authentication
        val token = idenplane.getAccessToken()
    }
}

User Info

Retrieve the authenticated user profile. Note: the User model does not include a roles field — only OIDC standard claims.

lifecycleScope.launch {
    val user = idenplane.getUserInfo()
    println(user.name)              // "John Doe"
    println(user.email)             // "[email protected]"
    println(user.preferredUsername)
}

Token Management

Tokens are stored in EncryptedSharedPreferences and refreshed automatically before expiry.

// Get the current access token
val token = idenplane.getAccessToken()

// Manual refresh
lifecycleScope.launch {
    idenplane.refreshToken()
    val newToken = idenplane.getAccessToken()
}

// Check authentication state
if (idenplane.isAuthenticated) { /* ... */ }

Logout

Logout clears stored tokens.

lifecycleScope.launch {
    idenplane.logout(activity)
    println("Logged out")
}

Jetpack Compose Integration

The SDK ships dedicated Compose helpers — rememberIdenplaneClient (auto-disposes the client) and collectAuthStateAsState (wraps the authState StateFlow<Boolean>).

import com.idenplane.sdk.rememberIdenplaneClient
import com.idenplane.sdk.collectAuthStateAsState

@Composable
fun AuthScreen(config: AuthConfig) {
    val context = LocalContext.current
    val idenplane = rememberIdenplaneClient(context, config)
    val isAuthenticated by idenplane.collectAuthStateAsState()
    val scope = rememberCoroutineScope()

    if (isAuthenticated) {
        Button(onClick = { scope.launch { idenplane.logout(context as Activity) } }) {
            Text("Logout")
        }
    } else {
        Button(onClick = { scope.launch { idenplane.login(context as Activity) } }) {
            Text("Sign In")
        }
    }
}