> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Email & SMS Authentication

Authenticate users with email or SMS one-time passwords (OTP).

## Email Authentication

```kotlin theme={"system"}
import com.dynamic.sdk.android.DynamicSDK

val sdk = DynamicSDK.getInstance()

// Send OTP to email
sdk.auth.email.sendOTP("user@example.com")

// Later, verify:
sdk.auth.email.verifyOTP("123456")

// Resend if needed:
sdk.auth.email.resendOTP()
```

### Rate Limits

Email verification is subject to the following rate limits:

* 3 attempts per 10 minutes per email address

This is in place to protect deliverability of emails and to prevent abuse.

## SMS Authentication

```kotlin theme={"system"}
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.Models.PhoneData

val sdk = DynamicSDK.getInstance()

// Send OTP via SMS
val phoneData = PhoneData(
    dialCode = "+1",
    iso2 = "US",
    phone = "5551234567"
)
sdk.auth.sms.sendOTP(phoneData)

// Later, verify:
sdk.auth.sms.verifyOTP("123456")

// Resend if needed:
sdk.auth.sms.resendOTP()
```

## External JWT Authentication

For apps with existing authentication systems, you can authenticate users with an external JWT:

```kotlin theme={"system"}
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.Models.SignInWithExternalJwtParams

val sdk = DynamicSDK.getInstance()

sdk.auth.externalAuth.signInWithExternalJwt(
    SignInWithExternalJwtParams(jwt = "your-jwt-token")
)
```

## Passkey Authentication

Sign in with a passkey:

```kotlin theme={"system"}
import com.dynamic.sdk.android.DynamicSDK

val sdk = DynamicSDK.getInstance()

sdk.auth.passkey.signIn()
```

For more details on passkey management and setup, see the [Passkeys](/kotlin/passkeys) documentation.

## Authentication State

Monitor authentication state and get user information:

```kotlin theme={"system"}
import com.dynamic.sdk.android.DynamicSDK
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch

val sdk = DynamicSDK.getInstance()

// Check if user is authenticated
val isAuthenticated = sdk.auth.isAuthenticated()

// Get current user
val user = sdk.auth.authenticatedUser
if (user != null) {
    println("User: ${user.userId}")
    println("Email: ${user.email}")
}

// Get auth token
val token = sdk.auth.token
if (token != null) {
    println("Token: $token")
}

// Listen for authentication changes (in ViewModel)
viewModelScope.launch {
    sdk.auth.authenticatedUserChanges.collect { user ->
        if (user != null) {
            // User logged in
            println("User authenticated: ${user.userId}")
        } else {
            // User logged out
            println("User logged out")
        }
    }
}

// Listen for token changes (in ViewModel)
viewModelScope.launch {
    sdk.auth.tokenChanges.collect { token ->
        if (token != null) {
            println("Token updated: $token")
        }
    }
}

// Logout
sdk.auth.logout()
```

## Built-in UI

The easiest way to add authentication is using the built-in UI which handles all authentication methods:

```kotlin theme={"system"}
import com.dynamic.sdk.android.DynamicSDK

val sdk = DynamicSDK.getInstance()
sdk.ui.showAuth()
```

## Best Practices

### 1. Error Handling

Always handle errors gracefully and provide clear feedback to users:

```kotlin theme={"system"}
try {
    sdk.auth.email.sendOTP(email)
} catch (e: Exception) {
    when {
        e.message?.contains("rate limit") == true -> {
            showError("Too many attempts. Please try again later.")
        }
        e.message?.contains("invalid email") == true -> {
            showError("Please enter a valid email address.")
        }
        else -> {
            showError("Failed to send OTP: ${e.message}")
        }
    }
}
```

### 2. User Experience

* Show loading states during authentication
* Provide clear error messages
* Allow users to resend OTP if needed
* Display the email/phone where OTP was sent

### 3. Security

* Never store OTP codes
* Always use HTTPS connections
* Implement proper session management
* Handle token refresh automatically

## Troubleshooting

### OTP Not Received

* Check that the email/phone number is valid
* Look in spam folder for email OTP
* Verify that the provider is enabled in Dynamic dashboard
* Check rate limits haven't been exceeded

### Authentication Fails

* Ensure OTP code is entered correctly
* Check that the code hasn't expired (codes typically expire after 10 minutes)
* Verify network connectivity
* Check for any error messages in Logcat

### Session Not Persisting

* Ensure you're listening to `authenticatedUserChanges` flow
* Verify that the SDK is properly initialized
* Check that you're not clearing app data

## What's Next

Now that you have authentication set up:

1. **[Social Authentication](/kotlin/social-authentication)** - Add social login options
2. **[Session Management](/kotlin/session-management)** - Manage authenticated sessions with Kotlin Flow
3. **[Wallet Operations](/kotlin/wallets)** - Work with user wallets
4. **[MFA](/kotlin/mfa)** - Add multi-factor authentication
