# 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:

1. code_challenge: A VARCHAR

2. 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.payload.data.get('code_challenge')
            code_challenge_method = request.payload.data.get('code_challenge_method')
            auth_code = AuthorizationCode(
                code=code,
                client_id=request.client.client_id,
                redirect_uri=request.redirect_uri,
                scope=request.payload.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 from public clients. 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)

## 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_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_authorization_code_challenge(authorization_code)

    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_authorization_code_challenge_method(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