public async Task <TResult> TokenRedeemedAsync <TResult>(string method, IProvideAuthorization provider,
                                                          string subject, Guid?stateId, Guid?loginId, IDictionary <string, string> extraParamsWithRedemptionParams,
                                                          Func <Guid, Guid, string, string, AuthenticationActions, IProvideAuthorization, IDictionary <string, string>, Uri, TResult> onLogin,
                                                          Func <Uri, string, IProvideAuthorization, IDictionary <string, string>, TResult> onLogout,
                                                          LookupCredentialNotFoundDelegate <TResult> lookupCredentialNotFound,
                                                          Func <string, TResult> onInvalidToken,
                                                          Func <string, TResult> onNotConfigured,
                                                          Func <string, TResult> onFailure,
                                                          TelemetryClient telemetry)
 {
     telemetry.TrackEvent("Sessions.CreateOrUpdateWithAuthenticationAsync:  Authenticated", extraParamsWithRedemptionParams);
     // This is the case where the login process started from an existing authentication resource
     if (stateId.HasValue)
     {
         telemetry.TrackEvent($"Sessions.CreateOrUpdateWithAuthenticationAsync:  StateId: {stateId.Value.ToString()}");
         return(await AuthenticateStateAsync(stateId.Value, loginId, method, subject, extraParamsWithRedemptionParams,
                                             (authorizationId, authenticationId, token, refreshToken, action, extraParamsAuthenticated, redirectUrl) =>
                                             onLogin(authorizationId, authenticationId, token, refreshToken, action, provider, extraParamsAuthenticated, redirectUrl),
                                             (redirectUrl, reason, extraParamsAuthenticated) => onLogout(redirectUrl, reason, provider, extraParamsAuthenticated),
                                             onInvalidToken,
                                             onNotConfigured,
                                             onFailure));
     }
     // This is the case where the login process started from an external system
     telemetry.TrackEvent("StateId not found.  Starting external system login flow.");
     return(await await dataContext.CredentialMappings.LookupCredentialMappingAsync(method, subject, loginId,
                                                                                    (authenticationId) =>
     {
         telemetry.TrackEvent($"Sessions.CreateOrUpdateWithAuthenticationAsync:  Called from external login system.  AuthenticationId: {authenticationId.ToString()}");
         var authorizationId = Guid.NewGuid();
         return this.CreateLoginAsync(authorizationId, authenticationId, method, default(Uri), extraParamsWithRedemptionParams,
                                      (session) => onLogin(authorizationId, authenticationId, session.token, session.refreshToken, AuthenticationActions.signin, provider, session.extraParams,
                                                           default(Uri)),
                                      "Guid not unique for creating authentication started from external system".AsFunctionException <TResult>(),
                                      onFailure);
     },
                                                                                    () => lookupCredentialNotFound(subject, provider, extraParamsWithRedemptionParams,
                                                                                                                   async(authenticationId, onCreatedLogin, onFailureToCreateLogin) =>
     {
         var sessionId = Guid.NewGuid();
         var authorizationId = sessionId;
         return await await dataContext.CredentialMappings.CreateCredentialMappingAsync <Task <TResult> >(
             sessionId, method, subject, authenticationId,
             async() =>
         {
             return await await this.CreateLoginAsync <Task <TResult> >(authorizationId, authenticationId, method, default(Uri), extraParamsWithRedemptionParams,
                                                                        (session) => onCreatedLogin(sessionId, session.token, session.refreshToken, AuthenticationActions.signin, session.redirectUrl),
                                                                        "Guid not unique for creating authentication started from external system".AsFunctionException <Task <TResult> >(),
                                                                        onFailureToCreateLogin.AsAsyncFunc());
         },
             () => "Guid not unique for creating authentication started from external system".AsFunctionException <Task <TResult> >()(),
             () => onFailureToCreateLogin("Token is already in use.").ToTask());
     })));
 }
        public async Task <TResult> CreateOrUpdateWithAuthenticationAsync <TResult>(
            AzureApplication application, string method,
            IDictionary <string, string> extraParams,
            Func <Guid, Guid, string, string, AuthenticationActions, IProvideAuthorization, IDictionary <string, string>, Uri, TResult> onLogin,
            Func <Uri, string, IProvideAuthorization, IDictionary <string, string>, TResult> onLogout,
            LookupCredentialNotFoundDelegate <TResult> lookupCredentialNotFound,
            Func <string, TResult> onInvalidToken,
            Func <string, TResult> systemOffline,
            Func <string, TResult> onNotConfigured,
            Func <string, TResult> onFailure)
        {
            return(await await application.GetAuthorizationProviderAsync(method,
                                                                         async (provider) =>
            {
                return await await provider.RedeemTokenAsync(extraParams,
                                                             (subject, stateId, loginId, extraParamsWithRedemptionParams) =>
                                                             TokenRedeemedAsync(method, provider,
                                                                                subject, stateId, loginId, extraParamsWithRedemptionParams,
                                                                                onLogin,
                                                                                onLogout,
                                                                                lookupCredentialNotFound,
                                                                                onInvalidToken,
                                                                                onNotConfigured,
                                                                                onFailure,
                                                                                this.telemetry),
                                                             async(stateId, extraParamsWithRedemptionParams) =>
                {
                    telemetry.TrackEvent("Sessions.CreateOrUpdateWithAuthenticationAsync:  Not Authenticated");
                    if (!stateId.HasValue)
                    {
                        onLogout(default(Uri), "State id missing.", provider, extraParamsWithRedemptionParams);
                    }

                    return await dataContext.AuthenticationRequests.FindByIdAsync(stateId.Value,
                                                                                  (authRequest) => onLogout(authRequest.redirectLogout, $"Not authenticated. [{stateId.Value}]", provider, extraParamsWithRedemptionParams),
                                                                                  () => onLogout(default(Uri), $"Authentication request not found. [{stateId.Value}]", provider, extraParamsWithRedemptionParams));
                },
                                                             onInvalidToken.AsAsyncFunc(),
                                                             systemOffline.AsAsyncFunc(),
                                                             onNotConfigured.AsAsyncFunc(),
                                                             onFailure.AsAsyncFunc());
            },
                                                                         () => systemOffline($"The requested credential system is not enabled for this deployment. [{method}]").ToTask(),
                                                                         (why) => onNotConfigured(why).ToTask()));
        }