Example #1
0
        /// <summary>
        /// Register a new SPA with SPA redirect URIs
        /// </summary>
        /// <param name="options">Command line options</param>
        /// <returns></returns>
        private async Task AddNewSpaWithSpaRedirectUri(Options options)
        {
            // We cannot the Graph SDK because spa is not available yet in the object
            // model of the Graph SDK
            string url  = "https://graph.microsoft.com/v1.0/applications";
            string body = Encoding.Default.GetString(Properties.Resources.spa_with_redirect_uri);

            body = body.Replace("[DisplayName]", options.AppName);
            body = body.Replace("[RedirectUri]", options.SpaRedirectUri);

            HttpClient         httpClient         = new HttpClient();
            HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, url);

            httpRequestMessage.Content = new StringContent(body, Encoding.UTF8, "application/json");
            await authenticationProvider.AuthenticateRequestAsync(httpRequestMessage);

            HttpResponseMessage httpReponseMessage = await httpClient.SendAsync(httpRequestMessage);

            string responseContent = await httpReponseMessage.Content.ReadAsStringAsync();

            string appId = null;

            if (httpReponseMessage.StatusCode == System.Net.HttpStatusCode.Created)
            {
                dynamic app = JsonConvert.DeserializeObject(responseContent);
                appId = app.appId;
            }

            string appUrl = $"https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/{appId}/isMSAApp/";

            Console.WriteLine(appUrl);
        }
        public async Task <SignInData> GetLatestUserLoginData(DateTime?fromDate = null)
        {
            string query = string.Empty;

            if (fromDate != null)
            {
                var fromDateFormatted = fromDate?.ToString("yyyy-MM-dd");
                query = $"{_azureAdGraphSettings.BetaGraphApiBaseUrl}auditLogs/signIns?&$filter=createdDateTime ge {fromDateFormatted}";
            }
            else
            {
                query = $"{_azureAdGraphSettings.BetaGraphApiBaseUrl}auditLogs/signIns";
            }

            var message = new HttpRequestMessage()
            {
                Method     = HttpMethod.Get,
                RequestUri = new Uri(query, UriKind.Absolute)
            };

            await _authenticationProvider.AuthenticateRequestAsync(message);

            var response = await _graphServiceClient.HttpProvider.SendAsync(message);

            var responseJson = await response.Content.ReadAsStringAsync();

            var deserializedSignInData = JsonConvert.DeserializeObject <SignInData>(responseJson);

            return(deserializedSignInData);
        }
        public async Task ShouldUseDelegateAuthProviderWhenUserAccessTokenIsProvidedAsync()
        {
            // Arrange
            string accessToken = "ACCESS_TOKEN_VIA_DELEGATE_PROVIDER";

            GraphSession.Instance.UserProvidedToken = new NetworkCredential(string.Empty, accessToken).SecurePassword;
            AuthContext userProvidedAuthContext = new AuthContext
            {
                AuthType     = AuthenticationType.UserProvidedAccessToken,
                ContextScope = ContextScope.Process
            };

            IAuthenticationProvider authProvider   = AuthenticationHelpers.GetAuthProvider(userProvidedAuthContext);
            HttpRequestMessage      requestMessage = new HttpRequestMessage();

            // Act
            await authProvider.AuthenticateRequestAsync(requestMessage);

            // Assert
            Assert.IsType <DelegateAuthenticationProvider>(authProvider);
            Assert.Equal("Bearer", requestMessage.Headers.Authorization.Scheme);
            Assert.Equal(accessToken, requestMessage.Headers.Authorization.Parameter);

            // reset static instance.
            GraphSession.Reset();
        }
        /// <summary>
        /// Retry sending HTTP request
        /// </summary>
        /// <param name="httpResponseMessage">The <see cref="HttpResponseMessage"/>to send.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/>to send.</param>
        /// <param name="authProvider">An authentication provider to pass to <see cref="AuthenticationHandler"/> for authenticating requests.</param>
        /// <returns></returns>
        private async Task <HttpResponseMessage> SendRetryAsync(HttpResponseMessage httpResponseMessage, IAuthenticationProvider authProvider, CancellationToken cancellationToken)
        {
            int retryAttempt = 0;

            while (retryAttempt < MaxRetry)
            {
                // general clone request with internal CloneAsync (see CloneAsync for details) extension method
                var newRequest = await httpResponseMessage.RequestMessage.CloneAsync();

                // Authenticate request using AuthenticationProvider

                await authProvider.AuthenticateRequestAsync(newRequest);

                httpResponseMessage = await base.SendAsync(newRequest, cancellationToken);

                retryAttempt++;

                if (!IsUnauthorized(httpResponseMessage) || !newRequest.IsBuffered())
                {
                    // Re-issue the request to get a new access token
                    return(httpResponseMessage);
                }
            }

            return(httpResponseMessage);
        }
        /// <summary>
        /// Retry sending HTTP request
        /// </summary>
        /// <param name="httpResponseMessage">The <see cref="HttpResponseMessage"/>to send.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/>to send.</param>
        /// <param name="authProvider">An authentication provider to pass to <see cref="AuthenticationHandler"/> for authenticating requests.</param>
        /// <returns></returns>
        private async Task <HttpResponseMessage> SendRetryAsync(HttpResponseMessage httpResponseMessage, IAuthenticationProvider authProvider, CancellationToken cancellationToken)
        {
            int retryAttempt = 0;

            while (retryAttempt < MaxRetry)
            {
                // general clone request with internal CloneAsync (see CloneAsync for details) extension method
                var newRequest = await httpResponseMessage.RequestMessage.CloneAsync();

                // extract the www-authenticate header and add claims to the request context
                if (httpResponseMessage.Headers.WwwAuthenticate.Any())
                {
                    var wwwAuthenticateHeader = httpResponseMessage.Headers.WwwAuthenticate.ToString();
                    AddClaimsToRequestContext(newRequest, wwwAuthenticateHeader);
                }

                // Authenticate request using AuthenticationProvider
                await authProvider.AuthenticateRequestAsync(newRequest);

                httpResponseMessage = await base.SendAsync(newRequest, cancellationToken);

                retryAttempt++;

                if (!IsUnauthorized(httpResponseMessage) || !newRequest.IsBuffered())
                {
                    // Re-issue the request to get a new access token
                    return(httpResponseMessage);
                }
            }

            return(httpResponseMessage);
        }
        private async Task <string> HttpGetAsync(string relativeUrl)
        {
            var uri = serviceRoot + "/" + relativeUrl;

            if (relativeUrl.ToLower().IndexOf("https://") >= 0)
            {
                uri = relativeUrl;
            }
            var message = new HttpRequestMessage(HttpMethod.Get, uri);
            await authenticationProvider.AuthenticateRequestAsync(message);

            var client   = new HttpClient();
            var response = await client.SendAsync(message);

            response.EnsureSuccessStatusCode();
            return(await response.Content.ReadAsStringAsync());
        }
 public Task AuthenticateRequestAsync(HttpRequestMessage request)
 {
     request.GetRequestContext().MiddlewareOptions[typeof(AuthenticationHandlerOption).ToString()] = new AuthenticationHandlerOption
     {
         AuthenticationProviderOption = authenticationProviderOption.Value
     };
     return(innerProvider.AuthenticateRequestAsync(request));
 }
