# APK Decompilation for OAuth/API Discovery

Session-derived technique: when an external API integration is broken and official docs are ambiguous or incomplete, decompiling a working competitor APK is often the fastest way to find the exact mechanics.

## When to Use This

- OAuth/device-code flows that don't match the documented spec
- Undocumented API endpoints (common in streaming apps)
- Parameter ordering or naming that differs from official docs
- Error handling patterns that aren't documented
- Token refresh mechanics that aren't publicly documented
- The integration "should work" per docs but fails in practice

## Workflow

### 1. Obtain the APK

Download from the app's website or extract from an Android device:
```bash
adb shell pm path com.example.app
adb pull /data/app/com.example.app-1/base.apk ./competitor.apk
```

### 2. Decompile with jadx

```bash
# Install jadx if not present
cd /tmp
curl -sL "https://github.com/skylot/jadx/releases/download/v1.5.1/jadx-1.5.1.zip" -o jadx.zip
unzip -q jadx.zip -d jadx-1.5.1

# Decompile
cd ~/apk-analysis
mkdir -p competitor-jadx
/tmp/jadx-1.5.1/bin/jadx --show-bad-code -d competitor-jadx competitor.apk
```

Note: `--show-bad-code` includes decompilations that may have errors. Expect some errors for obfuscated apps — the bulk of the code is still usable.

### 3. Search for the relevant flow

Use content search to find the auth/network code:
```bash
# Find auth-related files
grep -rln "oauth\|device.*code\|client_secret\|access_token" competitor-jadx/sources/ | head -20

# Find debrid-specific files
grep -rln "real.*debrid\|alldebrid\|premiumize\|torbox" competitor-jadx/sources/ | head -20

# Find the UI that triggers auth
grep -rln "connect.*debrid\|login.*debrid\|auth.*debrid" competitor-jadx/sources/ | head -20
```

### 4. Read the implementation

Trace from UI click → ViewModel/Presenter → API client → network call:
1. Find the activity/fragment that handles the auth (search for "login", "auth", "connect" in activity names)
2. Read the UI click handler — what method does it call?
3. Follow to the network layer — what API class/method is invoked?
4. Read the API interface — exact endpoint URLs, parameter names, HTTP methods
5. Read the response models — exact field names and types
6. Check error handling — what HTTP codes are treated as "keep polling" vs "fatal"

### 5. Extract the pattern

Document:
- Exact endpoint URL with all query/body parameters
- Request/response model field names
- Polling interval and timeout
- Error handling per HTTP status code
- Token storage pattern

## Real Example: Real-Debrid OAuth v2 (from Cinema HD v3.0.6)

**Problem:** Our Real-Debrid auth was broken. The user entered the device code on real-debrid.com but the app never authenticated. Official RD docs mention `/device/code` and `/token` but don't clearly document the 3-step flow.

**Decompiled source found:**
File: `com/movie/ui/activity/settings/subfragment/PremiumAccountFragment.java`

```java
void loginRealDebird() {
    // Step 1: request device code
    RealDebridGetDeviceCodeResult body = api.oauthDeviceCode(rd_client_id).execute().body();
    String device_code = body.getDevice_code();
    String user_code = body.getUser_code();
    
    // Show user the code + URL
    RxBus.post(new ApiRealDebridWaitingToVerifyEvent(verification_url, user_code));
    
    // Step 2: poll /device/credentials every 'interval' seconds
    for (int i = 0; i < expires_in; i++) {
        Thread.sleep(1000L);
        if (i % interval == 0) {
            RealDebridCheckAuthResult creds = api.oauthDeviceCredentials(rd_client_id, device_code).execute().body();
            String client_id = creds.getClient_id();
            String client_secret = creds.getClient_secret();
            
            if (client_id != null && client_secret != null && !client_id.isEmpty() && !client_secret.isEmpty()) {
                // Step 3: exchange for token
                HashMap hashMap = new HashMap();
                hashMap.put("client_id", client_id);
                hashMap.put("client_secret", client_secret);
                hashMap.put("code", device_code);
                hashMap.put("grant_type", "http://oauth.net/grant_type/device/1.0");
                
                RealDebridGetTokenResult token = api.oauthtoken(hashMap).execute().body();
                // token.getAccess_token() → store
                break;
            }
        }
    }
}
```

**Key discovery:** The flow has **three steps**, not two:
1. `/device/code` → `device_code`
2. **Poll `/device/credentials` → `client_id` + `client_secret`** (this was missing!)
3. `/token` with `client_id` + `client_secret` + `code` → `access_token`

**Result:** Adding the missing `/device/credentials` step fixed our Real-Debrid auth completely.

## Tips

- **Start with the UI layer, not the API layer.** Find the button click handler first, then trace down. Searching for API endpoints directly in a large codebase is slow.
- **Look for RxJava callbacks or async patterns.** Many Android apps use `Observable.create()`, `Single.create()`, or coroutines. The polling loop is often inside an `ObservableOnSubscribe` or `suspend` block.
- **Check the manifest for activities.** The `AndroidManifest.xml` lists all activities — use it as a map. Search for activity names containing "settings", "account", "premium", "debrid", "auth".
- **Don't worry about obfuscation.** Even if classes are renamed to `a`, `b`, `c`, the method names within API interfaces are often preserved (Retrofit uses reflection). Look for `@GET`, `@POST`, `@Query`, `@Field` annotations.
- **Use grep with context.** `grep -rn "oauthDeviceCode\|deviceCredentials" --include="*.java" sources/` finds the exact file quickly.

## Legal Note

Only decompile APKs you have the right to analyze (your own, or competitors' free/public APKs distributed for general use). Do not redistribute decompiled source code. Use it as a reference for your own independent implementation.
