When using the
authorization_code grant type with a
public client type, you will be required to implement an OAuth2 extension known as PKCE (Public Key for Code Exchange). This is because public clients leak their
client_secret, which means the standard
authorization_code flow is not suitable for reasons explained quite well in this medium post.
It's possible for public clients to use the implicit flow instead, and indeed you should if you can, however the implicit flow has trade offs such as returning no refresh tokens, which in practice means users must go through the oauth authorization dance every time a token expires. This is unaccaptable for many applications, so a solution was proposed as an extension to the OAuth2 spec. That solution was PKCE.
Implementing a PKCE
authorization_code flow is very similar to the regular
authorization_code flow, so we won't document it in its entirety. Instead we'll focus on the parts that differ, so you will also need to refer to the authorization_code documentation.
An example implementation in Python can be found on github.
The first thing we need to do is to generate something called a
code_verifier must be generated for each authorization attempt.
code_verifier should be a cryptographic random string made up of the characters
~ between 43 and 128 characters in length.
code_verifier, we now need to generate a value we call the
code_challenge. This must be done in a specific way for the handshake to work, otherwise the authorization server can not verify the authenticity of the
code_verifier and your requests will be rejected.
To generate a
code_challenge, we have to first generate a SHA256 hash of our
code_verifier, and then we base64 encode that hash in a url-safe manner. A url safe base64 encoding is one that replaces
A good way to check you're generating the
code_challenge correctly is to verify that your output matches the below when given the same input (
verifier in this case):
$ python -c 'from __future__ import print_function; import hashlib; import base64; print(base64.urlsafe_b64encode(hashlib.sha256("verifier".encode("utf8")).hexdigest().encode("utf8")))' ODhjOWVhZTY4ZWIzMDBiMjk3MWEyYmVjOWU1YTI2ZmY0MTc5ZmQ2NjFkNmI3ZDg2MWU0YzY1NTdiOWFhZWUxNA==
code_challengealong with the authorization request
When redirecting the user to Marvel in order to ask for authorization (step 1), we'll need to send along two extra parameters.
The first is the
code_challenge value we generated earlier. The second is
code_challenge_method, which will always have a value of
The full url should look something similar to this:
https://marvelapp.com/oauth/authorize? state=<random_string>& client_id=<client_id>& response_type=code& redirect_uri=<redirect_uri>& scope=<space-separated scopes>& code_challenge=<code_challenge>& code_challenge_method=S256
code_verifieralong with the token request
After the user is redirected back to your application in step 2, we'll need to use the same
code_verifier we generated the
code_challenge from earlier and include that when swapping our auth code for an access token in step 3.
The server will verify that the
code_verifier is the correct counterpart for the
code_challenge supplied at the authorization step.
The full list of parameters needed for the token request are below:
If all went well you should now be the proud owner of an access token. Yay!