Example #8
0
        protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            await _authenticationProvider.AuthenticateRequestAsync(request);

            return(await base.SendAsync(request, cancellationToken));
        }
        protected override void ProcessRecord()
        {
            base.ProcessRecord();
            IAuthContext authContext = new AuthContext {
                TenantId = TenantId
            };

            cancellationTokenSource = new CancellationTokenSource();
            // Set selected environment to the session object.
            GraphSession.Instance.Environment = environment;

            switch (ParameterSetName)
            {
            case Constants.UserParameterSet:
            {
                // 2 mins timeout. 1 min < HTTP timeout.
                TimeSpan authTimeout = new TimeSpan(0, 0, Constants.MaxDeviceCodeTimeOut);
                cancellationTokenSource = new CancellationTokenSource(authTimeout);
                authContext.AuthType    = AuthenticationType.Delegated;
                string[] processedScopes = ProcessScopes(Scopes);
                authContext.Scopes = processedScopes.Length == 0 ? new string[] { "User.Read" } : processedScopes;
                // Default to CurrentUser but allow the customer to change this via `ContextScope` param.
                authContext.ContextScope = this.IsParameterBound(nameof(ContextScope)) ? ContextScope : ContextScope.CurrentUser;
            }
            break;

            case Constants.AppParameterSet:
            {
                authContext.AuthType = AuthenticationType.AppOnly;
                authContext.ClientId = ClientId;
                authContext.CertificateThumbprint = CertificateThumbprint;
                authContext.CertificateName       = CertificateName;
                // Default to Process but allow the customer to change this via `ContextScope` param.
                authContext.ContextScope = this.IsParameterBound(nameof(ContextScope)) ? ContextScope : ContextScope.Process;
            }
            break;

            case Constants.AccessTokenParameterSet:
            {
                authContext.AuthType     = AuthenticationType.UserProvidedAccessToken;
                authContext.ContextScope = ContextScope.Process;
                // Store user provided access token to a session object.
                GraphSession.Instance.UserProvidedToken = new NetworkCredential(string.Empty, AccessToken).SecurePassword;
            }
            break;
            }

            CancellationToken cancellationToken = cancellationTokenSource.Token;

            try
            {
                // Gets a static instance of IAuthenticationProvider when the client app hasn't changed.
                IAuthenticationProvider authProvider      = AuthenticationHelpers.GetAuthProvider(authContext);
                IClientApplicationBase  clientApplication = null;
                if (ParameterSetName == Constants.UserParameterSet)
                {
                    clientApplication = (authProvider as DeviceCodeProvider).ClientApplication;
                }
                else if (ParameterSetName == Constants.AppParameterSet)
                {
                    clientApplication = (authProvider as ClientCredentialProvider).ClientApplication;
                }

                // Incremental scope consent without re-instantiating the auth provider. We will use a static instance.
                GraphRequestContext graphRequestContext = new GraphRequestContext();
                graphRequestContext.CancellationToken = cancellationToken;
                graphRequestContext.MiddlewareOptions = new Dictionary <string, IMiddlewareOption>
                {
                    {
                        typeof(AuthenticationHandlerOption).ToString(),
                        new AuthenticationHandlerOption
                        {
                            AuthenticationProviderOption = new AuthenticationProviderOption
                            {
                                Scopes       = authContext.Scopes,
                                ForceRefresh = ForceRefresh
                            }
                        }
                    }
                };

                // Trigger consent.
                HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
                httpRequestMessage.Properties.Add(typeof(GraphRequestContext).ToString(), graphRequestContext);
                authProvider.AuthenticateRequestAsync(httpRequestMessage).GetAwaiter().GetResult();

                IAccount account = null;
                if (clientApplication != null)
                {
                    // Only get accounts when we are using MSAL to get an access token.
                    IEnumerable <IAccount> accounts = clientApplication.GetAccountsAsync().GetAwaiter().GetResult();
                    account = accounts.FirstOrDefault();
                }
                DecodeJWT(httpRequestMessage.Headers.Authorization?.Parameter, account, ref authContext);

                // Save auth context to session state.
                GraphSession.Instance.AuthContext = authContext;
            }
            catch (AuthenticationException authEx)
            {
                if ((authEx.InnerException is TaskCanceledException) && cancellationToken.IsCancellationRequested)
                {
                    // DeviceCodeTimeout
                    throw new Exception(string.Format(
                                            CultureInfo.CurrentCulture,
                                            ErrorConstants.Message.DeviceCodeTimeout,
                                            Constants.MaxDeviceCodeTimeOut));
                }
                else
                {
                    throw authEx.InnerException ?? authEx;
                }
            }
            catch (Exception ex)
            {
                throw ex.InnerException ?? ex;
            }

            WriteObject("Welcome To Microsoft Graph!");
        }
