    def save_authorization_code(self, client_id, code, request, *args, **kwargs):
        """Persist the authorization_code.
        The code should at minimum be stored with:
            - the client_id (client_id)
            - the redirect URI used (request.redirect_uri)
            - a resource owner / user (request.user)
            - the authorized scopes (request.scopes)
            - the client state, if given (code.get('state'))
        The 'code' argument is actually a dictionary, containing at least a
        'code' key with the actual authorization code:
            {'code': 'sdf345jsdf0934f'}
        It may also have a 'state' key containing a nonce for the client, if it
        chose to send one.  That value should be saved and used in
        'validate_code'.
        It may also have a 'claims' parameter which, when present, will be a dict
        deserialized from JSON as described at
        http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
        This value should be saved in this method and used again in 'validate_code'.
        :param client_id: Unicode client identifier
        :param code: A dict of the authorization code grant and, optionally, state.
        :param request: The HTTP Request (oauthlib.common.Request)
        Method is used by:
            - Authorization Code Grant
        """
        log_code = code.get('code', 'undefined')[:3] + '...'
        app_log.debug(
            "Saving authorization code %s, %s, %s, %s",
            client_id,
            log_code,
            args,
            kwargs,
        )
        orm_client = (
            self.db.query(orm.OAuthClient).filter_by(identifier=client_id).first()
        )
        if orm_client is None:
            raise ValueError(f"No such client: {client_id}")

        orm_code = orm.OAuthCode(
            code=code['code'],
            # oauth has 5 minutes to complete
            expires_at=int(orm.OAuthCode.now() + 300),
            scopes=list(request.scopes),
            redirect_uri=orm_client.redirect_uri,
            session_id=request.session_id,
        )
        self.db.add(orm_code)
        orm_code.client = orm_client
        orm_code.user = request.user.orm_user
        self.db.commit()
Persist the authorization_code.
The code should at minimum be stored with:
- the client_id (client_id)
- the redirect URI used (request.redirect_uri)
- a resource owner / user (request.user)
- the authorized scopes (request.scopes)
- the client state, if given (code.get('state'))
The 'code' argument is actually a dictionary, containing at least a
'code' key with the actual authorization code:
{'code': 'sdf345jsdf0934f'}
It may also have a 'state' key containing a nonce for the client, if it
chose to send one.  That value should be saved and used in
'validate_code'.
It may also have a 'claims' parameter which, when present, will be a dict
deserialized from JSON as described at
http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
This value should be saved in this method and used again in 'validate_code'.
:param client_id: Unicode client identifier
:param code: A dict of the authorization code grant and, optionally, state.
:param request: The HTTP Request (oauthlib.common.Request)
Method is used by:
- Authorization Code Grant
jupyterhub/oauth/provider.py