private async Task <AuthenticationResult> RefreshAccessTokenAsync(AuthenticationResult result)
        {
            AuthenticationResult newResult = null;

            if (this.Resource != null)
            {
                try
                {
                    newResult = await this.SendTokenRequestByRefreshTokenAsync(result.RefreshToken);

                    this.Authenticator.UpdateTenantId(result.TenantId);

                    if (newResult.IdToken == null)
                    {
                        // If Id token is not returned by token endpoint when refresh token is redeemed, we should copy tenant and user information from the cached token.
                        newResult.UpdateTenantAndUserInfo(result.TenantId, result.IdToken, result.UserInfo);
                    }
                }
                catch (AdalException ex)
                {
                    AdalServiceException serviceException = ex as AdalServiceException;
                    if (serviceException != null && serviceException.ErrorCode == "invalid_request")
                    {
                        throw new AdalServiceException(
                                  AdalError.FailedToRefreshToken,
                                  AdalErrorMessage.FailedToRefreshToken + ". " + serviceException.Message,
                                  (WebException)serviceException.InnerException);
                    }

                    newResult = null;
                }
            }

            return(newResult);
        }
        internal AuthenticationResult LoadFromCache(string authority, string resource, string clientId, TokenSubjectType subjectType, string uniqueId, string displayableId, CallState callState)
        {
            Logger.Verbose(callState, "Looking up cache for a token...");

            AuthenticationResult result = null;

            KeyValuePair <TokenCacheKey, AuthenticationResult>?kvp = this.LoadSingleItemFromCache(authority, resource, clientId, subjectType, uniqueId, displayableId, callState);

            if (kvp.HasValue)
            {
                TokenCacheKey cacheKey = kvp.Value.Key;
                result = kvp.Value.Value;
                bool tokenNearExpiry = (result.ExpiresOn <= DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes));

                if (tokenNearExpiry)
                {
                    result.AccessToken = null;
                    Logger.Verbose(callState, "An expired or near expiry token was found in the cache");
                }
                else if (!cacheKey.ResourceEquals(resource))
                {
                    Logger.Verbose(callState,
                                   string.Format("Multi resource refresh token for resource '{0}' will be used to acquire token for '{1}'", cacheKey.Resource, resource));
                    var newResult = new AuthenticationResult(null, null, result.RefreshToken, DateTimeOffset.MinValue);
                    newResult.UpdateTenantAndUserInfo(result.TenantId, result.IdToken, result.UserInfo);
                    result = newResult;
                }
                else
                {
                    Logger.Verbose(callState, string.Format("{0} minutes left until token in cache expires", (result.ExpiresOn - DateTime.UtcNow).TotalMinutes));
                }

                if (result.AccessToken == null && result.RefreshToken == null)
                {
                    this.tokenCacheDictionary.Remove(cacheKey);
                    Logger.Information(callState, "An old item was removed from the cache");
                    this.HasStateChanged = true;
                    result = null;
                }

                if (result != null)
                {
                    Logger.Information(callState, "A matching item (access token or refresh token or both) was found in the cache");
                }
            }
            else
            {
                Logger.Information(callState, "No matching token was found in the cache");
            }

            return(result);
        }
        private AuthenticationResultEx GetResultFromBrokerResponse(Bundle bundleResult)
        {
            if (bundleResult == null)
            {
                throw new AdalException("bundleResult");
            }

            int    errCode = bundleResult.GetInt(AccountManager.KeyErrorCode);
            string msg     = bundleResult.GetString(AccountManager.KeyErrorMessage);

            if (!string.IsNullOrEmpty(msg))
            {
                throw new AdalException(errCode.ToString(CultureInfo.InvariantCulture), msg);
            }
            else
            {
                bool initialRequest = bundleResult.ContainsKey(BrokerConstants.AccountInitialRequest);
                if (initialRequest)
                {
                    // Initial request from app to Authenticator needs to launch
                    // prompt. null resultEx means initial request
                    return(null);
                }

                // IDtoken is not present in the current broker user model
                UserInfo             userinfo = GetUserInfoFromBrokerResult(bundleResult);
                AuthenticationResult result   =
                    new AuthenticationResult("Bearer", bundleResult.GetString(AccountManager.KeyAuthtoken),
                                             ConvertFromTimeT(bundleResult.GetLong("account.expiredate", 0)))
                {
                    UserInfo = userinfo
                };

                result.UpdateTenantAndUserInfo(bundleResult.GetString(BrokerConstants.AccountUserInfoTenantId), null,
                                               userinfo);

                return(new AuthenticationResultEx
                {
                    Result = result,
                    RefreshToken = null,
                    ResourceInResponse = null,
                });
            }
        }
        public static AuthenticationResult ParseTokenResponse(TokenResponse tokenResponse, CallState callState)
        {
            AuthenticationResult result;

            if (tokenResponse.AccessToken != null)
            {
                DateTimeOffset expiresOn = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResponse.ExpiresIn);

                result = new AuthenticationResult(tokenResponse.TokenType, tokenResponse.AccessToken, tokenResponse.RefreshToken, expiresOn)
                    {
#if ADAL_NET
                        // This is only needed for AcquireTokenByAuthorizationCode in which parameter resource is optional and we need
                        // to get it from the STS response.
                        Resource = tokenResponse.Resource,
#endif                        
                    };

                IdToken idToken = ParseIdToken(tokenResponse.IdToken);
                if (idToken != null)
                {
                    string tenantId = idToken.TenantId;
                    string uniqueId = null;
                    string displayableId = null;

                    if (!string.IsNullOrWhiteSpace(idToken.ObjectId))
                    {
                        uniqueId = idToken.ObjectId;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Subject))
                    {
                        uniqueId = idToken.Subject;
                    }

                    if (!string.IsNullOrWhiteSpace(idToken.UPN))
                    {
                        displayableId = idToken.UPN;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Email))
                    {
                        displayableId = idToken.Email;
                    }

                    string givenName = idToken.GivenName;
                    string familyName = idToken.FamilyName;
                    string identityProvider = idToken.IdentityProvider ?? idToken.Issuer;
                    DateTimeOffset? passwordExpiresOffest = null;
                    if (idToken.PasswordExpiration > 0)
                    {
                        passwordExpiresOffest = DateTime.UtcNow + TimeSpan.FromSeconds(idToken.PasswordExpiration);
                    }

                    Uri changePasswordUri = null;
                    if (!string.IsNullOrEmpty(idToken.PasswordChangeUrl))
                    {
                        changePasswordUri = new Uri(idToken.PasswordChangeUrl);
                    }

                    result.UpdateTenantAndUserInfo(tenantId, tokenResponse.IdToken, new UserInfo { UniqueId = uniqueId, DisplayableId = displayableId, GivenName = givenName, FamilyName = familyName, IdentityProvider = identityProvider, PasswordExpiresOn = passwordExpiresOffest, PasswordChangeUrl = changePasswordUri });
                }
            }
            else if (tokenResponse.Error != null)
            {
                throw new AdalServiceException(tokenResponse.Error, tokenResponse.ErrorDescription);
            }
            else
            {
                throw new AdalServiceException(AdalError.Unknown, AdalErrorMessage.Unknown);
            }

            return result;
        }
        internal AuthenticationResult LoadFromCache(string authority, string resource, string clientId, TokenSubjectType subjectType, string uniqueId, string displayableId, CallState callState)
        {
            lock (cacheLock)
            {
                Logger.Verbose(callState, "Looking up cache for a token...");

                AuthenticationResult result = null;

                KeyValuePair<TokenCacheKey, AuthenticationResult>? kvp = this.LoadSingleItemFromCache(authority,
                    resource, clientId, subjectType, uniqueId, displayableId, callState);

                if (kvp.HasValue)
                {
                    TokenCacheKey cacheKey = kvp.Value.Key;
                    result = kvp.Value.Value;
                    bool tokenNearExpiry = (result.ExpiresOn <=
                                            DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes));

                    if (tokenNearExpiry)
                    {
                        result.AccessToken = null;
                        Logger.Verbose(callState, "An expired or near expiry token was found in the cache");
                    }
                    else if (!cacheKey.ResourceEquals(resource))
                    {
                        Logger.Verbose(callState,
                            string.Format(
                                "Multi resource refresh token for resource '{0}' will be used to acquire token for '{1}'",
                                cacheKey.Resource, resource));
                        var newResult = new AuthenticationResult(null, null, result.RefreshToken,
                            DateTimeOffset.MinValue);
                        newResult.UpdateTenantAndUserInfo(result.TenantId, result.IdToken, result.UserInfo);
                        result = newResult;
                    }
                    else
                    {
                        Logger.Verbose(callState,
                            string.Format("{0} minutes left until token in cache expires",
                                (result.ExpiresOn - DateTime.UtcNow).TotalMinutes));
                    }

                    if (result.AccessToken == null && result.RefreshToken == null)
                    {
                        this.tokenCacheDictionary.Remove(cacheKey);
                        Logger.Information(callState, "An old item was removed from the cache");
                        this.HasStateChanged = true;
                        result = null;
                    }

                    if (result != null)
                    {
                        Logger.Information(callState,
                            "A matching item (access token or refresh token or both) was found in the cache");
                    }
                }
                else
                {
                    Logger.Information(callState, "No matching token was found in the cache");
                }

                return result;
            }
        }
        public AuthenticationResultEx GetResult(DateTimeOffset expiresOn, DateTimeOffset extendedExpiresOn)
        {
            AuthenticationResultEx resultEx;

            if (this.AccessToken != null)
            {
                var result = new AuthenticationResult(this.TokenType, this.AccessToken, expiresOn, extendedExpiresOn);

                IdToken idToken = IdToken.Parse(this.IdTokenString);
                if (idToken != null)
                {
                    string tenantId      = idToken.TenantId;
                    string uniqueId      = null;
                    string displayableId = null;

                    if (!string.IsNullOrWhiteSpace(idToken.ObjectId))
                    {
                        uniqueId = idToken.ObjectId;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Subject))
                    {
                        uniqueId = idToken.Subject;
                    }

                    if (!string.IsNullOrWhiteSpace(idToken.UPN))
                    {
                        displayableId = idToken.UPN;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Email))
                    {
                        displayableId = idToken.Email;
                    }

                    string         givenName             = idToken.GivenName;
                    string         familyName            = idToken.FamilyName;
                    string         identityProvider      = idToken.IdentityProvider ?? idToken.Issuer;
                    DateTimeOffset?passwordExpiresOffest = null;
                    if (idToken.PasswordExpiration > 0)
                    {
                        passwordExpiresOffest = DateTime.UtcNow + TimeSpan.FromSeconds(idToken.PasswordExpiration);
                    }

                    Uri changePasswordUri = null;
                    if (!string.IsNullOrEmpty(idToken.PasswordChangeUrl))
                    {
                        changePasswordUri = new Uri(idToken.PasswordChangeUrl);
                    }

                    result.UpdateTenantAndUserInfo(tenantId, this.IdTokenString,
                                                   new UserInfo
                    {
                        UniqueId          = uniqueId,
                        DisplayableId     = displayableId,
                        GivenName         = givenName,
                        FamilyName        = familyName,
                        IdentityProvider  = identityProvider,
                        PasswordExpiresOn = passwordExpiresOffest,
                        PasswordChangeUrl = changePasswordUri
                    });

                    result.Authority = Authority;
                }

                resultEx = new AuthenticationResultEx
                {
                    Result       = result,
                    RefreshToken = this.RefreshToken,
                    // This is only needed for AcquireTokenByAuthorizationCode in which parameter resource is optional and we need
                    // to get it from the STS response.
                    ResourceInResponse = this.Resource
                };
            }
            else if (this.Error != null)
            {
                throw new AdalServiceException(this.Error, this.ErrorDescription);
            }
            else
            {
                throw new AdalServiceException(AdalError.Unknown, AdalErrorMessage.Unknown);
            }

            return(resultEx);
        }
        public static AuthenticationResult ParseTokenResponse(TokenResponse tokenResponse, CallState callState)
        {
            AuthenticationResult result;

            if (tokenResponse.AccessToken != null)
            {
                DateTimeOffset expiresOn = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResponse.ExpiresIn);

                result = new AuthenticationResult(tokenResponse.TokenType, tokenResponse.AccessToken, tokenResponse.RefreshToken, expiresOn)
                {
                    // This is only needed for AcquireTokenByAuthorizationCode in which parameter resource is optional and we need
                    // to get it from the STS response.
                    Resource = tokenResponse.Resource,
                    IsMultipleResourceRefreshToken = (!string.IsNullOrWhiteSpace(tokenResponse.RefreshToken) && !string.IsNullOrWhiteSpace(tokenResponse.Resource)),
                };

                IdToken idToken = ParseIdToken(tokenResponse.IdToken);
                if (idToken != null)
                {
                    string tenantId      = idToken.TenantId;
                    string uniqueId      = null;
                    string displayableId = null;

                    if (!string.IsNullOrWhiteSpace(idToken.ObjectId))
                    {
                        uniqueId = idToken.ObjectId;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Subject))
                    {
                        uniqueId = idToken.Subject;
                    }

                    if (!string.IsNullOrWhiteSpace(idToken.UPN))
                    {
                        displayableId = idToken.UPN;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Email))
                    {
                        displayableId = idToken.Email;
                    }

                    string         givenName             = idToken.GivenName;
                    string         familyName            = idToken.FamilyName;
                    string         identityProvider      = idToken.IdentityProvider ?? idToken.Issuer;
                    DateTimeOffset?passwordExpiresOffest = null;
                    if (idToken.PasswordExpiration > 0)
                    {
                        passwordExpiresOffest = DateTime.UtcNow + TimeSpan.FromSeconds(idToken.PasswordExpiration);
                    }

                    Uri changePasswordUri = null;
                    if (!string.IsNullOrEmpty(idToken.PasswordChangeUrl))
                    {
                        changePasswordUri = new Uri(idToken.PasswordChangeUrl);
                    }

                    result.UpdateTenantAndUserInfo(tenantId, tokenResponse.IdToken, new UserInfo {
                        UniqueId = uniqueId, DisplayableId = displayableId, GivenName = givenName, FamilyName = familyName, IdentityProvider = identityProvider, PasswordExpiresOn = passwordExpiresOffest, PasswordChangeUrl = changePasswordUri
                    });
                }
            }
            else if (tokenResponse.Error != null)
            {
                var ex = new AdalServiceException(tokenResponse.Error, tokenResponse.ErrorDescription);
                PlatformPlugin.Logger.LogException(callState, ex);
                throw ex;
            }
            else
            {
                var ex = new AdalServiceException(AdalError.Unknown, AdalErrorMessage.Unknown);
                PlatformPlugin.Logger.LogException(callState, ex);
                throw ex;
            }

            return(result);
        }
        private AuthenticationResultEx GetResult(string token, string scope)
        {
            DateTimeOffset expiresOn = DateTime.UtcNow + TimeSpan.FromSeconds(this.ExpiresIn);
            var result = new AuthenticationResult(this.TokenType, token, expiresOn);

            ProfileInfo profileInfo = ProfileInfo.Parse(this.ProfileInfoString);
            if (profileInfo != null)
            {
                string tenantId = profileInfo.TenantId;
                string uniqueId = null;
                string displayableId = null;

                if (!string.IsNullOrWhiteSpace(profileInfo.ObjectId))
                {
                    uniqueId = profileInfo.ObjectId;
                }
                else if (!string.IsNullOrWhiteSpace(profileInfo.Subject))
                {
                    uniqueId = profileInfo.Subject;
                }

                if (!string.IsNullOrWhiteSpace(profileInfo.UPN))
                {
                    displayableId = profileInfo.UPN;
                }
                else if (!string.IsNullOrWhiteSpace(profileInfo.Email))
                {
                    displayableId = profileInfo.Email;
                }

                string givenName = profileInfo.GivenName;
                string familyName = profileInfo.FamilyName;
                string identityProvider = profileInfo.IdentityProvider ?? profileInfo.Issuer;
                DateTimeOffset? passwordExpiresOffest = null;
                if (profileInfo.PasswordExpiration > 0)
                {
                    passwordExpiresOffest = DateTime.UtcNow + TimeSpan.FromSeconds(profileInfo.PasswordExpiration);
                }

                Uri changePasswordUri = null;
                if (!string.IsNullOrEmpty(profileInfo.PasswordChangeUrl))
                {
                    changePasswordUri = new Uri(profileInfo.PasswordChangeUrl);
                }

                result.UpdateTenantAndUserInfo(tenantId, this.ProfileInfoString,
                    new UserInfo
                    {
                        UniqueId = uniqueId,
                        DisplayableId = displayableId,
                        GivenName = givenName,
                        FamilyName = familyName,
                        IdentityProvider = identityProvider,
                        PasswordExpiresOn = passwordExpiresOffest,
                        PasswordChangeUrl = changePasswordUri
                    });
            }

            return new AuthenticationResultEx
            {
                Result = result,
                RefreshToken = this.RefreshToken,
                // This is only needed for AcquireTokenByAuthorizationCode in which parameter resource is optional and we need
                // to get it from the STS response.
                ScopeInResponse = ADALScopeHelper.CreateArrayFromSingleString(scope)
            };
        }