Example #10
0
        protected override void ProcessRecord()
        {
            base.ProcessRecord();

            AuthConfig authConfig = new AuthConfig {
                TenantId = TenantId
            };
            CancellationToken cancellationToken = CancellationToken.None;

            if (ParameterSetName == Constants.UserParameterSet)
            {
                // 2 mins timeout. 1 min < HTTP timeout.
                TimeSpan authTimeout        = new TimeSpan(0, 0, Constants.MaxDeviceCodeTimeOut);
                CancellationTokenSource cts = new CancellationTokenSource(authTimeout);
                cancellationToken = cts.Token;

                authConfig.AuthType = AuthenticationType.Delegated;
                authConfig.Scopes   = Scopes ?? new string[] { "User.Read" };
            }
            else
            {
                authConfig.AuthType = AuthenticationType.AppOnly;
                authConfig.ClientId = ClientId;
                authConfig.CertificateThumbprint = CertificateThumbprint;
                authConfig.CertificateName       = CertificateName;
            }

            try
            {
                // Gets a static instance of IAuthenticationProvider when the client app hasn't changed.
                IAuthenticationProvider authProvider      = AuthenticationHelpers.GetAuthProvider(authConfig);
                IClientApplicationBase  clientApplication = null;
                if (ParameterSetName == Constants.UserParameterSet)
                {
                    clientApplication = (authProvider as DeviceCodeProvider).ClientApplication;
                }
                else
                {
                    clientApplication = (authProvider as ClientCredentialProvider).ClientApplication;
                }

                // Incremental scope consent without re-instanciating the auth provider. We will use a static instance.
                GraphRequestContext graphRequestContext = new GraphRequestContext();
                graphRequestContext.CancellationToken = cancellationToken;
                graphRequestContext.MiddlewareOptions = new Dictionary <string, IMiddlewareOption>
                {
                    {
                        typeof(AuthenticationHandlerOption).ToString(),
                        new AuthenticationHandlerOption
                        {
                            AuthenticationProviderOption = new AuthenticationProviderOption
                            {
                                Scopes       = authConfig.Scopes,
                                ForceRefresh = ForceRefresh
                            }
                        }
                    }
                };

                // Trigger consent.
                HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
                httpRequestMessage.Properties.Add(typeof(GraphRequestContext).ToString(), graphRequestContext);
                authProvider.AuthenticateRequestAsync(httpRequestMessage).GetAwaiter().GetResult();

                var accounts = clientApplication.GetAccountsAsync().GetAwaiter().GetResult();
                var account  = accounts.FirstOrDefault();

                JwtPayload jwtPayload = JwtHelpers.DecodeToObject <JwtPayload>(httpRequestMessage.Headers.Authorization?.Parameter);
                authConfig.Scopes   = jwtPayload?.Scp?.Split(' ') ?? jwtPayload?.Roles;
                authConfig.TenantId = jwtPayload?.Tid ?? account?.HomeAccountId?.TenantId;
                authConfig.AppName  = jwtPayload?.AppDisplayname;
                authConfig.Account  = jwtPayload?.Upn ?? account?.Username;

                // Save auth config to session state.
                SessionState.PSVariable.Set(Constants.GraphAuthConfigId, authConfig);
            }
            catch (AuthenticationException authEx)
            {
                if ((authEx.InnerException is TaskCanceledException) && cancellationToken.IsCancellationRequested)
                {
                    throw new Exception($"Device code terminal timed-out after {Constants.MaxDeviceCodeTimeOut} seconds. Please try again.");
                }
                else
                {
                    throw authEx.InnerException ?? authEx;
                }
            }
            catch (Exception ex)
            {
                throw ex.InnerException ?? ex;
            }

            WriteObject("Welcome To Microsoft Graph!");
        }
