public static async Task <TResult> ProcessAsync <TResult>(Authorization authorization,
                                                                  Func <Authorization, Task> saveAsync,
                                                                  Method authentication, string externalAccountKey,
                                                                  IDictionary <string, string> extraParams,
                                                                  Guid requestId, Uri baseUri, AzureApplication application, IProvideLogin loginProvider,
                                                                  Func <Uri, TResult> onRedirect,
                                                                  Func <string, TResult> onGeneralFailure,
                                                                  TelemetryClient telemetry)
        {
            authorization.authorized             = true;
            authorization.LocationAuthentication = null;
            var result = await await AccountMapping.FindByMethodAndKeyAsync(authentication.authenticationId, externalAccountKey,
                                                                            authorization,

                                                                            // Found
                                                                            async internalAccountId =>
            {
                authorization.parameters     = extraParams;
                authorization.accountIdMaybe = internalAccountId;
                await saveAsync(authorization);
                return(await CreateLoginResponseAsync(requestId,
                                                      internalAccountId, extraParams,
                                                      authentication, authorization,
                                                      baseUri,
                                                      application, loginProvider,
                                                      onRedirect,
                                                      onGeneralFailure,
                                                      telemetry));
            },

                                                                            // Not found
                                                                            async() =>
            {
                return(await await UnmappedCredentialAsync(externalAccountKey, extraParams,
                                                           authentication, authorization,
                                                           loginProvider, application, baseUri,

                                                           // Create mapping
                                                           async(internalAccountId) =>
                {
                    authorization.parameters = extraParams;
                    authorization.accountIdMaybe = internalAccountId;
                    await saveAsync(authorization);
                    return await await AccountMapping.CreateByMethodAndKeyAsync(authorization, externalAccountKey,
                                                                                internalAccountId,
                                                                                () =>
                    {
                        return CreateLoginResponseAsync(requestId,
                                                        internalAccountId, extraParams,
                                                        authentication, authorization,
                                                        baseUri,
                                                        application, loginProvider,
                                                        onRedirect,
                                                        onGeneralFailure,
                                                        telemetry);
                    },
                                                                                (why) => onGeneralFailure(why).AsTask());
                },

                                                           // Allow self serve
                                                           async() =>
                {
                    authorization.parameters = extraParams;
                    await saveAsync(authorization);
                    return await CreateLoginResponseAsync(requestId,
                                                          default(Guid?), extraParams,
                                                          authentication, authorization,
                                                          baseUri,
                                                          application, loginProvider,
                                                          onRedirect,
                                                          onGeneralFailure,
                                                          telemetry);
                },

                                                           // Intercept process
                                                           async(interceptionUrl) =>
                {
                    authorization.parameters = extraParams;
                    await saveAsync(authorization);
                    return onRedirect(interceptionUrl);
                },

                                                           // Failure
                                                           async(why) =>
                {
                    // Save params so they can be used later
                    authorization.parameters = extraParams;
                    await saveAsync(authorization);
                    return onGeneralFailure(why);
                },
                                                           telemetry));
            });

            return(result);
        }