OAuth2.0 has been a very popular protocol among developers for delegating authorization for modern apps. But when it comes to mobile apps or single page application (SPAs), the traditional Authorization code flow done with the help of client_id
and client_secret
has a serious security vulnerability: Code Interception.
Here enters: PKCE (Proof Key for Code Exchange) — a security enhancement that protects public clients from code interception attacks. This post breaks down what PKCE is, how it works, and how to implement it.
Need of PKCE Flow
In the traditional OAuth2.0 Authorization code flow, the client first sends authorize request to authorization server with client_id
, the server then responds back with a authorization_code
and then the client sends a request with the authorization_code
and client_secret
. Now, the problem here is that public client like mobile apps and SPAs can not store secrets securely and this makes them vulnerable to interception attacks. So, your authorization_code
and client_secret
once they get intercepted by an attacker can use them to initiate token exchange and access resources. PKCE flow mitigates this by adding a dynamic challenge and verification in each authorization request. This ensures that only the app has the ability to get authorized not any attacker even if they have intercepted the authorization_code
.
How PKCE Flow works
Let's walk through the PKCE flow and how it works:
1. Client generates Secret and Challenge
In this steps the client create a Secret and a Challenge. Secret is any random string and the Challenge is hashed version of the Secret using any of the cryptographic algorithms (SHA3-256 in our case).
code_verifier = randomString(43-128 chars)
code_challenge = base64url(SHA3-256(code_verifier))
2. Client send authorize request with code_challange
.
The client initiates authorization.
GET /authorize?
response_type=code&
client_id=your-client-id&
redirect_uri=https://yourapp.com/callback&
code_challenge=f591f035a31f320015177cadb73e2056939b5ddbd30e902c5f274bc092b29545&
code_challenge_method=SHA3-256
So there are two methods to pass code_challange_method
. First we can save it in the database of our authorization server as part of client's config, secondly we can pass it in the URL as a parameter, to add an extra layer of security in second method we can keep changing the method in each request.
3. User approval and server's redirect
The user logs in and approves apps access to its resources, and the authorization server redirects to client's callback url with authorization_code
.
Once the user is authenticated the server stores the code_challenge
and code_challenge_method
against authorization_code
that it issued.
4. Client initiates token exchange
Now once redirected, the client then uses authorization_code
to get tokens in exchange. Here the client sends code_secret
as parameter in request. This is the original Secret generated in the first step.
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=XYZ&
code_secret=some_code
The server compares the hash of code_secret
with the earlier code_challenge
. If they match, it issues tokens. Here while generating the hash from code_secret
one may introduce hash rounds a client's config, which is stored over database and only known to authorization server and the client. Adding hash rounds makes apps more secure and even less vulnerable to attacks. Even if someone mimics the PKCE flow, creating their own secret and challenge, they might not be aware of exact number of hash rounds.
When to use PKCE?
Use PKCE whenever your app is a public client:
- Native mobile apps (iOS, Android)
- Single Page Applications (React, Angular, Vue)
- Desktop apps (Electron, etc.)
Implementation Tips
- Use
SHA-256
as cryptographic method, or keep changing for each request - Never re-use
code_secret
, always generate new Secret for new request - Keep the PKCE logic in secure memory, avoid writing to local storage in browsers
Conclusion
So, at last we can conclude that OAuth2.0 can be a great choice to authorize users if you are building a public client, but with PKCE it adds more security with minimal complexity.
Thanks for you time!
Have a great day ahead!
Top comments (0)