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.
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.
The new database SHOULD contain two more columns:
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.
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:
code_challenge
and code_challenge_method
in .create_authorization_url
.code_verifier
in .fetch_token
.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_challenge
and
code_challenge_method
into database when save_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 |
---|