# Auth0 Android Major Migration

> >

- **Type:** Skill
- **Install:** `agentstack add skill-auth0-agent-skills-auth0-android-major-migration`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [auth0](https://agentstack.voostack.com/s/auth0)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [auth0](https://github.com/auth0)
- **Source:** https://github.com/auth0/agent-skills/tree/main/plugins/auth0/skills/auth0-android-major-migration

## Install

```sh
agentstack add skill-auth0-agent-skills-auth0-android-major-migration
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Auth0.Android v4 Migration

Migrates an existing Auth0.Android (`com.auth0.android:auth0`) v3 integration to v4. Every code change is gated on a search that confirms the project actually calls the affected API — if the project never uses `SecureCredentialsManager`, no `SecureCredentialsManager` code is touched. Changes follow the project's existing architecture (Kotlin or Java, callback or coroutine) and Android conventions.

## Target version is argument-based

This skill accepts an optional target version argument:

- **`/auth0-android-major-migration 4.0.0`** — migrate to the exact tag `4.0.0` (validated before use).
- **`/auth0-android-major-migration`** (no argument) — auto-resolve the **latest release within the next major (v4.x)**, including pre-releases.

`$ARGUMENTS`, when present, is the requested target tag. Step 2 validates it and resolves the final `` used for the rest of the migration.

## When NOT to Use

- **New Auth0 integration** (no existing Auth0.Android SDK): Use [auth0-android](/auth0-android)
- **Minor/patch update** (e.g., 3.18 → 3.19): Bump the `com.auth0.android:auth0` version in Gradle — no migration needed
- **iOS / macOS apps**: Use [auth0-swift-major-migration](/auth0-swift-major-migration)
- **React Native / Expo**: Use [auth0-react-native](/auth0-react-native) or [auth0-expo](/auth0-expo)
- **Flutter**: Use the native Flutter Auth0 SDK

## Prerequisites

- Existing Auth0.Android v3 integration (`com.auth0.android:auth0:3.x`)
- Android SDK / Gradle toolchain installed; project builds cleanly on the current version
- Project under git version control with a clean working tree

---

## Migration Workflow

> **Agent instruction:** Execute every step in order. The goal is a green build with the smallest correct changeset. Each code-change step is gated by the Step 5 file-reading audit — if the API was not found in the project's source files, skip the entire step for that area. Never add code the project doesn't already call. v4 also raises platform requirements (Step 3) that can **block** the migration until satisfied — handle those before touching any Auth0 API call site.

---

### Step 1 — Pre-flight & Safety Backup

```bash
# 1a. Verify clean working tree — stop if there are uncommitted changes
git status --porcelain
```

If the output is non-empty, ask the user:
> *"You have uncommitted changes. Should I stash them before proceeding (`git stash`), or would you like to commit first?"*

```bash
# 1b. Create a safety branch the user can reset to at any time
git checkout -b auth0-v4-migration-backup
git checkout -
```

```bash
# 1c. Confirm the project builds on the current version before touching anything
./gradlew assembleDebug 2>&1 | tail -15
```

If the build fails, stop. Ask the user to fix the existing issues first — do not migrate a project that does not build.

---

### Step 2 — Detect Current & Resolve Target Version

**Detect the current Auth0.Android version** (check each location that applies):

```bash
# Inline dependency in a module build file (Groovy or Kotlin DSL)
grep -rEn "com\.auth0\.android:auth0:[0-9]" --include=build.gradle --include=build.gradle.kts .

# Gradle version catalog
grep -rEn "auth0" --include=libs.versions.toml .

# Resolved lockfile (most reliable if present)
grep -rEn "com\.auth0\.android:auth0:[0-9]" --include=gradle.lockfile .
```

**Resolve the target version.** There are two paths:

**Path A — the user passed a target version argument (`$ARGUMENTS`):**

Validate it against the published releases before using it. It must pass **all three** checks:

```bash
# List all published Auth0.Android release tags
gh api repos/auth0/Auth0.Android/releases --paginate \
  --jq '.[] | select(.draft==false) | .tag_name'
```

1. **Exists** — the requested tag appears in the published release list above.
2. **Next major** — the tag is within the **v4** major line (`tag_name` starts with `4`). A `3.x` or lower tag is *not* the next major; reject it.
3. **Not a downgrade** — the tag is newer than the version detected in the project.

> **On any check failing, STOP and ask the user.** Do not silently fall back. For example:
> - *"`4.9.9` isn't a published Auth0.Android release. Published v4 releases are: `4.0.0-beta.1`, … . Please pass a valid v4 tag, or omit the argument to auto-resolve the latest v4 release."*
> - *"`3.19.0` is a v3 release, not the next major. This skill migrates to v4. Pass a v4 tag (e.g. `4.0.0`) or omit the argument."*
> - *"`4.0.0-beta.0` is older than the `4.0.0-beta.1` already in your project — that's a downgrade. Pass a newer v4 tag or omit the argument."*

**Path B — no argument: auto-resolve the latest v4 release (including pre-releases):**

```bash
# Newest v4.x release tag (stable or pre-release), most recent first
gh api repos/auth0/Auth0.Android/releases --paginate \
  --jq '[.[] | select(.draft==false) | select(.tag_name|startswith("4"))] | .[0].tag_name'
```

Record the result as `` and use it in every subsequent step.

> **If `` is a pre-release** (contains `-beta`, `-rc`, etc.), tell the user before continuing:
> *"v4 is not yet generally available — the latest v4 release is `` (a pre-release). I'll migrate to that. You can pin a different tag by passing it as an argument."*
>
> **If no v4 release exists yet** (the resolver returns empty), stop and tell the user there is no published v4 release to migrate to.

---

### Step 3 — Prerequisite Gate (Requirements Changes)

v4 raises the build toolchain and platform floor. Check each requirement **before** migrating any API. If a requirement is unmet, prompt the user and apply the build-file change (or block until they confirm) — a project that doesn't meet these will not build against v4 regardless of API changes.

> Confirm the exact required versions for `` from the SDK's own `build.gradle` / `gradle-wrapper.properties` fetched in Step 4 if they differ from the values below (these reflect the v4 baseline).

| Requirement | v3 | v4 | Where to check / change |
|---|---|---|---|
| **minSdk** | 21 | **26** (Android 8.0) | `android { defaultConfig { minSdk } }` |
| **Java** | 8+ | **17** | `compileOptions { sourceCompatibility/targetCompatibility }`, `kotlinOptions { jvmTarget }` |
| **Gradle** | — | **8.11.1+** | `gradle/wrapper/gradle-wrapper.properties` (`distributionUrl`) |
| **AGP** | — | **8.10.1+** | root `build.gradle` `com.android.tools.build:gradle` classpath / `plugins` block |
| **Kotlin** | — | **2.0.21** | `ext.kotlin_version` / version catalog (only if the project uses Kotlin) |

```bash
# Inspect current values
grep -rEn "minSdk(Version)?\s*[ =]" --include=build.gradle --include=build.gradle.kts .
grep -rEn "sourceCompatibility|targetCompatibility|jvmTarget" --include=build.gradle --include=build.gradle.kts .
grep -En "distributionUrl" gradle/wrapper/gradle-wrapper.properties
grep -rEn "com\.android\.tools\.build:gradle|kotlin_version|kotlin(\"|-)" --include=build.gradle --include=build.gradle.kts --include=libs.versions.toml .
```

**`minSdk` below 26 is a hard block.** If the project targets API 25 or lower, tell the user this raises the minimum supported Android version (devices on Android 7.1 and below will no longer be supported) and ask them to confirm before bumping `minSdk` to 26 — or to stay on v3.

Apply the required bumps (example shapes — match the project's DSL):

```groovy
android {
    defaultConfig { minSdk 26 }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
    kotlinOptions { jvmTarget = '17' }
}
```

See [references/process.md](references/process.md) for Kotlin DSL, version-catalog, and Gradle/AGP wrapper edge cases.

---

### Step 4 — Fetch & Read the v4 SDK Source

Fetch the actual Kotlin source for ``. The signatures here are the authoritative reference for every change made in Step 7. **Do not migrate from memory or from the guide alone — confirm each signature in the fetched source.**

```bash
TAG=   # the version resolved in Step 2, e.g. 4.0.0-beta.1
BASE="https://raw.githubusercontent.com/auth0/Auth0.Android/${TAG}/auth0/src/main/java/com/auth0/android"

# List all public Kotlin files in the SDK (confirm paths for this tag)
gh api "repos/auth0/Auth0.Android/git/trees/${TAG}?recursive=1" \
  --jq '.tree[].path | select(startswith("auth0/src/main/") and endswith(".kt"))'

# Fetch the files that back the breaking changes
for FILE in \
  provider/WebAuthProvider.kt \
  authentication/AuthenticationAPIClient.kt \
  authentication/mfa/MfaApiClient.kt \
  authentication/storage/SecureCredentialsManager.kt \
  authentication/storage/CredentialsManager.kt \
  authentication/storage/BaseCredentialsManager.kt \
  authentication/storage/Storage.kt \
  dpop/DPoPException.kt \
  result/SSOCredentials.kt \
  request/DefaultClient.kt ; do
    CONTENT=$(curl -sf "${BASE}/${FILE}")
    [ -n "$CONTENT" ] && echo "=== ${FILE} ===" && echo "$CONTENT"
done
```

> **If a release tag has no source yet** (e.g. during the v4 development phase, before the first tag carries the full tree), fall back to the `v4_development` branch for signature confirmation: replace `${TAG}` with `v4_development` in the URLs above. Always prefer the chosen tag when it has source.

Read the fetched source and note, for each file:
- Public method signatures that changed (parameters, return type, `@Throws`)
- Constructors that were removed
- Types/classes that were removed or renamed
- Default parameter values that changed (e.g. `minTtl`)

This is the ground truth. Every change in Step 7 must match a real signature in these files.

---

### Step 5 — Audit Which Auth0 APIs the Project Uses

**Find all source files that import the Auth0 SDK — these are the scope of the migration:**

```bash
grep -rlE "import com\.auth0\.android" --include="*.kt" --include="*.java" .
```

**Read every file from that list.** Do not grep for individual API patterns and stop there — read the full source so you can see exactly how `Auth0`, `WebAuthProvider`, `AuthenticationAPIClient`, `SecureCredentialsManager`/`CredentialsManager`, and any Auth0 types are used, including multi-line builder chains and any custom `Storage` conformances.

For each file, identify:

| What to look for | Section |
|---|---|
| `PasskeyAuthProvider` usage | §7.1 — class removed |
| `UsersAPIClient`, `ManagementException`, `ManagementCallback` | §7.2 — Management API removed |
| `loginWithOTP(`, `loginWithOOB(`, `loginWithRecoveryCode(`, `multifactorChallenge(` on `AuthenticationAPIClient` | §7.3 — deprecated MFA methods removed |
| `WebAuthProvider.useDPoP(` called on the object *before* `.login(` | §7.4 — `useDPoP` moved to the login builder |
| `DPoPException.UNSUPPORTED_ERROR` | §7.5 — constant removed |
| `.expiresIn` accessed on an `SSOCredentials` value | §7.6 — renamed to `expiresAt` (now a `Date`) |
| `SecureCredentialsManager(` with an `Auth0` instance as the first argument | §7.7 — `Auth0`-based constructors removed |
| `getCredentials(` / `awaitCredentials(` without an explicit `minTtl`, or `hasValidCredentials()` | §9.1 — default `minTtl` 0 → 60s (behavioral) |
| `clearCredentials(` | §9.3 — now clears **all** storage |
| A class implementing the `Storage` interface | §9.4 — new `removeAll()` (default impl provided) |

Build a checklist: **"This project uses: [list]"** and **"This project does NOT use: [list]"**. Only work through the §7.x / §9.x sections that appear in the "uses" list. Skip the rest entirely.

---

### Step 6 — Update the SDK Dependency

Apply the matching declaration style. Use `` from Step 2.

**Inline — Groovy DSL (`build.gradle`):**

```groovy
implementation 'com.auth0.android:auth0:'
```

**Inline — Kotlin DSL (`build.gradle.kts`):**

```kotlin
implementation("com.auth0.android:auth0:")
```

**Version catalog (`gradle/libs.versions.toml`):**

```toml
[versions]
auth0 = ""
```

> **Pre-release tags** (e.g. `4.0.0-beta.1`) must be pinned **exactly** — do not use a dynamic range like `4.+` or `[4.0,5.0)`, which Gradle may resolve to a different artifact. For stable v4 releases an exact version is still recommended for reproducibility.

Do **not** build yet — apply all known code changes first (Step 7), then build (Step 8) to surface any remainders.

---

### Step 7 — Apply Breaking Changes

> **Agent instruction:** Work through only the §7.x sections that matched during the Step 5 audit. Skip every section whose API the project does not use — do not touch those files. Apply each change exactly as shown, confirmed against the source fetched in Step 4. Do not rename variables, reformat, or modernise code that isn't being migrated. Match the project's existing style: callback → callback, coroutine `await` → coroutine `await`, Kotlin → Kotlin, Java → Java.

---

#### 7.1 — `PasskeyAuthProvider` removed

**Applies if:** Step 5 found `PasskeyAuthProvider` in the project's source files.

The `com.auth0.android.provider.PasskeyAuthProvider` class was removed. Passkey operations now live on `AuthenticationAPIClient`: `passkeyChallenge()`, `signupWithPasskey()`, and `signinWithPasskey()`. Confirm the exact signatures in the `AuthenticationAPIClient.kt` fetched in Step 4, then migrate each call site to the corresponding client method. If a passkey flow cannot be migrated confidently from the source, add a `// TODO:` and list it in the Step 10 summary rather than guessing.

---

#### 7.2 — Management API removed (`UsersAPIClient`)

**Applies if:** Step 5 found `UsersAPIClient`, `ManagementException`, or `ManagementCallback` in the project's source files.

The entire Management API client was removed from the SDK in v4. Calling the Management API directly from a mobile app was never recommended — it requires a privileged token on the device. **Do not silently delete the call sites.** Add a `// TODO:` that preserves the intent and surface this in the Step 10 summary as required backend work.

```kotlin
// v3 — direct Management API call from the app (e.g. updating user_metadata)
val users = UsersAPIClient(account, accessToken)
users.updateMetadata(userId, metadata)
    .start(object : Callback { /* ... */ })

// v4 — Management client removed; preserve intent, move to a backend
// TODO: Auth0.Android v4 removed the Management API client (UsersAPIClient).
// Expose an endpoint on your own backend (e.g. PATCH /me/metadata) that performs
// this operation. Call it from the app with the user's access token as a Bearer
// token. On the backend, obtain a machine-to-machine token via Client Credentials
// and call the Management API with the minimum required scopes.
// NEVER embed a Management API token in the app.
// See: https://auth0.com/docs/manage-users/user-accounts/manage-user-metadata
```

This **requires backend work** — record it in the Step 10 summary.

---

#### 7.3 — Deprecated MFA methods removed from `AuthenticationAPIClient` → `MfaApiClient`

**Applies if:** Step 5 found `loginWithOTP(`, `loginWithOOB(`, `loginWithRecoveryCode(`, or `multifactorChallenge(` called on an `AuthenticationAPIClient` in the project's source files.

These four methods were deprecated in v3 and removed in v4. Obtain an `MfaApiClient` via `AuthenticationAPIClient.mfaClient(mfaToken)` and use its APIs. Confirm the exact `MfaApiClient` method signatures in the `MfaApiClient.kt` fetched in Step 4 before applying changes.

```kotlin
// v3 — removed methods on AuthenticationAPIClient
authentication
    .loginWithOTP(mfaToken, otp)
    .start(object : Callback { /* ... */ })

// v4 — obtain an MfaApiClient and use its verify API (confirm signature in MfaApiClient.kt)
val mfaClient = authentication.mfaClient(mfaToken)
// e.g. mfaClient.verifyWithOTP(otp) — use the exact method/parameters from the fetched source
```

The `mfaToken` still comes from the same place — an `AuthenticationException` where the challenge is required. List every migrated MFA flow in the Step 10 summary and ask the user to **re-test each MFA flow end-to-end** against the

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [auth0](https://github.com/auth0)
- **Source:** [auth0/agent-skills](https://github.com/auth0/agent-skills)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-auth0-agent-skills-auth0-android-major-migration
- Seller: https://agentstack.voostack.com/s/auth0
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
