Table of Contents
RFC 7636 : Proof Key for Code Exchange (PKCE, pronounced “pixy”) is a specification about a countermeasure against the authorization code interception attack.
The specification was released on September, 2015. It has added:
code_challenge
parameter and code_challenge_method
parameter to authorization requests using the authorization code flow, andcode_verifier
parameter to token requests that correspond to the authorization requests.This mechanism enables an authorization server to reject a token request from a malicious application that does not have a code verifier.
An authorization request that uses PKCE goes out with code_challenge
parameter and optionally with code_challenge_method
parameter.
The value of code_challenge parameter is computed by applying a code challenge method (= computation logic) to a code verifier.
A code verifier itself is a random string using characters of [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~"
, with a minimum length of 43 characters and a maximum length of 128 characters.
The defined code challenge methods are plain
and S256
. Respective computation logics to convert a code verifier into a code challenge are as follows.
Method | Logic |
---|---|
plain |
code_challenge = code_verifier |
S256 |
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) |
The plain
method does not change the input, so the value of code_verifier
and the resultant value of code_challenge
are equal.
The S256
method computes the SHA-256 hash of the input and then encodes the hash value using Base64-URL. For example, when the value of code_verifier
is dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk, the value of code_challenge
becomes E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM.
When the used code challenge method is S256
, a client application must tell it by including code_challenge_method=S256
parameter in an authorization request. When code_challenge_method
parameter is omitted, an authorization server assumes plain
as the default value.
After generating an authorization code, an authorization server saves it into its DB with the code challenge and the code challenge method contained in the authorization request.
The authorization server will use the saved code challenge and the code challenge method later to verify a token request from the client application.
A response from the authorization endpoint has nothing special for PKCE. It’s a normal response as usual.
After receiving an authorization code from an authorization server, a client application makes a token request. In addition to the authorization code, the token request must include the code verifier used to compute the code challenge.
The name of the request parameter to specify a code verifier is code_verifier
.
A token endpoint of an authorization server that supports PKCE checks whether a token request contains a valid code verifier.
Of course, this check is performed only when grant_type is authorization_code and the authorization code contained in the token request is associated with a code challenge.
If a token request does not contain a valid code verifier although the conditions above meet, the request is regarded as from a malicious application and the authorization server returns an error response.
Verification is performed by comparing two code challenges.
One is what was contained in the authorization request and is stored in the DB. The other is what an authorization server computes using the code verifier contained in the token request and the code challenge method stored in the DB.
If the two code challenges are equal, the token request can be regarded as from the legitimate client application that has made the original authorization request. Otherwise, the token request must be regarded from a malicious application.
If a token request is verified, an authorization server issues an access token as usual.
If you don’t have an Authlete account yet, you can sign up here for free. It only takes 5 minutes.
To make an authorization request, you will need a Service ID and a Client ID.
If you need a Service ID and a Client ID, follow the Quick Setup Guide to setup your service and client.
Also, you can find the Service and Client ID the Authlete Management Console.
This section explains how to configure your service and client settings.
Table. Service Settings
Tab | Parameter | Value |
---|---|---|
Service Settings > Endpoints > Global Settings | Supported Grant Types | Include AUTHORIZATION_CODE |
Service Settings > Endpoints > Global Settings | Supported Response Types | Include CODE |
Configure Endpoints:
Navigate to Service Settings > Endpoints > Global Settings
Under the Supported Grant Types section, select AUTHORIZATION_CODE
.
Under the Supported Response Types section, select CODE
.
Click Save Changes to apply the updates.
Table. Client Settings
Tab | Parameter | Value |
---|---|---|
Client Settings > Basic Settings > General | Client Type | Select PUBLIC |
Client Settings > Endpoints > Global Settings | Grant Types | Include AUTHORIZATION_CODE |
Client Settings > Endpoints > Global Settings | Response Types | Include CODE |
Client Settings > Endpoints > Global Settings | Redirect URIs | https://api.authlete.com/api/mock/redirection/service-api-key |
Configure Client Basic Settings:
Navigate to Client Settings > Basic Settings > General
For Client Type, choose the PUBLIC
radio button.
Click Save Changes to apply the updates.
Configure Client Endpoints:
Navigate to Client Settings > Endpoints > Global Settings
Under the Supported Grant Types section, select AUTHORIZATION_CODE
.
Under the Supported Response Types section, select CODE
.
Under Redirect URIs, click Add URI. Be sure to adjust the redirect url to match your redirection:
https://us.authlete.com/api/mock/redirection/service-id
Click Save Changes to apply the updates.
Use the following curl
command to make an authorization request to the Authlete API. Be sure to replace $sat
with your actual bearer token along with the service-id and client-id.
# Linux/Mac
curl -v -X POST "https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/authorization" \
-H "Authorization: Bearer $sat" \
-d "ticket=5tqii9i_pUp1iteacZGUtdjikRnqGSrPwW7lqoH1Pcc" \
-d "subject=john.s@example.com" \
-d "response_type=code" \
-d "client_id=<Client ID e.g.26478243745571>" \
-d "redirect_uri=https://client.example.org/cb/example.com" \
-d "code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM" \
-d "code_challenge_method=S256"
# Windows (PowerShell)
curl.exe -v -X POST "https://us.authlete.com/api/933860280/auth/authorization" `
-H "Authorization: Bearer $env:sat" `
-d "ticket=5tqii9i_pUp1iteacZGUtdjikRnqGSrPwW7lqoH1Pcc" `
-d "subject=john.s@example.com" `
-d "response_type=code" `
-d "client_id=<Client ID e.g.26478243745571>" `
-d "redirect_uri=https://client.example.org/cb/example.com" `
-d "code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM" `
-d "code_challenge_method=S256"
Note that the request contains code_challenge
parameter and code_challenge_method
parameter. To implement PKCE, you need include and test these parameters.
You can also configure the code_challenge
and code_challenge_method
parameters in the Authlete Management Console.
A response from an authorization endpoint is returned to a redirection endpoint which a client application has registered in advance. Since the configuration of the redirect URIs of the client application contains one redirect URI, https://client.example.org/cb/example.com
, the response from the authorization endpoint is passed to the redirection endpoint and processed there.
The implementation of the redirection endpoint is provided just to help developers. The implementation displays parameter values it receives. For example, if an authorization response contains an authorization code, the redirection endpoint displays its value as shown below.
If the request is valid, Authlete returns a response like this:
{
"action": "INTERACTION",
"resultCode": "A004001",
"resultMessage": "[A004001] Authlete has successfully issued a ticket to the service (API Key = 933860280) for the authorization request from the client (ID = 2800496004). [response_type=code, openid=false]",
"ticket": "cElOaH9j4mS6AiIGR9oLqHlDn9jpvcNjqSgyRqfcmAE",
"client": {...},
"service": {...},
}
We assume the authorization server makes a redirection response to the user agent, and then the user agent makes the following HTTP GET request to the client.
GET /cb/example.com?code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI HTTP/1.1
Host: client.example.org
To make a token request, execute the following curl
command. Make sure to replace <Service ID>
, <Service Access Token>
, <Client ID>
, <Client Secret>
and <Code>
with your values.
curl -v -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/token \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
-d '{ "parameters": "grant_type=authorization_code&code=Xv_su944auuBgc5mfUnxXayiiQU9Z4-T_Yae_UfExmo&redirect_uri=https%3A%2F%2Fmy-client.example.com%2Fcb1&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", "clientId": "<Client ID e.g. 12898884596863>", "clientSecret": "J_3C7P0nDTP7CwCg_HyPQh7bTQ1696CC8GWot-EjesZmdBiU5Gsidq5Ve3tMaN2x2_VcKV1UE1U3ZdGKRuTs7A" }'
If the authorization code and the code verifier you entered are valid, an access token is returned in the form of JSON like the following.
{
"resultMessage" : "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
"action" : "OK",
"clientIdAliasUsed" : false,
"subject" : "testuser01",
"resultCode" : "A050001",
"refreshTokenExpiresAt" : 1730552811449,
"grantType" : "AUTHORIZATION_CODE",
"accessToken" : "7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY",
"idToken" : "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk",
"responseContent" : "{\"access_token\":\"7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY\",\"refresh_token\":\"T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE\",\"scope\":\"openid\",\"id_token\":\"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk\",\"token_type\":\"Bearer\",\"expires_in\":86400}",
"scopes" : [
"openid"
],
"accessTokenDuration" : 86400,
"type" : "tokenResponse",
"refreshToken" : "T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE",
"accessTokenExpiresAt" : 1730552811449,
"refreshTokenDuration" : 864000,
"clientId" : 12898884596863
}
Congratulations! You have succeeded in getting an access token using the authorization code flow secured by PKCE.
Authlete provides a configuration item for PKCE. PKCE can be enabled in the Service or Client Service. Login the Authlete Management Console, select a service and click the Authorization tab, and you will be able to find a boolean configuration item labeled “Proof Key for Code Exchange (RFC 7636)”.
To enable PKCE in Service Settings:
Navigate to Service Settings > Endpoints > Authorization > General
Under Proof Key for Code Exchange (PKCE), enable the Require PKCE
and Require S256 for Code Challenge Method
options.
Click Save Changes to apply the updates.
To enable PKCE in Client Settings:
Navigate to Client Settings > Endpoints > Authorization > General
Under Proof Key for Code Exchange (PKCE), enable the Require PKCE
and Require S256 for Code Challenge Method
options.
Click Save Changes to apply the updates.
If Proof Key for Code Exchange (PKCE) is enabled
, the code_challenge
request parameter is always required for authorization requests using authorization code flow. The default value is disabled
.
Enable Proof Key for Code Exchange (PKCE)
for better security. It makes the authorization server reject any authorization request using the authorization code flow that is not accompanied with code_challenge
request parameter.