When the native app begins the authorization request, instead of immediately launching a browser, the client first creates what is known as a “code verifier“. This is a cryptographically random string using the characters
0-9, and the punctuation characters
-._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long.
Once the app 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. Clients that do not have the ability to perform a SHA256 hash are permitted to use the plain code verifier string as the challenge.
Now that the client has a code challenge string, it includes that and a parameter that indicates which method was used to generate the challenge (plain or S256) along with the standard parameters of the authorization request. This means a complete authorization request will include the following parameters.
- response_type=code – indicates that your server expects to receive an authorization code
- client_id= – The client ID you received when you first created the application
- redirect_uri= – Indicates the URL to return the user to after authorization is complete, such as org.example.app://redirect
- state=1234zyx – A random string generated by your application, which you’ll verify later
- code_challenge=XXXXXXXXX – The code challenge generated as previously described
- code_challenge_method=S256 – either
S256, depending on whether the challenge is the plain verifier string or the SHA256 hash of the string. If this parameter is omitted, the server will assume
The authorization server should recognize the
code_challenge parameter in the request, and associate that with the authorization code it generates. Either store this in the database along with the authorization code, or if you’re using self-encoded authorization codes then it can be included in the code itself. (See The Authorization Response for details.) The server returns the authorization code as normal, and does not include the challenge in the data returned.
The authorization server can require that public clients must use the PKCE extension. This is really the only way to allow public clients to have a secure authorization flow without using the client secret. Since the authorization server should know that a specific client ID corresponds to a public client, it can deny authorization requests for public clients that do not contain a code challenge.
If the authorization server requires public clients to use PKCE, and the authorization request is missing the code challenge, then the server should return the error response with
error=invalid_request and the
error_uri should explain the nature of the error.