Example #11
0
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            //TODO : No userinfo endpoint, so we have to parse the AAD object to claims.
            //TODO : Create custome attributes in AAD.


            if (context.RequestedClaimTypes.Any())
            {
                if (context.Client.ClientId == "DotNetDevOps.Emails")
                {
                    // context.ValidatedRequest.
                    context.AddRequestedClaims(context.Subject.Claims);
                }

                if (options.Schemes.Contains(context.Subject.GetIdentityProvider()))
                {
                    var str = await azureB2CUserService.GetUserByObjectIdAsync(context.Subject.GetSubjectId());

                    context.AddRequestedClaims(GetClaims(str.Value));

                    if (context.RequestedClaimTypes.Contains("role"))
                    {
                        var roles = await azureB2CUserService.GetUserRolesAsync(context.Subject.GetSubjectId());

                        context.AddRequestedClaims(roles.Value.Select(v => new Claim("role", v)));
                    }
                }



                if (context.Subject.GetIdentityProvider() == options.AzureADScheme)
                {
                    string userId = context.Subject.FindFirst("oid")?.Value;
                    if (userId != null)
                    {
                        string requestUrl = $"https://graph.microsoft.com/v1.0/users/{userId}/memberOf?$select=displayName";

                        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);

                        await authenticationProvider.AuthenticateRequestAsync(request);

                        HttpResponseMessage response = await httpClientFactory.CreateClient().SendAsync(request);


                        var json = JObject.Parse(await response.Content.ReadAsStringAsync());

                        var claims = new List <Claim>()
                        {
                            new Claim("oid", userId)
                        };

                        foreach (var group in json["value"])
                        {
                            claims.Add(new Claim("role", group["displayName"].ToString(), System.Security.Claims.ClaimValueTypes.String, "Graph"));
                        }

                        context.AddRequestedClaims(claims);
                    }
                }
            }
            //   context.AddRequestedClaims(context.Subject.FindAll(JwtClaimTypes.Role));
        }
        protected override void ProcessRecord()
        {
            base.ProcessRecord();

            AuthConfig authConfig = new AuthConfig {
                TenantId = TenantId
            };
            CancellationToken cancellationToken = CancellationToken.None;

            if (ParameterSetName == Constants.UserParameterSet)
            {
                // 2 mins timeout. 1 min < HTTP timeout.
                TimeSpan authTimeout        = new TimeSpan(0, 0, Constants.MaxDeviceCodeTimeOut);
                CancellationTokenSource cts = new CancellationTokenSource(authTimeout);
                cancellationToken = cts.Token;

                authConfig.AuthType = AuthenticationType.Delegated;
                authConfig.Scopes   = Scopes ?? new string[] { "User.Read" };
            }
            else
            {
                authConfig.AuthType = AuthenticationType.AppOnly;
                authConfig.ClientId = ClientId;
                authConfig.CertificateThumbprint = CertificateThumbprint;
                authConfig.CertificateName       = CertificateName;
            }

            // Save auth config to session state.
            SessionState.PSVariable.Set(Constants.GraphAuthConfigId, authConfig);

            try
            {
                // Gets a static instance of IAuthenticationProvider when the client app hasn't changed.
                IAuthenticationProvider authProvider = AuthenticationHelpers.GetAuthProvider(authConfig);

                // Incremental scope consent without re-instanciating the auth provider. We will use a static instance.
                GraphRequestContext graphRequestContext = new GraphRequestContext();
                graphRequestContext.CancellationToken = cancellationToken;
                graphRequestContext.MiddlewareOptions = new Dictionary <string, IMiddlewareOption>
                {
                    {
                        typeof(AuthenticationHandlerOption).ToString(),
                        new AuthenticationHandlerOption
                        {
                            AuthenticationProviderOption = new AuthenticationProviderOption
                            {
                                Scopes       = authConfig.Scopes,
                                ForceRefresh = ForceRefresh
                            }
                        }
                    }
                };
                HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
                httpRequestMessage.Properties.Add(typeof(GraphRequestContext).ToString(), graphRequestContext);

                // Trigger consent.
                authProvider.AuthenticateRequestAsync(httpRequestMessage).GetAwaiter().GetResult();
            }
            catch (AuthenticationException authEx)
            {
                if ((authEx.InnerException is TaskCanceledException) && cancellationToken.IsCancellationRequested)
                {
                    throw new Exception($"Device code terminal timed-out after {Constants.MaxDeviceCodeTimeOut} seconds. Please try again.");
                }
                else
                {
                    throw authEx.InnerException ?? authEx;
                }
            }
            catch (Exception ex)
            {
                throw ex.InnerException ?? ex;
            }

            WriteObject("Welcome To Microsoft Graph!");
            // WriteObject(File.ReadAllText(".\\Art\\WelcomeText.txt"));
            // WriteObject(File.ReadAllText(".\\Art\\GRaphText.txt"));
        }
        async public static Task <HttpResponseMessage> SendWithRetriesAsync(HttpRequestMessage originalRequest, IAuthenticationProvider authProvider, CancellationToken ct, TimeSpan delaySend = default(TimeSpan))
        {
            // caller may have requested a delay
            if (delaySend > TimeSpan.Zero)
            {
                await Task.Delay(delaySend, ct);

                Logger.WriteLine($"Resuming delayed request after {delaySend.TotalSeconds} seconds.");
            }
            int throttlingRetryAttempt = 0;
            int networkErrorAttempt    = 0;
            HttpResponseMessage responseMessage;

            // in this loop we retry on any type of error. we count throttling errors and network errors separately
            // throttle errors are to be expected and retried up to N times. each retry has up to M retries due to low level error errors
            while (true)
            {
                TimeSpan retryDelay;
                var      request = await CloneHttpRequestMessageAsync(originalRequest);

                // authenticate the request before sending
                await authProvider.AuthenticateRequestAsync(request);

                try
                {
                    responseMessage = await httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead, ct);
                }
                // low level networking errors or cancelation due to timeout (TaskCanceledException is thrown)
                catch (Exception ex) when(ex is HttpRequestException || ex is TaskCanceledException)
                {
                    if (networkErrorAttempt++ < maxNetworkErrorRetries && !ct.IsCancellationRequested)
                    {
                        retryDelay = TimeSpan.FromSeconds(networkErrorRetryDelayInSec * networkErrorAttempt);
                        Logger.WriteLine($"Network error detected. Will retry after {retryDelay.TotalSeconds}s. Retry attempt no {networkErrorAttempt}. Error: {ex.Message}");
                        // retry loop
                        continue;
                    }
                    else
                    {
                        throw ex;
                    }
                }
                // response has been received.
                if (responseMessage.IsSuccessStatusCode)
                {
                    return(responseMessage);
                }
                //let's check if it is in one of the error states we can recover from
                if (ShouldRetryOnThrottling(responseMessage, throttlingRetryAttempt, out retryDelay))
                {
                    ++throttlingRetryAttempt;
                    networkErrorAttempt = 0;
                    Logger.WriteLine($"Service throttling detected. Will retry after {retryDelay.TotalSeconds}s. Retry attempt no {throttlingRetryAttempt}");
                }
                else if (ShouldRetryOnErrorResponseOrNetworkFailure(responseMessage, networkErrorAttempt, out retryDelay))
                {
                    ++networkErrorAttempt;
                    Logger.WriteLine($"Retryable error code: {responseMessage.StatusCode}. Will retry after {retryDelay.TotalSeconds}s. Retry attempt no {networkErrorAttempt}");
                }
                else
                {
                    // we should not retry, return the response as is
                    return(responseMessage);
                }
                // if we made it here, we need to wait and retry the loop
                Logger.WriteLine($"Waiting {retryDelay.TotalSeconds} to retry network request.");
                await Task.Delay(retryDelay).ConfigureAwait(false);
            }
        }
        /// <summary>
        /// Authenticates the client using the provided <see cref="IAuthContext"/>.
        /// </summary>
        /// <param name="authContext">The <see cref="IAuthContext"/> to authenticate.</param>
        /// <param name="forceRefresh">Whether or not to force refresh a token if one exists.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        public static async Task <IAuthContext> AuthenticateAsync(IAuthContext authContext, bool forceRefresh, CancellationToken cancellationToken)
        {
            try
            {
                // Gets a static instance of IAuthenticationProvider when the client app hasn't changed.
                IAuthenticationProvider authProvider      = AuthenticationHelpers.GetAuthProvider(authContext);
                IClientApplicationBase  clientApplication = null;
                if (authContext.AuthType == AuthenticationType.Delegated)
                {
                    clientApplication = (authProvider as DeviceCodeProvider).ClientApplication;
                }
                if (authContext.AuthType == AuthenticationType.AppOnly)
                {
                    clientApplication = (authProvider as ClientCredentialProvider).ClientApplication;
                }

                // Incremental scope consent without re-instantiating the auth provider. We will use a static instance.
                GraphRequestContext graphRequestContext = new GraphRequestContext();
                graphRequestContext.CancellationToken = cancellationToken;
                graphRequestContext.MiddlewareOptions = new Dictionary <string, IMiddlewareOption>
                {
                    {
                        typeof(AuthenticationHandlerOption).ToString(),
                        new AuthenticationHandlerOption
                        {
                            AuthenticationProviderOption = new AuthenticationProviderOption
                            {
                                Scopes       = authContext.Scopes,
                                ForceRefresh = forceRefresh
                            }
                        }
                    }
                };

                // Trigger consent.
                HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
                httpRequestMessage.Properties.Add(typeof(GraphRequestContext).ToString(), graphRequestContext);
                await authProvider.AuthenticateRequestAsync(httpRequestMessage);

                IAccount account = null;
                if (clientApplication != null)
                {
                    // Only get accounts when we are using MSAL to get an access token.
                    IEnumerable <IAccount> accounts = clientApplication.GetAccountsAsync().GetAwaiter().GetResult();
                    account = accounts.FirstOrDefault();
                }

                JwtHelpers.DecodeJWT(httpRequestMessage.Headers.Authorization?.Parameter, account, ref authContext);
                return(authContext);
            }
            catch (AuthenticationException authEx)
            {
                if ((authEx.InnerException is TaskCanceledException) && cancellationToken.IsCancellationRequested)
                {
                    // DeviceCodeTimeout
                    throw new Exception(string.Format(
                                            CultureInfo.CurrentCulture,
                                            ErrorConstants.Message.DeviceCodeTimeout,
                                            Constants.MaxDeviceCodeTimeOut));
                }
                else
                {
                    throw authEx.InnerException ?? authEx;
                }
            }
            catch (Exception ex)
            {
                throw ex.InnerException ?? ex;
            }
        }