OathWall

What Is PKCE and Why Your Game Needs It

The Oathwall Team3 min read

PKCE is the piece of OAuth that exists specifically because apps like games can't keep a secret. If you've read that your game is a "public client" and wondered how it's supposed to complete a login safely without a client secret, PKCE is the answer. Here's what it is and the exact attack it stops.

The problem PKCE solves

Go back to the OAuth authorization code flow. The provider hands your app a short-lived authorization code at the redirect step, and the app trades that code for tokens. On a confidential server, the exchange is protected by the client secret — only the holder of the secret can redeem the code.

On a device, there's no secret to protect it. And there's a specific way that bites on mobile: apps receive the redirect through a custom URI scheme (mygame://callback), and more than one app can register the same scheme. A malicious app that registered your scheme could intercept the authorization code as it comes back. Without a secret, the provider can't tell your app apart from the imposter — either could redeem the code for real tokens.

That's the authorization code interception attack, and it's not theoretical. PKCE (Proof Key for Code Exchange, RFC 7636) was written to close it.

How PKCE works

PKCE swaps the static client secret for a fresh, one-time proof generated per login. Three steps:

  1. At the start, the client generates a random string — the code_verifier — and keeps it in memory. It then hashes it with SHA-256 to produce the code_challenge, and sends only the challenge when it kicks off the login.
  2. The player signs in. The provider stores the challenge alongside the authorization code it issues.
  3. At the token exchange, the client sends the original code_verifier. The provider hashes it and checks the result matches the challenge it stored. Match means the same app that started the flow is finishing it. No match means reject.

The elegance is that the code_challenge travels over the visible front channel, but the code_verifier does not — it's only revealed at the final exchange. An attacker who intercepts the authorization code still can't redeem it, because they never saw the verifier, and they can't derive it from the hash. The stolen code is worthless.

This is why PKCE, not a shipped secret, is the correct protection for a public client — a point that follows directly from how OAuth 2.0 works.

PKCE in a Unity game

Two ways this shows up in practice.

If your game runs the OAuth flow itself, you implement PKCE: generate a verifier, hash it, send the challenge, hold the verifier until the exchange. It's not a huge amount of code, but you're now managing per-login crypto state across a browser round-trip and a deep link — plus handling every provider's differences on top.

If Oathwall runs the flow, the authorization code exchange happens on Oathwall's servers, where both the client secret and the PKCE handling live. Your game opens the hosted login and gets the result back. You don't generate verifiers or compute challenges — the confidential exchange is done for you.

using PixitGames.SSOLoginKit;

public class LoginManager : SsoClientBase
{
    // The code exchange (and its protections) happen
    // server-side. The game just starts the login.
    public void OnLoginButton() => StartLogin("google");

    protected override void OnLoginSuccess(LoginResult user)
    {
        Debug.Log($"Signed in as {user.name}");
    }
}

Either way, the takeaway is the same: a game should never lean on a client secret baked into the build, and it should never redeem an authorization code without proof that it started the flow. PKCE is how that proof works.

For what happens after login — the tokens you get and how the session stays alive — read access vs. refresh tokens. To see the full flow in a real integration, the Unity authentication guide ties it together.

Oathwall is available on the Unity Asset Store.

Frequently asked questions

What does PKCE stand for?
Proof Key for Code Exchange, defined in RFC 7636 and usually pronounced 'pixy.' It's an extension to OAuth 2.0's authorization code flow that lets a client prove the token request came from the same app that started the login, without relying on a client secret.
Why do games need PKCE?
A game is a public client — it runs on the player's device and can't safely hold a client secret. PKCE replaces the secret with a one-time proof generated fresh for each login, so an intercepted authorization code is useless to an attacker who doesn't hold the matching verifier.
What are the code_verifier and code_challenge?
The code_verifier is a random secret the client makes at the start of a login. The code_challenge is its SHA-256 hash, sent when the flow begins. At the token exchange, the client sends the original verifier; the server hashes it and checks it matches the challenge, proving the same app started and finished the flow.
Do I have to implement PKCE myself in Unity?
No. If Oathwall runs the flow, the authorization code exchange happens on Oathwall's servers, where the secret and the PKCE handling live. Your game opens the login and receives the result — you don't generate verifiers or hash challenges yourself.