PKCE: What it is and how to use it with OAuth 2.0

If you are working with OAuth and OIDC authorization code flow and want to setup PKCE flow then this article will help you to understand everything about PKCE.
profile
Narendra PareekFirst published: 2020-09-03Last updated: 2025-06-25
pkce

PKCE is an OAuth 2.0 security extension for public clients on mobile devices intended to avoid a malicious programme creeping into the same computer from intercepting the authorisation code. The RFC 7636 introduction discusses the mechanisms of such an attack.

PKCE has a different specification of its own. It allows applications to use the most reliable OAuth 2.0 flows in public or untrusted clients - the Authorization Code flow. In order to efficiently use a dynamically generated password, it achieves this by doing some setup work before the flow and some verification at the end of the flow.

This is important because getting a fixed secret in a public client is not safe.

In this blog, we will see how PKCE is useful in authorization code flow for OAuth and OIDC and how you can use this with your OAuth and OpenID Connect providers.

What is PKCE

Proof Key for Code Exchange as known as PKCE, is a key for preventing malicious attacks and securely performing code authorization flow.

I would say, PKCE is used to provide one more security layer to the authorization code flow in OAuth and OpenID Connect.

PKCE is mainly useful for the client-side application or any web apps that are using the client secret key and used to replace the static secret used in the authorization flow.

This flow basically works with two parameters Code Verifier and Code challenge. Let's see what are these parameters, how we use them, and generate them.

PKCE code verifier and challenge

The code verifier is a cryptographically random string using the characters A-Z, a-z, 0-9, and the punctuation characters -._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long. Once the client has generated the code verifier, it uses that to create the code challenge.

For devices that can perform a SHA256 hash, the code challenge is a BASE64-URL-encoded string of the SHA256 hash of the code verifier.

Generate code verifier and code challenge

Here you can see the examples to generate the Code verifier and code challenge in different languages. Either you can find Node and Go Packages for this but I would recommend you to not depend on any package for such small things.

NodeJs

1var crypto = require("crypto")
2function base64URLEncode(str) {
3return str.toString('base64')
4.replace(/+/g, '-')
5.replace(///g, '_')
6.replace(/=/g, '');
7}
8var verifier = base64URLEncode(crypto.randomBytes(32));
9console.log("code_verifier: ", verifier)
10if(verifier){
11var challenge = base64URLEncode(sha256(verifier));
12console.log("code_challenge: ",challenge)
13}
14function sha256(buffer) {
15return crypto.createHash('sha256').update(buffer).digest();
16}

Golang

1package main
2import (
3"crypto/sha256"
4"encoding/base64"
5"fmt"
6"math/rand"
7"strings"
8"time"
9)
10type CodeVerifier struct {
11Value string
12}
13const (
14length = 32
15)
16func base64URLEncode(str []byte) string {
17encoded := base64.StdEncoding.EncodeToString(str)
18encoded = strings.Replace(encoded, "+", "-", -1)
19encoded = strings.Replace(encoded, "/", "_", -1)
20encoded = strings.Replace(encoded, "=", "", -1)
21return encoded
22}
23func verifier() (*CodeVerifier, error) {
24r := rand.New(rand.NewSource(time.Now().UnixNano()))
25b := make([]byte, length, length)
26for i := 0; i < length; i++ {
27b[i] = byte(r.Intn(255))
28}
29return CreateCodeVerifierFromBytes(b)
30}
31func CreateCodeVerifierFromBytes(b []byte) (*CodeVerifier, error) {
32return &CodeVerifier{
33Value: base64URLEncode(b),
34}, nil
35}
36func (v *CodeVerifier) CodeChallengeS256() string {
37h := sha256.New()
38h.Write([]byte(v.Value))
39return base64URLEncode(h.Sum(nil))
40}
41func main() {
42verifier, _ := verifier()
43fmt.Println("code_verifier: ", verifier.Value)
44challenge := verifier.CodeChallengeS256()
45fmt.Println("code_challenge :", challenge)
46}

Implement the OAuth 2.0 Authorization Code with PKCE Flow

Get the Authorization code

In the OAuth Authorization flow, we need to have the code verifier and code challenge to start with the authentication and obviously an OAuth provider to connect.

For the initial request, we need to pass the code_challenge and code_challenge_method to the OAuth or OIDC provider that supports PKCE based flow.

The request will look like:

1Provider + /oauth/redirect?
2client_id={client_id}
3&redirect_uri={Callback URL}
4&scope={Scope}
5&response_type=code
6&state={random long string}
7&code_challenge={code challenge}
8&code_challenge_method=SHA256

The provider should redirect you to the authentication/login page and where you’ll get the code after successful authentication.

Code Exchange

In the code exchange request, we need to pass the code we have received through the above request and the code verifier that we have generated in our first step.

1POST Provider + /oauth/access_token
2Request body:
3{
4client_id:{client_id},
5client_secret:{client_secret},
6redirect_uri:{redirect_uri},
7response_type:token,
8Code:{code} // That we have received in authorization request
9code_verifier: {code verifier // generated in the first step
10}

Once the code_verificer hash matches with the code_challenge of the authorization request, You will get the token in the response with status code 200 OK.

1{
2    "access_token": "c5a****b-****-4*7f-a********e4a",
3    "token_type": "access_token",
4    "refresh_token": "5*****82-b***-**82-8c*1-*******7ce",
5    "expires_in": 11972
6}

That's it and you've implemented PKCE flow in your application.

Share On:
Share on TwitterShare on LinkedIn