/// <summary>
 /// Token request for refresh
 /// </summary>
 public OAuthTokenRequest(TokenClaimsPrincipal current, String scope)
 {
     this.GrantType    = "refresh_token";
     this.RefreshToken = current.RefreshToken;
     this.Scope        = scope;
 }
        /// <summary>
        /// Authenticate the user
        /// </summary>
        /// <param name="principal">Principal.</param>
        /// <param name="password">Password.</param>
        public System.Security.Principal.IPrincipal Authenticate(System.Security.Principal.IPrincipal principal, string password, String tfaSecret)
        {
            AuthenticatingEventArgs e = new AuthenticatingEventArgs(principal.Identity.Name);

            this.Authenticating?.Invoke(this, e);
            if (e.Cancel)
            {
                this.m_tracer.TraceWarning("Pre-Event ordered cancel of auth {0}", principal);
                return(null);
            }

            // Get the scope being requested
            String scope = "*";

            // Authenticate
            IPrincipal retVal = null;

            try
            {
                using (IRestClient restClient = ApplicationContext.Current.GetRestClient(Core.Interop.ServiceEndpointType.AuthenticationService))
                {
                    // Set credentials
                    restClient.Credentials = new OAuthTokenServiceCredentials(principal);

                    // Create grant information
                    OAuthTokenRequest request = null;
                    if (!String.IsNullOrEmpty(password))
                    {
                        request = new OAuthTokenRequest(principal.Identity.Name, password, scope);
                    }
                    else if (principal is TokenClaimsPrincipal)
                    {
                        request = new OAuthTokenRequest(principal as TokenClaimsPrincipal, scope);
                    }
                    else
                    {
                        request = new OAuthTokenRequest(principal.Identity.Name, null, scope);
                    }

                    // Set credentials
                    if (restClient.Description.Binding.Security?.Mode == Core.Http.Description.SecurityScheme.Basic)
                    {
                        restClient.Credentials = new OAuthTokenServiceCredentials(principal);
                    }
                    else
                    {
                        request.ClientId     = ApplicationContext.Current.ApplicationName;
                        request.ClientSecret = ApplicationContext.Current.ApplicationSecret;
                    }

                    try
                    {
                        restClient.Requesting += (o, p) =>
                        {
                            if (!String.IsNullOrEmpty(tfaSecret))
                            {
                                p.AdditionalHeaders.Add("X-SanteDB-TfaSecret", tfaSecret);
                            }
                        };

                        OAuthTokenResponse response = restClient.Post <OAuthTokenRequest, OAuthTokenResponse>("oauth2_token", "application/x-www-form-urlencoded", request);
                        retVal = new TokenClaimsPrincipal(response.AccessToken, response.IdToken, response.TokenType, response.RefreshToken);
                        this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(principal.Identity.Name, retVal, true));
                    }
                    catch (RestClientException <OAuthTokenResponse> ex)
                    {
                        this.m_tracer.TraceWarning("OAUTH Server Responded: {0}", ex.Result.ErrorDescription);
                    }
                    catch (WebException ex) // Raw level web exception
                    {
                        this.m_tracer.TraceError("Error authenticating: {0}", ex.Message);
                    }
                    catch (SecurityException ex)
                    {
                        this.m_tracer.TraceError("Server was contacted however the token is invalid: {0}", ex.Message);
                        throw;
                    }
                    catch (Exception ex) // fallback to local
                    {
                        this.m_tracer.TraceError("General Authentication Error: {0}", ex.Message);
                    }
                }
            }
            catch
            {
                this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(principal.Identity.Name, retVal, false));
                throw;
            }

            return(retVal);
        }