The OAuth2 flow for native apps: PKCE
If you are building a native application, and you need OAuth 2.0, PKCE OAuth is your best choice. Here I will explain why.
Native application is often used to refer to native application that has no back-end, and running totally in user’s devices such as Windows, Mac, iOS, and Android, where securely storing secrets is impossible.
What are the OAuth 2 options for those native applications and what are the pros and cons for them?
- Implicit Flow: Implicit flow will pass
Access Token
to Redirect URL。Assume your native application is redirecting to third-party browsers to perform OAuth2 authorization request, then your application either obtain theAccess Token
back by listening toapp-name://?access_token=
request or start a HTTP server to listen tohttp://localhost:{port}/?access_token=
request. These two approaches both have the risk ofAccess Token
being intercepted by malicious party who occupy URL Scheme or localhost port. Also access token can’t be renewed after expiration. Thus implicit flow is not recommended. - Authorization Code Flow:
Access Token
of this flow will not be passed toRedirect URL
directly.Redirect URL
will only receive anauthorization code
,which need to be used along withClient ID
,andClient Secret
to exchange forAccess Token
. Since native application can’t securely storeClient Secret
, malicious party can decode it from native code/binary, and interceptAuthorization Code
to exchange forAccess Token
. Thus authorization code flow is not recommended either. Even some OAuth provider doesn’t requireClient Secret
,Access Token
can still be exchanged by malicious party.
Now that two options are excluded, how can native application securely implement OAuth2? The answer is PKCE OAuth 2.0.
PKCE (Proof Key for Code Exchange), is using cryptography method to prevent malicious party to be able to exchange access token with the information they can intercept.
PKCE flow steps:
- Generate random string and encode with URL-Safe Base64, and used as
code_verifier
- Do SHA256 hash,and URL-Safe Base64,and used as
code_challenge
- Redirect to OAuth provider with
code_challenge
and receiveAuthorization Code
- Exchange for
Access Token
withcode_verifier
Since malicious party can’t infer code_verifier
by code_challenge
, only the native application itself knows about the two value. In this way, even if malicious party intercepted code_challenge
, it will not be able to exchange Access Token
.
Generate PKCE Code Verifier and Code Challenge Online
Link to the tool: https://tonyxu-io.github.io/pkce-generator/
Implementation (JavaScript)
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>
<script>
function generateCodeVerifier() {
var code_verifier = generateRandomString(32);
document.getElementById("code_verifier").value = code_verifier;
}
function generateRandomString(length) {
var text = "";
var possible =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
function generateCodeChallenge(code_verifier) {
return (code_challenge = base64URL(CryptoJS.SHA256(code_verifier)));
}
function base64URL(string) {
return string
.toString(CryptoJS.enc.Base64)
.replace(/=/g, "")
.replace(/\+/g, "-")
.replace(/\//g, "_");
}
function submit() {
var code_verifier = document.getElementById("code_verifier").value;
var code_challenge = generateCodeChallenge(code_verifier);
document.getElementById("code_challenge").innerHTML = code_challenge;
document.getElementById("code_challenge_div").style.display = "block";
}
</script>
</head>
<body>
<div>
<label for="code_verifier">Code Verifier: </label>
<input type="text" id="code_verifier" name="code_verifier" size="38" />
</div>
<br />
<div style="display:none" id="code_challenge_div">
Code Challenge:
<span id="code_challenge"> </span>
</div>
<br />
<div>
<button onclick="generateCodeVerifier()">Generate Code Verifier</button>
<button onclick="submit()">Generate Code Challenge</button>
</div>
</body>
</html>
OAuth2 providers that support PKCE
- OAuth 2.0 for Mobile & Desktop Apps
- Authorize access to Azure Active Directory web applications using the OAuth 2.0 code grant flow
- Implementing the Authorization Code Flow with PKCE
Reference: