2 minute read
How do I implement a PKCE client with Authproject?
PKCE, or Proof Key for Code Exchange, is an extension to OAuth2’s authorization code flow to enable “public” clients to exchange their credentials for tokens, while maintaining the security of the system. Postman has an excellent set of docs explaining what PKCE is, and how it works.
In order for PKCE to work, there are a couple small requirements. The first is that your client must be set to be a “public” client (NOTE: this is not the default for new OAuth clients created in Authproject). The second is that your client must not have a client secret. This is handled automatically by us - if you request a public client, a client secret will not be generated.
In order to demonstrate how to use PKCE with Authproject, we have a sample Python program that will perform a request on behalf of the user, exchange the received authorization code for a token, and display that token.
import base64
import webbrowser
import secrets
import hashlib
from requests_oauthlib import OAuth2Session
# Client ID, provided by Authproject
client_id = "<your-client-id>"
# Base URL for authorization
authorization_base_url = "https://<your-auth-domain>/oauth2/authorize"
# Token URL for exchanging authorization code for access token
token_url = "https://<your-auth-domain>/oauth2/token"
# Redirect URI registered with the OAuth2 provider
redirect_uri = "https://localhost:9000/callback"
# OAuth2 scope (optional, depends on your server)
scope = ["openid", "profile", "email"]
def generate_pkce_pair():
# Generate a high-entropy code verifier
code_verifier = (
base64.urlsafe_b64encode(secrets.token_bytes(64)).rstrip(b"=").decode("utf-8")
)
# Create code challenge
code_challenge = (
base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode("utf-8")).digest())
.rstrip(b"=")
.decode("utf-8")
)
return code_verifier, code_challenge
def main():
code_verifier, code_challenge = generate_pkce_pair()
# Create an OAuth2 session
oauth = OAuth2Session(
client_id,
redirect_uri=redirect_uri,
scope=scope,
)
# Get authorization URL and state
authorization_url, state = oauth.authorization_url(
authorization_base_url,
code_challenge=code_challenge,
code_challenge_method="S256",
)
print("Open this URL in a browser and authorize:", authorization_url)
webbrowser.open(authorization_url)
# Get the authorization response from the user
redirect_response = input("Paste the full redirect URL here: ").strip()
# Fetch the access token
token = oauth.fetch_token(
token_url,
authorization_response=redirect_response,
include_client_id=True,
code_verifier=code_verifier,
)
print("\nAccess token:", token)
if __name__ == "__main__":
main()
When setting up PKCE with your client, there are some simple steps to follow:
code_challenge
and code_challenge_method
in the requestcode_verifier
in the
request