PKCE in Action with WSO2 Identity Server

Janak Amarasena
Identity Beyond Borders
4 min readSep 13, 2019

Let's see how PKCE works with OAuth 2.0 Authorization Code Grant using the WSO2 Identity Server. By the way, if you're wondering what the heck PKCE is, then you can read all about it from here.

Before getting started you will need to download the WSO2 Identity Server. You can get the latest version of the product from here (you can download the “Binary without updates”).

Startup the server and lets quickly configure an OAuth 2 Service Provider so we can checkout PKCE in action.

1. Log in to the carbon management console.

http://localhost:9443/carbon
username: admin
password: admin

2. On the Main tab, click Service Providers > Add

3. Enter a Service Provider Name and click on Register

4. Click on the Inbound Authentication Configuration dropdown and click on the OAuth/OpenID Connect Configuration dropdown and click Configure.

5. Leave all the default configurations as they are and only add the Callback Url as https://example-app.com/redirect and tick the PKCE Mandatory checkbox. Scroll to the bottom and click the Add button.

6. After the above step(5) is completed you should have the client credentials. Its in Inbound Authentication Configuration > OAuth/OpenID Connect Configuration.

7. Make note of the OAuth Client Key and the OAuth Client Secret. And also the Callback Url you configured(https://example-app.com/redirect).

That’s all we need from the Identity Server, just keep it running.

Let's see PKCE in Action

I won’t be explaining about PKCE here. If you feel a bit lost head-on here and quickly read about PKCE and come back. It's only a 4min read ;)

Okay, let's start the flow. We will be using PKCE with the Authorization Code grant.

Lets first create a PKCE code verifier and a code challenge. Head-on to tonyxu-io.github.io/pkce-generator and first click on Generate Code Verifier and then on Generate Code Challenge. Make note of the two values. The code challenge you get here is the base64 URL encoded value of the SHA256 hashed code_verifier so the code challenge method will be S256.

The authorization request of the Authz Code flow with PKCE looks like below.

https://localhost:9443/oauth2/authorize?response_type=code&client_id=<OAuth_Client_Key>&redirect_uri=<Callback_Url>&state=<Random_String>&code_challenge=<Code_Challenge>&code_challenge_method=<Code_Challenge_Method>

Sample request;

https://localhost:9443/oauth2/authorize?response_type=code&client_id=X_evTCx5txiXfpMLdYGs8zj7eTga&redirect_uri=https://example-app.com/redirect&state=JCyDD4q0VjoHsWdE&code_challenge=EC_Pf7j6_g5oQfkUy99aUcHgF98EjbMSsqnLedAMaYo&code_challenge_method=S256

Go ahead and replace the <OAuth_Client_Key>, <Callback_Url>, <Code_Challenge> with the values you previously got. For <Random_String> you can put some random string like JCyDD4q0VjoHsWdE which is for the state. Like I mentioned previously <Code_Challenge_Method> will be “S256” this is also an optional parameter and if it's not sent “Plain will be the default value (which means for the Authorisation Server your code verifier is the same as the code challenge).

Send the request you created with your values in the browser.

User credentials
username: admin
password: admin

You will be redirected https://example-app.com/redirect and the authz code and the state(the same state you sent) will be displayed. Make note of the authorization code you received. These details will also be available in the browsers’ URL section.

Now let's get an access token. cURL for the token request with PKCE looks like below;

curl -k -X POST https://localhost:9443/oauth2/token -H 'Authorization: Basic <base64encoded(OAuth_Client_Key:OAuth_Client_Secret)>' -H 'Content-Type: application/x-www-form-urlencoded' -d 'grant_type=authorization_code&redirect_uri=<Callback_Url>&code=<Authorization_Code>&code_verifier=<Code_Verifier>'

Sample request;

curl -k -X POST https://localhost:9443/oauth2/token -H 'Authorization: Basic WF9ldlRDeDV0eGlYZnBNTGRZR3M4emo3ZVRnYTpoZnBKamdtTlQxSHVJMVdEU3M5VWFsUDRVYXNh' -H 'Content-Type: application/x-www-form-urlencoded' -d 'grant_type=authorization_code&redirect_uri=https://example-app.com/redirect&code=86d3735e-e744-3864-92e8-665560e6fac4&code_verifier=uy383dWCPy8D5anX9cK42v3fTBCc10CsnvfXrcfENewIFSJvEm1nEczo8C63Mud7QPPkLQ5GVJvzRaxfzVmWi6rqUrPIVhpPQxywRCaxovGzMhDoLjMpZ0ddLRrMrjpY'

Go ahead and replace the <base64encoded(OAuth_Client_Key:OAuth_Client_Secret)> with the base64 encoded “OAuth Client Key” and “OAuth Client Secret” you have, <Callback_Url> is the same as the previous request. <Authorization_Code> is the code you got from the previous request. <Code_Verifier> is the code verifier you obtained.

Execute the cURL command and you should get an access token. The response will look something like this.

{"access_token":"3d893ce9-4f7e-39c3-992e-a660e23fc3da","refresh_token":"d7bd1b6f-e104-3b3d-bb5d-b5015d941f00","token_type":"Bearer","expires_in":3600}

Making a token request without a client secret

When using PKCE you will most probably not use a client secret in that case here is how you can go about doing the token request. (The /authorize endpoint call is same as before.)

Firstly you will need to do a small change in the service provider that you created to allow you to do a token call without the client secret. Go to the relevant service provider’s configuration and go into the Inbound Authentication Configuration dropdown and click on the OAuth/OpenID Connect Configuration and edit it. There you will find a checkbox saying “Allow authentication without the client secret” go ahead and tick it and update the configuration.

Now when doing the token call to the token endpoint you can have the call like below. What’s different here from the previous token request is that we don't use an Authorization header and now we are sending the client_id as a param in the request body.

curl -k -X POST https://localhost:9443/oauth2/token -H 'Content-Type: application/x-www-form-urlencoded' -d 'client_id=<OAuth_Client_Key>&grant_type=authorization_code&redirect_uri=<Callback_Url>&code=<Authorization_Code>&code_verifier=<Code_Verifier>'

Sample request;

curl -k -X POST https://localhost:9443/oauth2/token -H 'Content-Type: application/x-www-form-urlencoded' -d 'client_id=X_evTCx5txiXfpMLdYGs8zj7eTga&grant_type=authorization_code&redirect_uri=https://example-app.com/redirect&code=86d3735e-e744-3864-92e8-665560e6fac4&code_verifier=uy383dWCPy8D5anX9cK42v3fTBCc10CsnvfXrcfENewIFSJvEm1nEczo8C63Mud7QPPkLQ5GVJvzRaxfzVmWi6rqUrPIVhpPQxywRCaxovGzMhDoLjMpZ0ddLRrMrjpY'

Well, that's it :) Go ahead and play around with this, try if you can get an access token with a wrong code_verifier or by not sending the code_verifier at all. Also, check out the flow without sending the code_challenge_method.

--

--