/// <summary>
        /// Given a <see cref="RefreshTokenRequest"/>, it will retrieve a refreshed access token from the authorization server.
        /// </summary>
        /// <param name="request">The refresh token request details, containing a valid refresh token.</param>
        /// <returns>The new token issued by the server.</returns>
        public async Task <AccessTokenResponse> GetTokenAsync(RefreshTokenRequest request)
        {
            var parameters = new Dictionary <string, object> {
                { "grant_type", "refresh_token" },
                { "refresh_token", request.RefreshToken },
                { "client_id", request.ClientId },
                { "client_secret", request.ClientSecret }
            };

            if (!string.IsNullOrEmpty(request.Audience))
            {
                parameters.Add("audience", request.Audience);
            }

            if (!string.IsNullOrEmpty(request.Scope))
            {
                parameters.Add("scope", request.Scope);
            }
            var response = await Connection.PostAsync <AccessTokenResponse>("oauth/token", null, parameters, null, null, null, null).ConfigureAwait(false);

            IdentityTokenValidator validator = new IdentityTokenValidator();
            await validator.ValidateAsync(response.IdToken, _baseUri.AbsoluteUri, request.ClientId);

            return(response);
        }
        /// <summary>
        /// Given an <see cref="ResourceOwnerTokenRequest" />, it will do the authentication on the provider and return an <see cref="AccessTokenResponse"/>.
        /// </summary>
        /// <param name="request">The authentication request details containing information regarding the username, password etc.</param>
        /// <returns>An <see cref="AccessTokenResponse" /> with the response.</returns>
        /// <remarks>
        /// The grant_type parameter required by the /oauth/token endpoint will automatically be inferred from the <paramref name="request"/> parameter. If no Realm was specified,
        /// then the grant_type will be set to "password". If a Realm was specified, then the grant_type will be set to "http://auth0.com/oauth/grant-type/password-realm"
        /// </remarks>
        public async Task <AccessTokenResponse> GetTokenAsync(ResourceOwnerTokenRequest request)
        {
            var parameters = new Dictionary <string, object>
            {
                { "client_id", request.ClientId },
                { "username", request.Username },
                { "password", request.Password },
                { "scope", request.Scope }
            };

            if (!string.IsNullOrEmpty(request.ClientSecret))
            {
                parameters.Add("client_secret", request.ClientSecret);
            }

            if (!string.IsNullOrEmpty(request.Audience))
            {
                parameters.Add("audience", request.Audience);
            }

            if (string.IsNullOrEmpty(request.Realm))
            {
                parameters.Add("grant_type", "password");
            }
            else
            {
                parameters.Add("grant_type", "http://auth0.com/oauth/grant-type/password-realm");
                parameters.Add("realm", request.Realm);
            }

            var headers = new Dictionary <string, object>();

            if (!string.IsNullOrEmpty(request.ForwardedForIp))
            {
                headers.Add("auth0-forwarded-for", request.ForwardedForIp);
            }

            var response = await Connection.PostAsync <AccessTokenResponse>("oauth/token", null, parameters, null, null, headers, null).ConfigureAwait(false);

            IdentityTokenValidator validator = new IdentityTokenValidator();
            await validator.ValidateAsync(response.IdToken, _baseUri.AbsoluteUri, request.ClientId);

            return(response);
        }
        /// <summary>
        /// Request an Access Token using the Authorization Code (PKCE) flow.
        /// </summary>
        /// <param name="request">The <see cref="AuthorizationCodePkceTokenRequest"/> containing the information of the request.</param>
        /// <returns>An <see cref="AccessTokenResponse"/> containing the token information</returns>
        public async Task <AccessTokenResponse> GetTokenAsync(AuthorizationCodePkceTokenRequest request)
        {
            var response = await Connection.PostAsync <AccessTokenResponse>("oauth/token", null, new Dictionary <string, object>
            {
                { "grant_type", "authorization_code" },
                { "client_id", request.ClientId },
                { "code", request.Code },
                { "code_verifier", request.CodeVerifier },
                { "redirect_uri", request.RedirectUri }
            },
                                                                            null,
                                                                            null,
                                                                            null,
                                                                            null).ConfigureAwait(false);

            IdentityTokenValidator validator = new IdentityTokenValidator();
            await validator.ValidateAsync(response.IdToken, _baseUri.AbsoluteUri, request.ClientId);

            return(response);
        }