RFC7636: Proof Key for Code Exchange by OAuth Public Clients¶
This RFC7636 is used to improve the security of Authorization Code flow for public clients by sending extra “code_challenge” and “code_verifier” to the authorization server.
Using RFC7636 in Authorization Code Grant¶
In order to apply proof key for code exchange, you need to register the
CodeChallenge extension to AuthorizationCodeGrant. But before
that, we need to re-design our AuthorizationCode database.
For Flask Developers, check the section Authorization Code Grant.
For Django Developers, check the section Authorization Code Grant.
The new database SHOULD contain two more columns:
code_challenge: A VARCHAR
code_challenge_method: A VARCHAR
And the AuthorizationCodeGrant should record the code_challenge and
code_challenge_method into database in save_authorization_code
method:
class MyAuthorizationCodeGrant(AuthorizationCodeGrant):
# YOU MAY NEED TO ADD "none" METHOD FOR AUTHORIZATION WITHOUT CLIENT SECRET
TOKEN_ENDPOINT_AUTH_METHODS = ['client_secret_basic', 'client_secret_post', 'none']
def save_authorization_code(self, code, request):
# NOTICE BELOW
code_challenge = request.data.get('code_challenge')
code_challenge_method = request.data.get('code_challenge_method')
auth_code = AuthorizationCode(
code=code,
client_id=request.client.client_id,
redirect_uri=request.redirect_uri,
scope=request.scope,
user_id=request.user.id,
code_challenge=code_challenge,
code_challenge_method=code_challenge_method,
)
auth_code.save()
return auth_code
Now you can register your AuthorizationCodeGrant with the extension:
from authlib.oauth2.rfc7636 import CodeChallenge
server.register_grant(MyAuthorizationCodeGrant, [CodeChallenge(required=True)])
If required=True, code challenge is required for authorization code flow.
If required=False, it is optional, it will only valid the code challenge
when clients send these parameters.
Using code_challenge in Client¶
Read the Code Challenge section in the Web OAuth Clients.
It is also possible to add code_challenge in OAuth2Session,
consider that we already have a session:
>>> from authlib.oauth2.rfc7636 import create_s256_code_challenge
>>> code_verifier = generate_token(48)
>>> code_challenge = create_s256_code_challenge(code_verifier)
>>> uri, state = session.create_authorization_url(authorize_url, code_challenge=code_challenge, code_challenge_method='S256')
>>> # visit uri, get the response
>>> authorization_response = 'https://example.com/auth?code=42..e9&state=d..t'
>>> token = session.fetch_token(token_endpoint, authorization_response=authorization_response, code_verifier=code_verifier)
The authorization flow is the same as in OAuth 2 Session, what you need to do is:
adding
code_challengeandcode_challenge_methodin.create_authorization_url.adding
code_verifierin.fetch_token.
API Reference¶
-
class
authlib.oauth2.rfc7636.CodeChallenge(required=True)¶ CodeChallenge extension to Authorization Code Grant. It is used to improve the security of Authorization Code flow for public clients by sending extra “code_challenge” and “code_verifier” to the authorization server.
The AuthorizationCodeGrant SHOULD save the
code_challengeandcode_challenge_methodinto database whensave_authorization_code. Then register this extension via:server.register_grant( AuthorizationCodeGrant, [CodeChallenge(required=True)] )
-
DEFAULT_CODE_CHALLENGE_METHOD= 'plain'¶ defaults to “plain” if not present in the request
-
SUPPORTED_CODE_CHALLENGE_METHOD= ['plain', 'S256']¶ supported
code_challenge_method
Get “code_challenge” associated with this authorization code. Developers MAY re-implement it in subclass, the default logic:
def get_authorization_code_challenge(self, authorization_code): return authorization_code.code_challenge
- Parameters
authorization_code – the instance of authorization_code
Get “code_challenge_method” associated with this authorization code. Developers MAY re-implement it in subclass, the default logic:
def get_authorization_code_challenge_method(self, authorization_code): return authorization_code.code_challenge_method
- Parameters
authorization_code – the instance of authorization_code
-