public void ShouldUseCertThumbPrintInsteadOfPassedInCertificateWhenBothAreSpecified()
        {
            // Arrange
            var         dummyCertName          = "CN=dummycert";
            var         inMemoryCertName       = "CN=inmemorycert";
            var         storedDummyCertificate = CreateAndStoreSelfSignedCert(dummyCertName);
            var         inMemoryCertificate    = CreateSelfSignedCert(inMemoryCertName);
            AuthContext appOnlyAuthContext     = new AuthContext
            {
                AuthType = AuthenticationType.AppOnly,
                ClientId = Guid.NewGuid().ToString(),
                CertificateThumbprint = storedDummyCertificate.Thumbprint,
                Certificate           = inMemoryCertificate,
                ContextScope          = ContextScope.Process
            };
            // Act
            IAuthenticationProvider authProvider = AuthenticationHelpers.GetAuthProvider(appOnlyAuthContext);

            // Assert
            Assert.IsType <ClientCredentialProvider>(authProvider);
            var clientCredentialProvider = (ClientCredentialProvider)authProvider;

            // Assert: That the certificate used is dummycert (Thumbprint), that is in the store
            Assert.NotEqual(inMemoryCertName, clientCredentialProvider.ClientApplication.AppConfig.ClientCredentialCertificate.SubjectName.Name);
            Assert.Equal(appOnlyAuthContext.CertificateThumbprint, clientCredentialProvider.ClientApplication.AppConfig.ClientCredentialCertificate.Thumbprint);

            //CleanUp
            DeleteSelfSignedCertByThumbprint(appOnlyAuthContext.CertificateThumbprint);
            GraphSession.Reset();
        }
        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();
        }
        public void ShouldThrowIfNullInMemoryCertIsProvided()
        {
            // Arrange
            AuthContext appOnlyAuthContext = new AuthContext
            {
                AuthType     = AuthenticationType.AppOnly,
                ClientId     = Guid.NewGuid().ToString(),
                Certificate  = null,
                ContextScope = ContextScope.Process
            };
            // Act
            Action action = () => AuthenticationHelpers.GetAuthProvider(appOnlyAuthContext);

            //Assert
            Assert.Throws <ArgumentNullException>(action);
        }
        public void ShouldThrowIfNonExistentCertNameIsProvided()
        {
            // Arrange
            var         dummyCertName      = "CN=NonExistingCert";
            AuthContext appOnlyAuthContext = new AuthContext
            {
                AuthType        = AuthenticationType.AppOnly,
                ClientId        = Guid.NewGuid().ToString(),
                CertificateName = dummyCertName,
                ContextScope    = ContextScope.Process
            };
            // Act
            Action action = () => AuthenticationHelpers.GetAuthProvider(appOnlyAuthContext);

            //Assert
            Assert.ThrowsAny <Exception>(action);
        }
Esempio n. 5
0
 /// <summary>
 ///     Gets a Custom AuthProvider or configured default provided depending on Auth Scheme specified.
 /// </summary>
 /// <returns></returns>
 private IAuthenticationProvider GetAuthProvider()
 {
     if (Authentication == GraphRequestAuthenticationType.UserProvidedToken)
     {
         return(new InvokeGraphRequestAuthProvider(GraphRequestSession));
     }
     // Ensure that AuthContext is present in DefaultAuth mode, otherwise demand for Connect-Graph to be called.
     if (Authentication == GraphRequestAuthenticationType.Default && GraphSession.Instance.AuthContext != null)
     {
         return(AuthenticationHelpers.GetAuthProvider(GraphSession.Instance.AuthContext));
     }
     else
     {
         var error = new ArgumentNullException(Resources.MissingAuthenticationContext.FormatCurrentCulture(nameof(GraphSession.Instance.AuthContext)),
                                               nameof(GraphSession.Instance.AuthContext));
         throw error;
     }
 }
        public void ShouldUseInteractiveProviderWhenDelegated()
        {
            // Arrange
            AuthContext delegatedAuthContext = new AuthContext
            {
                AuthType     = AuthenticationType.Delegated,
                Scopes       = new[] { "User.Read" },
                ContextScope = ContextScope.Process
            };

            // Act
            IAuthenticationProvider authProvider = AuthenticationHelpers.GetAuthProvider(delegatedAuthContext);

            // Assert
            Assert.IsType <InteractiveAuthenticationProvider>(authProvider);

            // reset static instance.
            GraphSession.Reset();
        }
