Authorization Request

17.1

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 A-Z, a-z, 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 derive 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, although that provides less security benefits so should really only be used if absolutely necessary.

Base64-URL-encoding is a minor variation on the typical Base64 encoding method. It starts with the same Base64-encoding method available in most programming languages, but uses URL-safe characters instead. You can implement a Base64-URL-encoding method by taking a Base64-encoded string and making the following modifications to the string: Take the Base64-encoded string, and change + to -, and / to _, then trim the trailing = from the end.

PHP

function base64_urlencode($str) {
  return rtrim(strtr(base64_encode($hash), '+/', '-_'), '=');
}

JavaScript

function base64_urlencode(str) {
  return btoa(String.fromCharCode.apply(null, 
    new Uint8Array(str)))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');
}

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 plain or S256, depending on whether the challenge is the plain verifier string or the SHA256 hash of the string.

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.

Error Response

The authorization server can require that public clients must use the PKCE extension. This is really the only way to allow native apps to have a secure authorization flow without using the client secret, especially without the redirect URI security that’s available with web-based clients. 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_description or error_uri should explain the nature of the error.