public override async Task <IActionResult> Handle(HandlerContext context, CancellationToken cancellationToken)
        {
            try
            {
                _authorizationCodeGrantTypeValidator.Validate(context);
                var oauthClient = await AuthenticateClient(context, cancellationToken);

                context.SetClient(oauthClient);
                var code            = context.Request.Data.GetAuthorizationCode();
                var previousRequest = await _grantedTokenHelper.GetAuthorizationCode(code, cancellationToken);

                if (previousRequest == null)
                {
                    // https://tools.ietf.org/html/rfc6749#section-4.1.2
                    var searchResult = await _grantedTokenHelper.SearchTokens(new SearchTokenParameter
                    {
                        AuthorizationCode = code
                    }, cancellationToken);

                    if (searchResult.Content.Any())
                    {
                        await _grantedTokenHelper.RemoveTokens(searchResult.Content, cancellationToken);

                        _logger.LogError($"authorization code '{code}' has already been used, all tokens previously issued have been revoked");
                        return(BuildError(HttpStatusCode.BadRequest, ErrorCodes.INVALID_GRANT, ErrorMessages.AUTHORIZATION_CODE_ALREADY_USED));
                    }

                    return(BuildError(HttpStatusCode.BadRequest, ErrorCodes.INVALID_GRANT, ErrorMessages.BAD_AUTHORIZATION_CODE));
                }

                var previousClientId = previousRequest.GetClientId();
                if (!previousClientId.Equals(oauthClient.ClientId, StringComparison.InvariantCultureIgnoreCase))
                {
                    return(BuildError(HttpStatusCode.BadRequest, ErrorCodes.INVALID_REQUEST, ErrorMessages.REFRESH_TOKEN_NOT_ISSUED_BY_CLIENT));
                }

                await _grantedTokenHelper.RemoveAuthorizationCode(code, cancellationToken);

                var scopes = previousRequest.GetScopesFromAuthorizationRequest();
                var result = BuildResult(context, scopes);
                foreach (var tokenBuilder in _tokenBuilders)
                {
                    await tokenBuilder.Refresh(previousRequest, context, cancellationToken);
                }

                _tokenProfiles.First(t => t.Profile == context.Client.PreferredTokenProfile).Enrich(context);
                foreach (var kvp in context.Response.Parameters)
                {
                    result.Add(kvp.Key, kvp.Value);
                }

                return(new OkObjectResult(result));
            }
            catch (OAuthException ex)
            {
                return(BuildError(HttpStatusCode.BadRequest, ex.Code, ex.Message));
            }
        }
        public override async Task <IActionResult> Handle(HandlerContext context)
        {
            try
            {
                _authorizationCodeGrantTypeValidator.Validate(context);
                var oauthClient = await AuthenticateClient(context);

                context.SetClient(oauthClient);
                var code            = context.Request.Data.GetAuthorizationCode();
                var previousRequest = _grantedTokenHelper.GetAuthorizationCode(code);
                if (previousRequest == null)
                {
                    return(BuildError(HttpStatusCode.BadRequest, ErrorCodes.INVALID_REQUEST, ErrorMessages.BAD_AUTHORIZATION_CODE));
                }

                var previousClientId = previousRequest.GetClientId();
                if (!previousClientId.Equals(oauthClient.ClientId, StringComparison.InvariantCultureIgnoreCase))
                {
                    return(BuildError(HttpStatusCode.BadRequest, ErrorCodes.INVALID_REQUEST, ErrorMessages.REFRESH_TOKEN_NOT_ISSUED_BY_CLIENT));
                }

                _grantedTokenHelper.RemoveAuthorizationCode(code);
                var scopes = previousRequest.GetScopesFromAuthorizationRequest();
                var result = BuildResult(context, scopes);
                foreach (var tokenBuilder in _tokenBuilders)
                {
                    await tokenBuilder.Refresh(previousRequest, context).ConfigureAwait(false);
                }

                _tokenProfiles.First(t => t.Profile == context.Client.PreferredTokenProfile).Enrich(context);
                foreach (var kvp in context.Response.Parameters)
                {
                    result.Add(kvp.Key, kvp.Value);
                }

                return(new OkObjectResult(result));
            }
            catch (OAuthException ex)
            {
                return(BuildError(HttpStatusCode.BadRequest, ex.Code, ex.Message));
            }
        }