Esempio n. 7
0
        public void GetGraphHttpClientWithClientTimeoutParameterShouldReturnHttpClientWithSpecifiedTimeout()
        {
            GraphSession.Initialize(() => new GraphSession());
            TimeSpan timeSpan    = TimeSpan.FromSeconds(10);
            var      authContext = new AuthContext
            {
                AuthType     = AuthenticationType.UserProvidedAccessToken,
                ContextScope = ContextScope.Process
            };
            IAuthenticationProvider authProvider = AuthenticationHelpers.GetAuthProvider(authContext);

            HttpClient httpClient = HttpHelpers.GetGraphHttpClient(authProvider, timeSpan);

            Assert.Equal(authContext.ClientTimeout, TimeSpan.FromSeconds(Constants.ClientTimeout));
            Assert.Equal(httpClient.Timeout, timeSpan);

            // reset static instance.
            GraphSession.Reset();
        }
        public void ShouldUseDeviceCodeWhenFallback()
        {
            // Arrange
            AuthContext delegatedAuthContext = new AuthContext
            {
                AuthType         = AuthenticationType.Delegated,
                Scopes           = new[] { "User.Read" },
                ContextScope     = ContextScope.Process,
                AuthProviderType = AuthProviderType.DeviceCodeProviderFallBack
            };

            // Act
            IAuthenticationProvider authProvider = AuthenticationHelpers.GetAuthProvider(delegatedAuthContext);

            // Assert
            Assert.IsType <DeviceCodeProvider>(authProvider);

            // reset static instance.
            GraphSession.Reset();
        }
        public void ShouldUseInMemoryCertificateWhenProvided()
        {
            // Arrange
            var         certificate        = CreateSelfSignedCert("cn=inmemorycert");
            AuthContext appOnlyAuthContext = new AuthContext
            {
                AuthType     = AuthenticationType.AppOnly,
                ClientId     = Guid.NewGuid().ToString(),
                Certificate  = certificate,
                ContextScope = ContextScope.Process
            };
            // Act
            IAuthenticationProvider authProvider = AuthenticationHelpers.GetAuthProvider(appOnlyAuthContext);

            // Assert
            Assert.IsType <ClientCredentialProvider>(authProvider);
            var clientCredentialProvider = (ClientCredentialProvider)authProvider;

            // Assert: That the certificate created and set above is the same as used here.
            Assert.Equal(clientCredentialProvider.ClientApplication.AppConfig.ClientCredentialCertificate, certificate);
            GraphSession.Reset();
        }
        public void ShouldUseClientCredentialProviderWhenAppOnlyContextIsProvided()
        {
            // Arrange
            AuthContext appOnlyAuthContext = new AuthContext
            {
                AuthType        = AuthenticationType.AppOnly,
                ClientId        = Guid.NewGuid().ToString(),
                CertificateName = "cn=dummyCert",
                ContextScope    = ContextScope.Process
            };

            CreateAndStoreSelfSignedCert(appOnlyAuthContext.CertificateName);

            // Act
            IAuthenticationProvider authProvider = AuthenticationHelpers.GetAuthProvider(appOnlyAuthContext);

            // Assert
            Assert.IsType <ClientCredentialProvider>(authProvider);

            // reset
            DeleteSelfSignedCertByName(appOnlyAuthContext.CertificateName);
            GraphSession.Reset();
        }
        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!");
        }
