/// <summary>
        /// Get user information from the OP after user authentication
        /// </summary>
        /// <param name="url">The url to be used to retrieve user information</param>
        /// <param name="userInfoRequestMessage">The user info request message</param>
        /// <param name="accessToken">The access token obtain during authentication</param>
        /// <returns>The response message containing user information</returns>
        public OIDCUserInfoResponseMessage GetUserInfo(string url, OIDCUserInfoRequestMessage userInfoRequestMessage, string accessToken, string idTokenSub = null, bool bearer = true, string ClientSecret = null, List<OIDCKey> RPKeys = null)
        {
            WebRequest request;
            if (bearer)
            {
                request = WebRequest.Create(url);
                request.Headers.Add("Authorization", "Bearer " + accessToken);
            }
            else
            {
                request = WebRequest.Create(url + "?access_token=" + accessToken);
            }
            string returnedString = WebOperations.PostUrlContent(request, userInfoRequestMessage);
            string jsonToken = userInfoRequestMessage.CheckSignatureAndDecryptJWT(returnedString, null, ClientSecret, RPKeys);
            Dictionary<string, object> returnedJson = Deserializer.DeserializeFromJson<Dictionary<string, object>>(jsonToken);

            if (returnedJson.Keys.Contains("error"))
            {
                OIDCResponseError error = new OIDCResponseError();
                error.DeserializeFromDictionary(returnedJson);
                throw new OIDCException("Error while asking for user info: " + error.Error + "\n" + error.ErrorDescription);
            }

            OIDCUserInfoResponseMessage userInfoResponse = new OIDCUserInfoResponseMessage();
            userInfoResponse.DeserializeFromDictionary(returnedJson);

            if (idTokenSub != null && userInfoResponse.Sub != idTokenSub)
            {
                throw new OIDCException("Wrong sub in UserInfo, it does not match idToken's.");
            }

            return userInfoResponse;
        }
        /// <summary>
        /// Method that performs a dynamic client registration with the OP server.
        /// </summary>
        /// <param name="RegistrationEndpoint">The URL of the OP describing the registration endpoint.</param>
        /// <param name="clientMetadata">The OIDCClientInformation object describing the client information to
        /// be submitted to the OP for registration.</param>
        /// <param name="TokenEndpointAuthMethod">(optional) the endpoint authentication method used to
        /// authenticate the client with the OP sever (if not specified using "client_secret_basic".</param>
        /// <returns>An oject describing all client information as returned by the OP server after
        /// registration.</returns>
        /// <exception cref="OpenIDClient.OIDCException">Thrown when an error occurs while registering
        /// the client with the OP.</exception>
        public OIDCClientInformation RegisterClient(string RegistrationEndpoint, OIDCClientInformation clientMetadata, string TokenEndpointAuthMethod = "client_secret_basic")
        {
            // Make registration request
            Dictionary<string, object> data = clientMetadata.SerializeToDictionary();
            OIDCClientRegistrationRequest registrationRequest = new OIDCClientRegistrationRequest();
            registrationRequest.DeserializeFromDictionary(data);

            // Check error and store client information from OP
            WebRequest request = WebRequest.Create(RegistrationEndpoint);
            string returnedString = WebOperations.PostUrlContent(request, registrationRequest, true);
            Dictionary<string, object> returnedJson = Deserializer.DeserializeFromJson<Dictionary<string, object>>(returnedString);
            if (returnedJson.Keys.Contains("error"))
            {
                OIDCResponseError error = new OIDCResponseError();
                throw new OIDCException("Error while registering client: " + error.Error + "\n" + error.ErrorDescription);
            }

            OIDCClientInformation clientInformation = new OIDCClientInformation();
            clientInformation.DeserializeFromDictionary(returnedJson);
            return clientInformation;
        }
        /// <summary>
        /// Method that submits a tokn request to the OP.
        /// </summary>
        /// <param name="url">The URL to be used where to send the request</param>
        /// <param name="tokenRequestMessage">The token request message</param>
        /// <param name="clientInformation">The client information obtained from the OP</param>
        /// <returns>Returns the token response obtained from the OP</returns>
        public OIDCTokenResponseMessage SubmitTokenRequest(string url, OIDCTokenRequestMessage tokenRequestMessage, OIDCClientInformation clientInformation, byte[] privateKey = null)
        {
            WebRequest request = WebRequest.Create(url);
            OIDCAuthenticatedMessage message = tokenRequestMessage as OIDCAuthenticatedMessage;
            string grantType = clientInformation.TokenEndpointAuthMethod;
            AddClientAuthenticatedToRequest(ref request, ref message, grantType, clientInformation, privateKey);
            string returnedString = WebOperations.PostUrlContent(request, message);
            Dictionary<string, object> returnedJson = Deserializer.DeserializeFromJson<Dictionary<string, object>>(returnedString);

            if (returnedJson.Keys.Contains("error"))
            {
                OIDCResponseError error = new OIDCResponseError();
                error.DeserializeFromDictionary(returnedJson);
                throw new OIDCException("Error while registering client: " + error.Error + "\n" + error.ErrorDescription);
            }

            OIDCTokenResponseMessage tokenResponse = new OIDCTokenResponseMessage();
            tokenResponse.DeserializeFromDictionary(returnedJson);
            return tokenResponse;
        }
        /// <summary>
        /// Method called toparse an authentication implicit response from OP.
        /// </summary>
        /// <param name="queryString">The string reprsenting the authentication response provided
        /// by the OP.</param>
        /// <param name="scope">(optional) Eventual scope used for the call to be used for verification.</param>
        /// <param name="state">(optional) Eventual state used for the call to be used for verification.</param>
        /// <returns>A validated message containing answer frop OP.</returns>
        public OIDCAuthImplicitResponseMessage ParseAuthImplicitResponse(string queryString, List<MessageScope> scope = null, string state = null)
        {
            OIDCAuthImplicitResponseMessage responseMessage = new OIDCAuthImplicitResponseMessage();
            try
            {
                responseMessage.DeserializeFromQueryString(queryString);
            }
            catch (OIDCException)
            {
                OIDCResponseError error = new OIDCResponseError();
                error.DeserializeFromQueryString(queryString);
                throw new OIDCException("Error while parsing authorization response: " + error.Error + "\n" + error.ErrorDescription);
            }

            if (state != null && responseMessage.State != state)
            {
                throw new OIDCException("Error with authentication answer, wrong state.");
            }

            return responseMessage;
        }