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.
New in version v0.10.
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 create_authorization_code
method:
class MyAuthorizationCodeGrant(AuthorizationCodeGrant):
def create_authorization_code(self, client, grant_user, request):
code = generate_token(48)
# NOTICE BELOW
code_challenge = request.data.get('code_challenge')
code_challenge_method = request.data.get('code_challenge_method')
item = AuthorizationCode(
code=code,
client_id=client.client_id,
redirect_uri=request.redirect_uri,
scope=request.scope,
user_id=grant_user.get_user_id(),
code_challenge=code_challenge,
code_challenge_method=code_challenge_method,
)
db.session.add(item)
db.session.commit()
return 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-a-urlsafe-string'
>>> code_challenge = create_s256_code_challenge(code_verifier)
>>> uri, state = session.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 create_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 |
|---|