Esempio n. 12
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!");
        }
Esempio n. 13
0
        /// <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>
        /// <param name="fallBackWarning">Callback to report FallBack to DeviceCode Authentication</param>
        /// <returns></returns>
        public static async Task <IAuthContext> AuthenticateAsync(IAuthContext authContext, bool forceRefresh, CancellationToken cancellationToken, Action fallBackWarning = null)
        {
            // Gets a static instance of IAuthenticationProvider when the client app hasn't changed.
            var authProvider = AuthenticationHelpers.GetAuthProvider(authContext);
            IClientApplicationBase clientApplication = null;

            switch (authContext.AuthProviderType)
            {
            case AuthProviderType.DeviceCodeProvider:
            case AuthProviderType.DeviceCodeProviderFallBack:
                clientApplication = (authProvider as DeviceCodeProvider).ClientApplication;
                break;

            case AuthProviderType.InteractiveAuthenticationProvider:
            {
                var interactiveProvider = (authProvider as InteractiveAuthenticationProvider).ClientApplication;
                //When User is not Interactive, Pre-Emptively Fallback and warn, to DeviceCode
                if (!interactiveProvider.IsUserInteractive())
                {
                    authContext.AuthProviderType = AuthProviderType.DeviceCodeProviderFallBack;
                    fallBackWarning?.Invoke();
                    var fallBackAuthContext = await AuthenticateAsync(authContext, forceRefresh, cancellationToken, fallBackWarning);

                    return(fallBackAuthContext);
                }
                break;
            }

            case AuthProviderType.ClientCredentialProvider:
            {
                clientApplication = (authProvider as ClientCredentialProvider).ClientApplication;
                break;
            }
            }
            try
            {
                // Incremental scope consent without re-instantiating the auth provider. We will use provided 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)
            {
                //Interactive Authentication Failure: Could Not Open Browser, fallback to DeviceAuth
                if (IsUnableToOpenWebPageError(authEx))
                {
                    authContext.AuthProviderType = AuthProviderType.DeviceCodeProviderFallBack;
                    //ReAuthenticate using DeviceCode as fallback.
                    var fallBackAuthContext = await AuthenticateAsync(authContext, forceRefresh, cancellationToken);

                    //Indicate that this was a Fallback
                    if (fallBackWarning != null && fallBackAuthContext.AuthProviderType == AuthProviderType.DeviceCodeProviderFallBack)
                    {
                        fallBackWarning();
                    }
                    return(fallBackAuthContext);
                }

                if (authEx.InnerException is TaskCanceledException && cancellationToken.IsCancellationRequested)
                {
                    // Authentication requets timeout.
                    throw new Exception(string.Format(CultureInfo.CurrentCulture, ErrorConstants.Message.DeviceCodeTimeout, Constants.MaxDeviceCodeTimeOut));
                }
                else if (authEx.InnerException is MsalServiceException msalServiceEx &&
                         msalServiceEx.StatusCode == 400 &&
                         msalServiceEx.ErrorCode == "invalid_scope" &&
                         string.IsNullOrWhiteSpace(authContext.TenantId) &&
                         (authContext.AuthProviderType == AuthProviderType.DeviceCodeProvider ||
                          authContext.AuthProviderType == AuthProviderType.DeviceCodeProviderFallBack))
                {
                    // MSAL scope validation error. Ask customer to specify sign-in audience or tenant Id.
                    throw new MsalClientException(msalServiceEx.ErrorCode, $"{msalServiceEx.Message}.\r\n{ErrorConstants.Message.InvalidScope}", msalServiceEx);
                }

                //Something Unknown Went Wrong
                throw authEx.InnerException ?? authEx;
            }
            catch (Exception ex)
            {
                throw ex.InnerException ?? ex;
            }
        }
        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"));
        }
        /// <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;
            }
        }