OAuth 2.0 and PKCE
Prerequisite Knowledge
Before reading this article, you should first learn about:
In the previous articles on OAuth 2.0 and OIDC, we explained the authorization code flow in detail. There is a key step:
The ExampleNote server uses the authorization code and
client_secretto get the Access Token.
This process looks perfect, but it has a hidden assumption: the client can keep the client_secret safe.
For a server-side web app, this is true, because the client_secret is stored on the server. Users and hackers cannot get it.
But for mobile apps (Android, iOS), SPA apps (frontend only apps), and desktop apps, this is not true.
For example, suppose you are making an Android app and want to use Google login. Following the standard OAuth 2.0 flow, you need to put the client_secret in your app code.
But Android APK files can be decompiled. Anyone can extract the client_secret from your app.
This brings up an important concept in OAuth 2.0: Client Types. There are mainly two types:
Confidential Client: A client that can keep the client_secret safe.
A typical example is a server-side web app. The client_secret is on the server and not exposed.
Public Client: A client that cannot keep the client_secret safe. For example, mobile apps, SPA apps, and desktop apps.
The Dilemma of Public Clients
Public clients have a dilemma:
Problem 1: With client_secret, it will leak
If you hard-code the client_secret in an Android app, after decompiling the APK, a hacker can steal it and pretend to be your app.
Even though you can use app protection, like code obfuscation or reinforcement, it only makes it harder to decompile. Including the client_secret in the app code is a serious security risk. It should be avoided.
Problem 2: Without client_secret, it's not safe
If you don't use the client_secret and just use the code to get the token, there can be an authorization code interception attack: if a hacker steals the code, they can use it to get an Access Token and access user data.
So, using a static secret is risky, but not using it is not safe either. What can we do? For this problem, there is a special solution for public clients: PKCE (Proof Key for Code Exchange).
Below is the full timing diagram of the PKCE authorization code flow: