adb authorization explained: RSA keys and the unauthorized error
The first time you plug an Android phone into a computer and run adb devices, you often don’t get a device ID back. You get the word unauthorized sitting next to the serial number instead. That single word is adb telling you the phone doesn’t trust this computer yet, and it won’t let you install an APK, pull logs, or open a shell until you tap “allow” on the phone’s own screen. Underneath that popup is an actual RSA keypair doing cryptographic verification, not just a permissions toggle you can flip and forget.
If you do any Android development, QA, screen mirroring, or device automation, you’ll run into this every time you touch a new machine, a fresh emulator image, a factory-reset phone, or a device running inside a container. Knowing what’s actually being checked, and where the keys live on disk, turns a confusing “why won’t adb see my phone” detour into a fix that takes ten seconds.
what it is
adb, the Android Debug Bridge, is the command-line tool Google ships in Android SDK Platform Tools for talking to a device or emulator from a desktop, covered in Google’s own adb reference. Authorization is the trust check adb runs before it lets a given computer do anything on that bridge. It’s a pairing step between two RSA keys: one your computer already has, one the device is deciding whether to remember.
This wasn’t always required. Early Android let any computer with USB access run adb commands against an unlocked phone with no confirmation at all. Google closed that hole starting with Android 4.2.2 (API level 17) in 2013, adding the authorization dialog and the underlying RSA challenge so a device only accepts commands from computers a human has explicitly approved. Google’s own security architecture docs walk through the exact protocol in Android’s ADB authentication reference.
how it works
Your computer generates an RSA keypair once, the first time adb runs, and stores it at ~/.android/adbkey (private key) and ~/.android/adbkey.pub (public key). On Windows that’s C:\Users\<you>\.android\adbkey. That keypair is tied to your machine, not to any one phone.
When you connect a device, whether over USB or via wireless debugging, adbd on the phone sends a random challenge token to the host. Your computer signs that token with its private key and sends the signature and its public key back. adbd checks that public key against the list it already trusts, stored on the device at /data/misc/adb/adb_keys. If it’s on the list, the connection goes straight through and adb devices reports the device as device. If it isn’t, the phone shows the “Allow USB debugging?” dialog with a fingerprint of that key, and until someone taps Allow, adb devices reports unauthorized, not offline, not broken, just waiting on a human.
Ticking “always allow from this computer” is what writes your public key into adb_keys permanently. Skip that box and you’ll get the prompt again next session. You can also force the whole thing to reset from the device side: Developer options has a “Revoke USB debugging authorizations” action that wipes adb_keys entirely, so every computer, including yours, has to be re-approved on the next connection. Both the dialog and the revoke option are documented in Google’s guide on running apps on a hardware device.
Wireless debugging complicates this slightly. Android 11 replaced the old adb tcpip workaround with a proper pairing flow built into Developer options, using a six-digit code instead of a plain accept-tap. I go through that handshake step by step in the adb over Wi-Fi wireless debugging guide, including where that pairing state lives separately from the USB adb_keys list.
why it matters
- it’s a real security boundary, not cosmetic. USB debugging being switched on doesn’t hand out shell access to whoever plugs in a cable. It just makes the device reachable; the RSA check is what still gates it.
- it blocks tools you already use. Screen mirroring apps like scrcpy ride on top of adb, so the exact same unauthorized state stops them cold. My scrcpy guide for controlling Android from a desktop covers where that popup shows up mid-setup and what to check if it never appears.
- it changes how you build test automation. Frameworks like UiAutomator2 and Appium (compared in my UiAutomator2 vs Appium piece) both drive devices through adb underneath. On an unattended device farm or CI runner, nobody’s there to tap the dialog, so keys have to be pre-approved on the device image, or the host has to point adb at a fixed keypair via the
ADB_VENDOR_KEYSenvironment variable instead of generating a new ephemeral one each run. - it works differently when the phone isn’t physically yours to unlock and tap. If you’re driving Android hardware that lives somewhere else, adb access has to be deliberately opened up rather than assumed. On cloudf.one, which rents real Android phones on dedicated hardware in Singapore, each with its own persistent Singapore mobile IP, there’s no self-service adb: adb and Appium only reach a rented phone through a WireGuard tunnel set up on request by emailing [email protected]. That’s a deliberate access boundary on top of the RSA check, not a workaround for it.
common misconceptions
- “USB debugging enabled means my phone is exposed to anyone with a cable.” Not quite. Enabling it in Developer options makes the phone reachable over adb, but the RSA handshake still has to clear, and that requires a tap on the device screen from an unrecognized key.
- “unauthorized means a broken cable or driver.” A bad cable or missing Windows driver usually shows up as the device not listing at all, or listing as
offline.unauthorizedspecifically means adb can see the device and is waiting for the on-device approval tap, so check the phone screen for a hidden dialog before touching drivers. - “emulators behave exactly like real hardware for this.” Not always. Many Android emulator system images used for local testing ship with adb’s secure mode disabled, so they skip the authorization prompt entirely, which can hide a permissions issue you’d hit immediately on physical hardware. I break down where the two diverge in emulator vs real device testing.
- “revoking authorizations breaks my setup for good.” It just clears the device’s trusted-key list. Your RSA keypair on the computer is untouched; you’ll simply see the approval dialog once more on the next connection, from every host including your own.
where to go from here
A few directions worth following once the basic authorization flow makes sense:
- set up authorization-free debugging over the network with adb over Wi-Fi wireless debugging, which uses a pairing code instead of the USB dialog.
- if the goal is mirroring and controlling a phone from a desktop rather than scripting it, the scrcpy guide covers the same authorization step from that angle.
- for anyone building automated test suites, UiAutomator2 vs Appium explains how each framework handles device connections and where pre-authorized keys save you from flaky CI runs.
- if you’re deciding whether to test on physical hardware or emulator images, emulator vs real device testing has the tradeoffs, including this authorization gap.
For more explainers like this one, the blog index has the rest of the adb series.
Only automate devices and apps you own or are authorized to test. This article doesn’t cover, and I won’t cover, defeating root detection, Play Integrity, or any platform’s anti-automation terms.
Written by Xavier Fok
disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-09-12.